Update avcodec to 20080825

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27550 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul
2008-09-15 14:04:59 +00:00
parent 30dd64ce04
commit 67bd3f8a49
53 changed files with 26771 additions and 3367 deletions
@@ -0,0 +1,497 @@
/*
* Chinese AVS video (AVS1-P2, JiZhun profile) decoder.
* Copyright (c) 2006 Stefan Gehrer <[email protected]>
*
* MMX-optimized DSP functions, based on H.264 optimizations by
* Michael Niedermayer and Loren Merritt
*
* 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/common.h"
#include "libavutil/x86_cpu.h"
#include "libavcodec/dsputil.h"
#include "dsputil_mmx.h"
/*****************************************************************************
*
* inverse transform
*
****************************************************************************/
static inline void cavs_idct8_1d(int16_t *block, uint64_t bias)
{
asm volatile(
"movq 112(%0), %%mm4 \n\t" /* mm4 = src7 */
"movq 16(%0), %%mm5 \n\t" /* mm5 = src1 */
"movq 80(%0), %%mm2 \n\t" /* mm2 = src5 */
"movq 48(%0), %%mm7 \n\t" /* mm7 = src3 */
"movq %%mm4, %%mm0 \n\t"
"movq %%mm5, %%mm3 \n\t"
"movq %%mm2, %%mm6 \n\t"
"movq %%mm7, %%mm1 \n\t"
"paddw %%mm4, %%mm4 \n\t" /* mm4 = 2*src7 */
"paddw %%mm3, %%mm3 \n\t" /* mm3 = 2*src1 */
"paddw %%mm6, %%mm6 \n\t" /* mm6 = 2*src5 */
"paddw %%mm1, %%mm1 \n\t" /* mm1 = 2*src3 */
"paddw %%mm4, %%mm0 \n\t" /* mm0 = 3*src7 */
"paddw %%mm3, %%mm5 \n\t" /* mm5 = 3*src1 */
"paddw %%mm6, %%mm2 \n\t" /* mm2 = 3*src5 */
"paddw %%mm1, %%mm7 \n\t" /* mm7 = 3*src3 */
"psubw %%mm4, %%mm5 \n\t" /* mm5 = 3*src1 - 2*src7 = a0 */
"paddw %%mm6, %%mm7 \n\t" /* mm7 = 3*src3 + 2*src5 = a1 */
"psubw %%mm2, %%mm1 \n\t" /* mm1 = 2*src3 - 3*src5 = a2 */
"paddw %%mm0, %%mm3 \n\t" /* mm3 = 2*src1 + 3*src7 = a3 */
"movq %%mm5, %%mm4 \n\t"
"movq %%mm7, %%mm6 \n\t"
"movq %%mm3, %%mm0 \n\t"
"movq %%mm1, %%mm2 \n\t"
SUMSUB_BA( %%mm7, %%mm5 ) /* mm7 = a0 + a1 mm5 = a0 - a1 */
"paddw %%mm3, %%mm7 \n\t" /* mm7 = a0 + a1 + a3 */
"paddw %%mm1, %%mm5 \n\t" /* mm5 = a0 - a1 + a2 */
"paddw %%mm7, %%mm7 \n\t"
"paddw %%mm5, %%mm5 \n\t"
"paddw %%mm6, %%mm7 \n\t" /* mm7 = b4 */
"paddw %%mm4, %%mm5 \n\t" /* mm5 = b5 */
SUMSUB_BA( %%mm1, %%mm3 ) /* mm1 = a3 + a2 mm3 = a3 - a2 */
"psubw %%mm1, %%mm4 \n\t" /* mm4 = a0 - a2 - a3 */
"movq %%mm4, %%mm1 \n\t" /* mm1 = a0 - a2 - a3 */
"psubw %%mm6, %%mm3 \n\t" /* mm3 = a3 - a2 - a1 */
"paddw %%mm1, %%mm1 \n\t"
"paddw %%mm3, %%mm3 \n\t"
"psubw %%mm2, %%mm1 \n\t" /* mm1 = b7 */
"paddw %%mm0, %%mm3 \n\t" /* mm3 = b6 */
"movq 32(%0), %%mm2 \n\t" /* mm2 = src2 */
"movq 96(%0), %%mm6 \n\t" /* mm6 = src6 */
"movq %%mm2, %%mm4 \n\t"
"movq %%mm6, %%mm0 \n\t"
"psllw $2, %%mm4 \n\t" /* mm4 = 4*src2 */
"psllw $2, %%mm6 \n\t" /* mm6 = 4*src6 */
"paddw %%mm4, %%mm2 \n\t" /* mm2 = 5*src2 */
"paddw %%mm6, %%mm0 \n\t" /* mm0 = 5*src6 */
"paddw %%mm2, %%mm2 \n\t"
"paddw %%mm0, %%mm0 \n\t"
"psubw %%mm0, %%mm4 \n\t" /* mm4 = 4*src2 - 10*src6 = a7 */
"paddw %%mm2, %%mm6 \n\t" /* mm6 = 4*src6 + 10*src2 = a6 */
"movq (%0), %%mm2 \n\t" /* mm2 = src0 */
"movq 64(%0), %%mm0 \n\t" /* mm0 = src4 */
SUMSUB_BA( %%mm0, %%mm2 ) /* mm0 = src0+src4 mm2 = src0-src4 */
"psllw $3, %%mm0 \n\t"
"psllw $3, %%mm2 \n\t"
"paddw %1, %%mm0 \n\t" /* add rounding bias */
"paddw %1, %%mm2 \n\t" /* add rounding bias */
SUMSUB_BA( %%mm6, %%mm0 ) /* mm6 = a4 + a6 mm0 = a4 - a6 */
SUMSUB_BA( %%mm4, %%mm2 ) /* mm4 = a5 + a7 mm2 = a5 - a7 */
SUMSUB_BA( %%mm7, %%mm6 ) /* mm7 = dst0 mm6 = dst7 */
SUMSUB_BA( %%mm5, %%mm4 ) /* mm5 = dst1 mm4 = dst6 */
SUMSUB_BA( %%mm3, %%mm2 ) /* mm3 = dst2 mm2 = dst5 */
SUMSUB_BA( %%mm1, %%mm0 ) /* mm1 = dst3 mm0 = dst4 */
:: "r"(block), "m"(bias)
);
}
static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, int stride)
{
int i;
DECLARE_ALIGNED_8(int16_t, b2[64]);
for(i=0; i<2; i++){
DECLARE_ALIGNED_8(uint64_t, tmp);
cavs_idct8_1d(block+4*i, ff_pw_4);
asm volatile(
"psraw $3, %%mm7 \n\t"
"psraw $3, %%mm6 \n\t"
"psraw $3, %%mm5 \n\t"
"psraw $3, %%mm4 \n\t"
"psraw $3, %%mm3 \n\t"
"psraw $3, %%mm2 \n\t"
"psraw $3, %%mm1 \n\t"
"psraw $3, %%mm0 \n\t"
"movq %%mm7, %0 \n\t"
TRANSPOSE4( %%mm0, %%mm2, %%mm4, %%mm6, %%mm7 )
"movq %%mm0, 8(%1) \n\t"
"movq %%mm6, 24(%1) \n\t"
"movq %%mm7, 40(%1) \n\t"
"movq %%mm4, 56(%1) \n\t"
"movq %0, %%mm7 \n\t"
TRANSPOSE4( %%mm7, %%mm5, %%mm3, %%mm1, %%mm0 )
"movq %%mm7, (%1) \n\t"
"movq %%mm1, 16(%1) \n\t"
"movq %%mm0, 32(%1) \n\t"
"movq %%mm3, 48(%1) \n\t"
: "=m"(tmp)
: "r"(b2+32*i)
: "memory"
);
}
for(i=0; i<2; i++){
cavs_idct8_1d(b2+4*i, ff_pw_64);
asm volatile(
"psraw $7, %%mm7 \n\t"
"psraw $7, %%mm6 \n\t"
"psraw $7, %%mm5 \n\t"
"psraw $7, %%mm4 \n\t"
"psraw $7, %%mm3 \n\t"
"psraw $7, %%mm2 \n\t"
"psraw $7, %%mm1 \n\t"
"psraw $7, %%mm0 \n\t"
"movq %%mm7, (%0) \n\t"
"movq %%mm5, 16(%0) \n\t"
"movq %%mm3, 32(%0) \n\t"
"movq %%mm1, 48(%0) \n\t"
"movq %%mm0, 64(%0) \n\t"
"movq %%mm2, 80(%0) \n\t"
"movq %%mm4, 96(%0) \n\t"
"movq %%mm6, 112(%0) \n\t"
:: "r"(b2+4*i)
: "memory"
);
}
add_pixels_clamped_mmx(b2, dst, stride);
/* clear block */
asm volatile(
"pxor %%mm7, %%mm7 \n\t"
"movq %%mm7, (%0) \n\t"
"movq %%mm7, 8(%0) \n\t"
"movq %%mm7, 16(%0) \n\t"
"movq %%mm7, 24(%0) \n\t"
"movq %%mm7, 32(%0) \n\t"
"movq %%mm7, 40(%0) \n\t"
"movq %%mm7, 48(%0) \n\t"
"movq %%mm7, 56(%0) \n\t"
"movq %%mm7, 64(%0) \n\t"
"movq %%mm7, 72(%0) \n\t"
"movq %%mm7, 80(%0) \n\t"
"movq %%mm7, 88(%0) \n\t"
"movq %%mm7, 96(%0) \n\t"
"movq %%mm7, 104(%0) \n\t"
"movq %%mm7, 112(%0) \n\t"
"movq %%mm7, 120(%0) \n\t"
:: "r" (block)
);
}
/*****************************************************************************
*
* motion compensation
*
****************************************************************************/
/* vertical filter [-1 -2 96 42 -7 0] */
#define QPEL_CAVSV1(A,B,C,D,E,F,OP) \
"movd (%0), "#F" \n\t"\
"movq "#C", %%mm6 \n\t"\
"pmullw %5, %%mm6 \n\t"\
"movq "#D", %%mm7 \n\t"\
"pmullw %6, %%mm7 \n\t"\
"psllw $3, "#E" \n\t"\
"psubw "#E", %%mm6 \n\t"\
"psraw $3, "#E" \n\t"\
"paddw %%mm7, %%mm6 \n\t"\
"paddw "#E", %%mm6 \n\t"\
"paddw "#B", "#B" \n\t"\
"pxor %%mm7, %%mm7 \n\t"\
"add %2, %0 \n\t"\
"punpcklbw %%mm7, "#F" \n\t"\
"psubw "#B", %%mm6 \n\t"\
"psraw $1, "#B" \n\t"\
"psubw "#A", %%mm6 \n\t"\
"paddw %4, %%mm6 \n\t"\
"psraw $7, %%mm6 \n\t"\
"packuswb %%mm6, %%mm6 \n\t"\
OP(%%mm6, (%1), A, d) \
"add %3, %1 \n\t"
/* vertical filter [ 0 -1 5 5 -1 0] */
#define QPEL_CAVSV2(A,B,C,D,E,F,OP) \
"movd (%0), "#F" \n\t"\
"movq "#C", %%mm6 \n\t"\
"paddw "#D", %%mm6 \n\t"\
"pmullw %5, %%mm6 \n\t"\
"add %2, %0 \n\t"\
"punpcklbw %%mm7, "#F" \n\t"\
"psubw "#B", %%mm6 \n\t"\
"psubw "#E", %%mm6 \n\t"\
"paddw %4, %%mm6 \n\t"\
"psraw $3, %%mm6 \n\t"\
"packuswb %%mm6, %%mm6 \n\t"\
OP(%%mm6, (%1), A, d) \
"add %3, %1 \n\t"
/* vertical filter [ 0 -7 42 96 -2 -1] */
#define QPEL_CAVSV3(A,B,C,D,E,F,OP) \
"movd (%0), "#F" \n\t"\
"movq "#C", %%mm6 \n\t"\
"pmullw %6, %%mm6 \n\t"\
"movq "#D", %%mm7 \n\t"\
"pmullw %5, %%mm7 \n\t"\
"psllw $3, "#B" \n\t"\
"psubw "#B", %%mm6 \n\t"\
"psraw $3, "#B" \n\t"\
"paddw %%mm7, %%mm6 \n\t"\
"paddw "#B", %%mm6 \n\t"\
"paddw "#E", "#E" \n\t"\
"pxor %%mm7, %%mm7 \n\t"\
"add %2, %0 \n\t"\
"punpcklbw %%mm7, "#F" \n\t"\
"psubw "#E", %%mm6 \n\t"\
"psraw $1, "#E" \n\t"\
"psubw "#F", %%mm6 \n\t"\
"paddw %4, %%mm6 \n\t"\
"psraw $7, %%mm6 \n\t"\
"packuswb %%mm6, %%mm6 \n\t"\
OP(%%mm6, (%1), A, d) \
"add %3, %1 \n\t"
#define QPEL_CAVSVNUM(VOP,OP,ADD,MUL1,MUL2)\
int w= 2;\
src -= 2*srcStride;\
\
while(w--){\
asm volatile(\
"pxor %%mm7, %%mm7 \n\t"\
"movd (%0), %%mm0 \n\t"\
"add %2, %0 \n\t"\
"movd (%0), %%mm1 \n\t"\
"add %2, %0 \n\t"\
"movd (%0), %%mm2 \n\t"\
"add %2, %0 \n\t"\
"movd (%0), %%mm3 \n\t"\
"add %2, %0 \n\t"\
"movd (%0), %%mm4 \n\t"\
"add %2, %0 \n\t"\
"punpcklbw %%mm7, %%mm0 \n\t"\
"punpcklbw %%mm7, %%mm1 \n\t"\
"punpcklbw %%mm7, %%mm2 \n\t"\
"punpcklbw %%mm7, %%mm3 \n\t"\
"punpcklbw %%mm7, %%mm4 \n\t"\
VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP)\
VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP)\
VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP)\
VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP)\
VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP)\
VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP)\
VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP)\
VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP)\
\
: "+a"(src), "+c"(dst)\
: "S"((x86_reg)srcStride), "D"((x86_reg)dstStride), "m"(ADD), "m"(MUL1), "m"(MUL2)\
: "memory"\
);\
if(h==16){\
asm volatile(\
VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP)\
VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP)\
VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP)\
VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP)\
VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP)\
VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP)\
VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP)\
VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP)\
\
: "+a"(src), "+c"(dst)\
: "S"((x86_reg)srcStride), "D"((x86_reg)dstStride), "m"(ADD), "m"(MUL1), "m"(MUL2)\
: "memory"\
);\
}\
src += 4-(h+5)*srcStride;\
dst += 4-h*dstStride;\
}
#define QPEL_CAVS(OPNAME, OP, MMX)\
static void OPNAME ## cavs_qpel8_h_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride){\
int h=8;\
asm volatile(\
"pxor %%mm7, %%mm7 \n\t"\
"movq %5, %%mm6 \n\t"\
"1: \n\t"\
"movq (%0), %%mm0 \n\t"\
"movq 1(%0), %%mm2 \n\t"\
"movq %%mm0, %%mm1 \n\t"\
"movq %%mm2, %%mm3 \n\t"\
"punpcklbw %%mm7, %%mm0 \n\t"\
"punpckhbw %%mm7, %%mm1 \n\t"\
"punpcklbw %%mm7, %%mm2 \n\t"\
"punpckhbw %%mm7, %%mm3 \n\t"\
"paddw %%mm2, %%mm0 \n\t"\
"paddw %%mm3, %%mm1 \n\t"\
"pmullw %%mm6, %%mm0 \n\t"\
"pmullw %%mm6, %%mm1 \n\t"\
"movq -1(%0), %%mm2 \n\t"\
"movq 2(%0), %%mm4 \n\t"\
"movq %%mm2, %%mm3 \n\t"\
"movq %%mm4, %%mm5 \n\t"\
"punpcklbw %%mm7, %%mm2 \n\t"\
"punpckhbw %%mm7, %%mm3 \n\t"\
"punpcklbw %%mm7, %%mm4 \n\t"\
"punpckhbw %%mm7, %%mm5 \n\t"\
"paddw %%mm4, %%mm2 \n\t"\
"paddw %%mm3, %%mm5 \n\t"\
"psubw %%mm2, %%mm0 \n\t"\
"psubw %%mm5, %%mm1 \n\t"\
"movq %6, %%mm5 \n\t"\
"paddw %%mm5, %%mm0 \n\t"\
"paddw %%mm5, %%mm1 \n\t"\
"psraw $3, %%mm0 \n\t"\
"psraw $3, %%mm1 \n\t"\
"packuswb %%mm1, %%mm0 \n\t"\
OP(%%mm0, (%1),%%mm5, q) \
"add %3, %0 \n\t"\
"add %4, %1 \n\t"\
"decl %2 \n\t"\
" jnz 1b \n\t"\
: "+a"(src), "+c"(dst), "+m"(h)\
: "d"((x86_reg)srcStride), "S"((x86_reg)dstStride), "m"(ff_pw_5), "m"(ff_pw_4)\
: "memory"\
);\
}\
\
static inline void OPNAME ## cavs_qpel8or16_v1_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int h){\
QPEL_CAVSVNUM(QPEL_CAVSV1,OP,ff_pw_64,ff_pw_96,ff_pw_42) \
}\
\
static inline void OPNAME ## cavs_qpel8or16_v2_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int h){\
QPEL_CAVSVNUM(QPEL_CAVSV2,OP,ff_pw_4,ff_pw_5,ff_pw_5) \
}\
\
static inline void OPNAME ## cavs_qpel8or16_v3_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int h){\
QPEL_CAVSVNUM(QPEL_CAVSV3,OP,ff_pw_64,ff_pw_96,ff_pw_42) \
}\
\
static void OPNAME ## cavs_qpel8_v1_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride){\
OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst , src , dstStride, srcStride, 8);\
}\
static void OPNAME ## cavs_qpel16_v1_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride){\
OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst , src , dstStride, srcStride, 16);\
OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\
}\
\
static void OPNAME ## cavs_qpel8_v2_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride){\
OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst , src , dstStride, srcStride, 8);\
}\
static void OPNAME ## cavs_qpel16_v2_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride){\
OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst , src , dstStride, srcStride, 16);\
OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\
}\
\
static void OPNAME ## cavs_qpel8_v3_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride){\
OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst , src , dstStride, srcStride, 8);\
}\
static void OPNAME ## cavs_qpel16_v3_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride){\
OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst , src , dstStride, srcStride, 16);\
OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\
}\
\
static void OPNAME ## cavs_qpel16_h_ ## MMX(uint8_t *dst, uint8_t *src, int dstStride, int srcStride){\
OPNAME ## cavs_qpel8_h_ ## MMX(dst , src , dstStride, srcStride);\
OPNAME ## cavs_qpel8_h_ ## MMX(dst+8, src+8, dstStride, srcStride);\
src += 8*srcStride;\
dst += 8*dstStride;\
OPNAME ## cavs_qpel8_h_ ## MMX(dst , src , dstStride, srcStride);\
OPNAME ## cavs_qpel8_h_ ## MMX(dst+8, src+8, dstStride, srcStride);\
}\
#define CAVS_MC(OPNAME, SIZE, MMX) \
static void ff_ ## OPNAME ## cavs_qpel ## SIZE ## _mc20_ ## MMX(uint8_t *dst, uint8_t *src, int stride){\
OPNAME ## cavs_qpel ## SIZE ## _h_ ## MMX(dst, src, stride, stride);\
}\
\
static void ff_ ## OPNAME ## cavs_qpel ## SIZE ## _mc01_ ## MMX(uint8_t *dst, uint8_t *src, int stride){\
OPNAME ## cavs_qpel ## SIZE ## _v1_ ## MMX(dst, src, stride, stride);\
}\
\
static void ff_ ## OPNAME ## cavs_qpel ## SIZE ## _mc02_ ## MMX(uint8_t *dst, uint8_t *src, int stride){\
OPNAME ## cavs_qpel ## SIZE ## _v2_ ## MMX(dst, src, stride, stride);\
}\
\
static void ff_ ## OPNAME ## cavs_qpel ## SIZE ## _mc03_ ## MMX(uint8_t *dst, uint8_t *src, int stride){\
OPNAME ## cavs_qpel ## SIZE ## _v3_ ## MMX(dst, src, stride, stride);\
}\
#define PUT_OP(a,b,temp, size) "mov" #size " " #a ", " #b " \n\t"
#define AVG_3DNOW_OP(a,b,temp, size) \
"mov" #size " " #b ", " #temp " \n\t"\
"pavgusb " #temp ", " #a " \n\t"\
"mov" #size " " #a ", " #b " \n\t"
#define AVG_MMX2_OP(a,b,temp, size) \
"mov" #size " " #b ", " #temp " \n\t"\
"pavgb " #temp ", " #a " \n\t"\
"mov" #size " " #a ", " #b " \n\t"
QPEL_CAVS(put_, PUT_OP, 3dnow)
QPEL_CAVS(avg_, AVG_3DNOW_OP, 3dnow)
QPEL_CAVS(put_, PUT_OP, mmx2)
QPEL_CAVS(avg_, AVG_MMX2_OP, mmx2)
CAVS_MC(put_, 8, 3dnow)
CAVS_MC(put_, 16,3dnow)
CAVS_MC(avg_, 8, 3dnow)
CAVS_MC(avg_, 16,3dnow)
CAVS_MC(put_, 8, mmx2)
CAVS_MC(put_, 16,mmx2)
CAVS_MC(avg_, 8, mmx2)
CAVS_MC(avg_, 16,mmx2)
void ff_put_cavs_qpel8_mc00_mmx2(uint8_t *dst, uint8_t *src, int stride);
void ff_avg_cavs_qpel8_mc00_mmx2(uint8_t *dst, uint8_t *src, int stride);
void ff_put_cavs_qpel16_mc00_mmx2(uint8_t *dst, uint8_t *src, int stride);
void ff_avg_cavs_qpel16_mc00_mmx2(uint8_t *dst, uint8_t *src, int stride);
void ff_cavsdsp_init_mmx2(DSPContext* c, AVCodecContext *avctx) {
#define dspfunc(PFX, IDX, NUM) \
c->PFX ## _pixels_tab[IDX][ 0] = ff_ ## PFX ## NUM ## _mc00_mmx2; \
c->PFX ## _pixels_tab[IDX][ 2] = ff_ ## PFX ## NUM ## _mc20_mmx2; \
c->PFX ## _pixels_tab[IDX][ 4] = ff_ ## PFX ## NUM ## _mc01_mmx2; \
c->PFX ## _pixels_tab[IDX][ 8] = ff_ ## PFX ## NUM ## _mc02_mmx2; \
c->PFX ## _pixels_tab[IDX][12] = ff_ ## PFX ## NUM ## _mc03_mmx2; \
dspfunc(put_cavs_qpel, 0, 16);
dspfunc(put_cavs_qpel, 1, 8);
dspfunc(avg_cavs_qpel, 0, 16);
dspfunc(avg_cavs_qpel, 1, 8);
#undef dspfunc
c->cavs_idct8_add = cavs_idct8_add_mmx;
}
void ff_cavsdsp_init_3dnow(DSPContext* c, AVCodecContext *avctx) {
#define dspfunc(PFX, IDX, NUM) \
c->PFX ## _pixels_tab[IDX][ 0] = ff_ ## PFX ## NUM ## _mc00_mmx2; \
c->PFX ## _pixels_tab[IDX][ 2] = ff_ ## PFX ## NUM ## _mc20_3dnow; \
c->PFX ## _pixels_tab[IDX][ 4] = ff_ ## PFX ## NUM ## _mc01_3dnow; \
c->PFX ## _pixels_tab[IDX][ 8] = ff_ ## PFX ## NUM ## _mc02_3dnow; \
c->PFX ## _pixels_tab[IDX][12] = ff_ ## PFX ## NUM ## _mc03_3dnow; \
dspfunc(put_cavs_qpel, 0, 16);
dspfunc(put_cavs_qpel, 1, 8);
dspfunc(avg_cavs_qpel, 0, 16);
dspfunc(avg_cavs_qpel, 1, 8);
#undef dspfunc
c->cavs_idct8_add = cavs_idct8_add_mmx;
}
@@ -0,0 +1,127 @@
/*
* CPU detection code, extracted from mmx.h
* (c)1997-99 by H. Dietz and R. Fisher
* Converted to C and improved by Fabrice Bellard.
*
* 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 <stdlib.h>
#include "libavutil/x86_cpu.h"
#include "libavcodec/dsputil.h"
#undef printf
/* ebx saving is necessary for PIC. gcc seems unable to see it alone */
#define cpuid(index,eax,ebx,ecx,edx)\
asm volatile\
("mov %%"REG_b", %%"REG_S"\n\t"\
"cpuid\n\t"\
"xchg %%"REG_b", %%"REG_S\
: "=a" (eax), "=S" (ebx),\
"=c" (ecx), "=d" (edx)\
: "0" (index));
/* Function to test if multimedia instructions are supported... */
int mm_support(void)
{
int rval = 0;
int eax, ebx, ecx, edx;
int max_std_level, max_ext_level, std_caps=0, ext_caps=0;
x86_reg a, c;
asm volatile (
/* See if CPUID instruction is supported ... */
/* ... Get copies of EFLAGS into eax and ecx */
"pushf\n\t"
"pop %0\n\t"
"mov %0, %1\n\t"
/* ... Toggle the ID bit in one copy and store */
/* to the EFLAGS reg */
"xor $0x200000, %0\n\t"
"push %0\n\t"
"popf\n\t"
/* ... Get the (hopefully modified) EFLAGS */
"pushf\n\t"
"pop %0\n\t"
: "=a" (a), "=c" (c)
:
: "cc"
);
if (a == c)
return 0; /* CPUID not supported */
cpuid(0, max_std_level, ebx, ecx, edx);
if(max_std_level >= 1){
cpuid(1, eax, ebx, ecx, std_caps);
if (std_caps & (1<<23))
rval |= FF_MM_MMX;
if (std_caps & (1<<25))
rval |= FF_MM_MMXEXT
#if !defined(__GNUC__) || __GNUC__ > 2
| FF_MM_SSE;
if (std_caps & (1<<26))
rval |= FF_MM_SSE2;
if (ecx & 1)
rval |= FF_MM_SSE3;
if (ecx & 0x00000200 )
rval |= FF_MM_SSSE3
#endif
;
}
cpuid(0x80000000, max_ext_level, ebx, ecx, edx);
if(max_ext_level >= 0x80000001){
cpuid(0x80000001, eax, ebx, ecx, ext_caps);
if (ext_caps & (1<<31))
rval |= FF_MM_3DNOW;
if (ext_caps & (1<<30))
rval |= FF_MM_3DNOWEXT;
if (ext_caps & (1<<23))
rval |= FF_MM_MMX;
if (ext_caps & (1<<22))
rval |= FF_MM_MMXEXT;
}
#if 0
av_log(NULL, AV_LOG_DEBUG, "%s%s%s%s%s%s%s%s\n",
(rval&FF_MM_MMX) ? "MMX ":"",
(rval&FF_MM_MMXEXT) ? "MMX2 ":"",
(rval&FF_MM_SSE) ? "SSE ":"",
(rval&FF_MM_SSE2) ? "SSE2 ":"",
(rval&FF_MM_SSE3) ? "SSE3 ":"",
(rval&FF_MM_SSSE3) ? "SSSE3 ":"",
(rval&FF_MM_3DNOW) ? "3DNow ":"",
(rval&FF_MM_3DNOWEXT) ? "3DNowExt ":"");
#endif
return rval;
}
#ifdef TEST
int main ( void )
{
int mm_flags;
mm_flags = mm_support();
printf("mm_support = 0x%08X\n",mm_flags);
return 0;
}
#endif
@@ -0,0 +1,308 @@
/*
* Copyright (c) 2005 Zoltan Hidvegi <hzoli -a- hzoli -d- com>,
* Loren Merritt
*
* 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
*/
/**
* MMX optimized version of (put|avg)_h264_chroma_mc8.
* H264_CHROMA_MC8_TMPL must be defined to the desired function name
* H264_CHROMA_OP must be defined to empty for put and pavgb/pavgusb for avg
* H264_CHROMA_MC8_MV0 must be defined to a (put|avg)_pixels8 function
*/
static void H264_CHROMA_MC8_TMPL(uint8_t *dst/*align 8*/, uint8_t *src/*align 1*/, int stride, int h, int x, int y, int rnd)
{
const uint64_t *rnd_reg;
DECLARE_ALIGNED_8(uint64_t, AA);
DECLARE_ALIGNED_8(uint64_t, DD);
int i;
if(y==0 && x==0) {
/* no filter needed */
H264_CHROMA_MC8_MV0(dst, src, stride, h);
return;
}
assert(x<8 && y<8 && x>=0 && y>=0);
if(y==0 || x==0)
{
/* 1 dimensional filter only */
const int dxy = x ? 1 : stride;
rnd_reg = rnd ? &ff_pw_4 : &ff_pw_3;
asm volatile(
"movd %0, %%mm5\n\t"
"movq %1, %%mm4\n\t"
"movq %2, %%mm6\n\t" /* mm6 = rnd */
"punpcklwd %%mm5, %%mm5\n\t"
"punpckldq %%mm5, %%mm5\n\t" /* mm5 = B = x */
"pxor %%mm7, %%mm7\n\t"
"psubw %%mm5, %%mm4\n\t" /* mm4 = A = 8-x */
:: "rm"(x+y), "m"(ff_pw_8), "m"(*rnd_reg));
for(i=0; i<h; i++) {
asm volatile(
/* mm0 = src[0..7], mm1 = src[1..8] */
"movq %0, %%mm0\n\t"
"movq %1, %%mm2\n\t"
:: "m"(src[0]), "m"(src[dxy]));
asm volatile(
/* [mm0,mm1] = A * src[0..7] */
/* [mm2,mm3] = B * src[1..8] */
"movq %%mm0, %%mm1\n\t"
"movq %%mm2, %%mm3\n\t"
"punpcklbw %%mm7, %%mm0\n\t"
"punpckhbw %%mm7, %%mm1\n\t"
"punpcklbw %%mm7, %%mm2\n\t"
"punpckhbw %%mm7, %%mm3\n\t"
"pmullw %%mm4, %%mm0\n\t"
"pmullw %%mm4, %%mm1\n\t"
"pmullw %%mm5, %%mm2\n\t"
"pmullw %%mm5, %%mm3\n\t"
/* dst[0..7] = (A * src[0..7] + B * src[1..8] + 4) >> 3 */
"paddw %%mm6, %%mm0\n\t"
"paddw %%mm6, %%mm1\n\t"
"paddw %%mm2, %%mm0\n\t"
"paddw %%mm3, %%mm1\n\t"
"psrlw $3, %%mm0\n\t"
"psrlw $3, %%mm1\n\t"
"packuswb %%mm1, %%mm0\n\t"
H264_CHROMA_OP(%0, %%mm0)
"movq %%mm0, %0\n\t"
: "=m" (dst[0]));
src += stride;
dst += stride;
}
return;
}
/* general case, bilinear */
rnd_reg = rnd ? &ff_pw_32.a : &ff_pw_28.a;
asm volatile("movd %2, %%mm4\n\t"
"movd %3, %%mm6\n\t"
"punpcklwd %%mm4, %%mm4\n\t"
"punpcklwd %%mm6, %%mm6\n\t"
"punpckldq %%mm4, %%mm4\n\t" /* mm4 = x words */
"punpckldq %%mm6, %%mm6\n\t" /* mm6 = y words */
"movq %%mm4, %%mm5\n\t"
"pmullw %%mm6, %%mm4\n\t" /* mm4 = x * y */
"psllw $3, %%mm5\n\t"
"psllw $3, %%mm6\n\t"
"movq %%mm5, %%mm7\n\t"
"paddw %%mm6, %%mm7\n\t"
"movq %%mm4, %1\n\t" /* DD = x * y */
"psubw %%mm4, %%mm5\n\t" /* mm5 = B = 8x - xy */
"psubw %%mm4, %%mm6\n\t" /* mm6 = C = 8y - xy */
"paddw %4, %%mm4\n\t"
"psubw %%mm7, %%mm4\n\t" /* mm4 = A = xy - (8x+8y) + 64 */
"pxor %%mm7, %%mm7\n\t"
"movq %%mm4, %0\n\t"
: "=m" (AA), "=m" (DD) : "rm" (x), "rm" (y), "m" (ff_pw_64));
asm volatile(
/* mm0 = src[0..7], mm1 = src[1..8] */
"movq %0, %%mm0\n\t"
"movq %1, %%mm1\n\t"
: : "m" (src[0]), "m" (src[1]));
for(i=0; i<h; i++) {
src += stride;
asm volatile(
/* mm2 = A * src[0..3] + B * src[1..4] */
/* mm3 = A * src[4..7] + B * src[5..8] */
"movq %%mm0, %%mm2\n\t"
"movq %%mm1, %%mm3\n\t"
"punpckhbw %%mm7, %%mm0\n\t"
"punpcklbw %%mm7, %%mm1\n\t"
"punpcklbw %%mm7, %%mm2\n\t"
"punpckhbw %%mm7, %%mm3\n\t"
"pmullw %0, %%mm0\n\t"
"pmullw %0, %%mm2\n\t"
"pmullw %%mm5, %%mm1\n\t"
"pmullw %%mm5, %%mm3\n\t"
"paddw %%mm1, %%mm2\n\t"
"paddw %%mm0, %%mm3\n\t"
: : "m" (AA));
asm volatile(
/* [mm2,mm3] += C * src[0..7] */
"movq %0, %%mm0\n\t"
"movq %%mm0, %%mm1\n\t"
"punpcklbw %%mm7, %%mm0\n\t"
"punpckhbw %%mm7, %%mm1\n\t"
"pmullw %%mm6, %%mm0\n\t"
"pmullw %%mm6, %%mm1\n\t"
"paddw %%mm0, %%mm2\n\t"
"paddw %%mm1, %%mm3\n\t"
: : "m" (src[0]));
asm volatile(
/* [mm2,mm3] += D * src[1..8] */
"movq %1, %%mm1\n\t"
"movq %%mm1, %%mm0\n\t"
"movq %%mm1, %%mm4\n\t"
"punpcklbw %%mm7, %%mm0\n\t"
"punpckhbw %%mm7, %%mm4\n\t"
"pmullw %2, %%mm0\n\t"
"pmullw %2, %%mm4\n\t"
"paddw %%mm0, %%mm2\n\t"
"paddw %%mm4, %%mm3\n\t"
"movq %0, %%mm0\n\t"
: : "m" (src[0]), "m" (src[1]), "m" (DD));
asm volatile(
/* dst[0..7] = ([mm2,mm3] + 32) >> 6 */
"paddw %1, %%mm2\n\t"
"paddw %1, %%mm3\n\t"
"psrlw $6, %%mm2\n\t"
"psrlw $6, %%mm3\n\t"
"packuswb %%mm3, %%mm2\n\t"
H264_CHROMA_OP(%0, %%mm2)
"movq %%mm2, %0\n\t"
: "=m" (dst[0]) : "m" (*rnd_reg));
dst+= stride;
}
}
static void H264_CHROMA_MC4_TMPL(uint8_t *dst/*align 4*/, uint8_t *src/*align 1*/, int stride, int h, int x, int y)
{
asm volatile(
"pxor %%mm7, %%mm7 \n\t"
"movd %5, %%mm2 \n\t"
"movd %6, %%mm3 \n\t"
"movq "MANGLE(ff_pw_8)", %%mm4\n\t"
"movq "MANGLE(ff_pw_8)", %%mm5\n\t"
"punpcklwd %%mm2, %%mm2 \n\t"
"punpcklwd %%mm3, %%mm3 \n\t"
"punpcklwd %%mm2, %%mm2 \n\t"
"punpcklwd %%mm3, %%mm3 \n\t"
"psubw %%mm2, %%mm4 \n\t"
"psubw %%mm3, %%mm5 \n\t"
"movd (%1), %%mm0 \n\t"
"movd 1(%1), %%mm6 \n\t"
"add %3, %1 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpcklbw %%mm7, %%mm6 \n\t"
"pmullw %%mm4, %%mm0 \n\t"
"pmullw %%mm2, %%mm6 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"1: \n\t"
"movd (%1), %%mm0 \n\t"
"movd 1(%1), %%mm1 \n\t"
"add %3, %1 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpcklbw %%mm7, %%mm1 \n\t"
"pmullw %%mm4, %%mm0 \n\t"
"pmullw %%mm2, %%mm1 \n\t"
"paddw %%mm0, %%mm1 \n\t"
"movq %%mm1, %%mm0 \n\t"
"pmullw %%mm5, %%mm6 \n\t"
"pmullw %%mm3, %%mm1 \n\t"
"paddw %4, %%mm6 \n\t"
"paddw %%mm6, %%mm1 \n\t"
"psrlw $6, %%mm1 \n\t"
"packuswb %%mm1, %%mm1 \n\t"
H264_CHROMA_OP4((%0), %%mm1, %%mm6)
"movd %%mm1, (%0) \n\t"
"add %3, %0 \n\t"
"movd (%1), %%mm6 \n\t"
"movd 1(%1), %%mm1 \n\t"
"add %3, %1 \n\t"
"punpcklbw %%mm7, %%mm6 \n\t"
"punpcklbw %%mm7, %%mm1 \n\t"
"pmullw %%mm4, %%mm6 \n\t"
"pmullw %%mm2, %%mm1 \n\t"
"paddw %%mm6, %%mm1 \n\t"
"movq %%mm1, %%mm6 \n\t"
"pmullw %%mm5, %%mm0 \n\t"
"pmullw %%mm3, %%mm1 \n\t"
"paddw %4, %%mm0 \n\t"
"paddw %%mm0, %%mm1 \n\t"
"psrlw $6, %%mm1 \n\t"
"packuswb %%mm1, %%mm1 \n\t"
H264_CHROMA_OP4((%0), %%mm1, %%mm0)
"movd %%mm1, (%0) \n\t"
"add %3, %0 \n\t"
"sub $2, %2 \n\t"
"jnz 1b \n\t"
: "+r"(dst), "+r"(src), "+r"(h)
: "r"((x86_reg)stride), "m"(ff_pw_32), "m"(x), "m"(y)
);
}
#ifdef H264_CHROMA_MC2_TMPL
static void H264_CHROMA_MC2_TMPL(uint8_t *dst/*align 2*/, uint8_t *src/*align 1*/, int stride, int h, int x, int y)
{
int tmp = ((1<<16)-1)*x + 8;
int CD= tmp*y;
int AB= (tmp<<3) - CD;
asm volatile(
/* mm5 = {A,B,A,B} */
/* mm6 = {C,D,C,D} */
"movd %0, %%mm5\n\t"
"movd %1, %%mm6\n\t"
"punpckldq %%mm5, %%mm5\n\t"
"punpckldq %%mm6, %%mm6\n\t"
"pxor %%mm7, %%mm7\n\t"
/* mm0 = src[0,1,1,2] */
"movd %2, %%mm2\n\t"
"punpcklbw %%mm7, %%mm2\n\t"
"pshufw $0x94, %%mm2, %%mm2\n\t"
:: "r"(AB), "r"(CD), "m"(src[0]));
asm volatile(
"1:\n\t"
"add %4, %1\n\t"
/* mm1 = A * src[0,1] + B * src[1,2] */
"movq %%mm2, %%mm1\n\t"
"pmaddwd %%mm5, %%mm1\n\t"
/* mm0 = src[0,1,1,2] */
"movd (%1), %%mm0\n\t"
"punpcklbw %%mm7, %%mm0\n\t"
"pshufw $0x94, %%mm0, %%mm0\n\t"
/* mm1 += C * src[0,1] + D * src[1,2] */
"movq %%mm0, %%mm2\n\t"
"pmaddwd %%mm6, %%mm0\n\t"
"paddw %3, %%mm1\n\t"
"paddw %%mm0, %%mm1\n\t"
/* dst[0,1] = pack((mm1 + 32) >> 6) */
"psrlw $6, %%mm1\n\t"
"packssdw %%mm7, %%mm1\n\t"
"packuswb %%mm7, %%mm1\n\t"
H264_CHROMA_OP4((%0), %%mm1, %%mm3)
"movd %%mm1, %%esi\n\t"
"movw %%si, (%0)\n\t"
"add %4, %0\n\t"
"sub $1, %2\n\t"
"jnz 1b\n\t"
: "+r" (dst), "+r"(src), "+r"(h)
: "m" (ff_pw_32), "r"((x86_reg)stride)
: "%esi");
}
#endif
@@ -0,0 +1,208 @@
/*
* Copyright (c) 2008 Loren Merritt
*
* 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
*/
/**
* SSSE3 optimized version of (put|avg)_h264_chroma_mc8.
* H264_CHROMA_MC8_TMPL must be defined to the desired function name
* H264_CHROMA_MC8_MV0 must be defined to a (put|avg)_pixels8 function
* AVG_OP must be defined to empty for put and the identify for avg
*/
static void H264_CHROMA_MC8_TMPL(uint8_t *dst/*align 8*/, uint8_t *src/*align 1*/, int stride, int h, int x, int y, int rnd)
{
if(y==0 && x==0) {
/* no filter needed */
H264_CHROMA_MC8_MV0(dst, src, stride, h);
return;
}
assert(x<8 && y<8 && x>=0 && y>=0);
if(y==0 || x==0)
{
/* 1 dimensional filter only */
asm volatile(
"movd %0, %%xmm7 \n\t"
"movq %1, %%xmm6 \n\t"
"pshuflw $0, %%xmm7, %%xmm7 \n\t"
"movlhps %%xmm6, %%xmm6 \n\t"
"movlhps %%xmm7, %%xmm7 \n\t"
:: "r"(255*(x+y)+8), "m"(*(rnd?&ff_pw_4:&ff_pw_3))
);
if(x) {
asm volatile(
"1: \n\t"
"movq (%1), %%xmm0 \n\t"
"movq 1(%1), %%xmm1 \n\t"
"movq (%1,%3), %%xmm2 \n\t"
"movq 1(%1,%3), %%xmm3 \n\t"
"punpcklbw %%xmm1, %%xmm0 \n\t"
"punpcklbw %%xmm3, %%xmm2 \n\t"
"pmaddubsw %%xmm7, %%xmm0 \n\t"
"pmaddubsw %%xmm7, %%xmm2 \n\t"
AVG_OP("movq (%0), %%xmm4 \n\t")
AVG_OP("movhps (%0,%3), %%xmm4 \n\t")
"paddw %%xmm6, %%xmm0 \n\t"
"paddw %%xmm6, %%xmm2 \n\t"
"psrlw $3, %%xmm0 \n\t"
"psrlw $3, %%xmm2 \n\t"
"packuswb %%xmm2, %%xmm0 \n\t"
AVG_OP("pavgb %%xmm4, %%xmm0 \n\t")
"movq %%xmm0, (%0) \n\t"
"movhps %%xmm0, (%0,%3) \n\t"
"sub $2, %2 \n\t"
"lea (%1,%3,2), %1 \n\t"
"lea (%0,%3,2), %0 \n\t"
"jg 1b \n\t"
:"+r"(dst), "+r"(src), "+r"(h)
:"r"((x86_reg)stride)
);
} else {
asm volatile(
"1: \n\t"
"movq (%1), %%xmm0 \n\t"
"movq (%1,%3), %%xmm1 \n\t"
"movdqa %%xmm1, %%xmm2 \n\t"
"movq (%1,%3,2), %%xmm3 \n\t"
"punpcklbw %%xmm1, %%xmm0 \n\t"
"punpcklbw %%xmm3, %%xmm2 \n\t"
"pmaddubsw %%xmm7, %%xmm0 \n\t"
"pmaddubsw %%xmm7, %%xmm2 \n\t"
AVG_OP("movq (%0), %%xmm4 \n\t")
AVG_OP("movhps (%0,%3), %%xmm4 \n\t")
"paddw %%xmm6, %%xmm0 \n\t"
"paddw %%xmm6, %%xmm2 \n\t"
"psrlw $3, %%xmm0 \n\t"
"psrlw $3, %%xmm2 \n\t"
"packuswb %%xmm2, %%xmm0 \n\t"
AVG_OP("pavgb %%xmm4, %%xmm0 \n\t")
"movq %%xmm0, (%0) \n\t"
"movhps %%xmm0, (%0,%3) \n\t"
"sub $2, %2 \n\t"
"lea (%1,%3,2), %1 \n\t"
"lea (%0,%3,2), %0 \n\t"
"jg 1b \n\t"
:"+r"(dst), "+r"(src), "+r"(h)
:"r"((x86_reg)stride)
);
}
return;
}
/* general case, bilinear */
asm volatile(
"movd %0, %%xmm7 \n\t"
"movd %1, %%xmm6 \n\t"
"movdqa %2, %%xmm5 \n\t"
"pshuflw $0, %%xmm7, %%xmm7 \n\t"
"pshuflw $0, %%xmm6, %%xmm6 \n\t"
"movlhps %%xmm7, %%xmm7 \n\t"
"movlhps %%xmm6, %%xmm6 \n\t"
:: "r"((x*255+8)*(8-y)), "r"((x*255+8)*y), "m"(*(rnd?&ff_pw_32:&ff_pw_28))
);
asm volatile(
"movq (%1), %%xmm0 \n\t"
"movq 1(%1), %%xmm1 \n\t"
"punpcklbw %%xmm1, %%xmm0 \n\t"
"add %3, %1 \n\t"
"1: \n\t"
"movq (%1), %%xmm1 \n\t"
"movq 1(%1), %%xmm2 \n\t"
"movq (%1,%3), %%xmm3 \n\t"
"movq 1(%1,%3), %%xmm4 \n\t"
"lea (%1,%3,2), %1 \n\t"
"punpcklbw %%xmm2, %%xmm1 \n\t"
"punpcklbw %%xmm4, %%xmm3 \n\t"
"movdqa %%xmm1, %%xmm2 \n\t"
"movdqa %%xmm3, %%xmm4 \n\t"
"pmaddubsw %%xmm7, %%xmm0 \n\t"
"pmaddubsw %%xmm6, %%xmm1 \n\t"
"pmaddubsw %%xmm7, %%xmm2 \n\t"
"pmaddubsw %%xmm6, %%xmm3 \n\t"
"paddw %%xmm5, %%xmm0 \n\t"
"paddw %%xmm5, %%xmm2 \n\t"
"paddw %%xmm0, %%xmm1 \n\t"
"paddw %%xmm2, %%xmm3 \n\t"
"movdqa %%xmm4, %%xmm0 \n\t"
"psrlw $6, %%xmm1 \n\t"
"psrlw $6, %%xmm3 \n\t"
AVG_OP("movq (%0), %%xmm2 \n\t")
AVG_OP("movhps (%0,%3), %%xmm2 \n\t")
"packuswb %%xmm3, %%xmm1 \n\t"
AVG_OP("pavgb %%xmm2, %%xmm1 \n\t")
"movq %%xmm1, (%0)\n\t"
"movhps %%xmm1, (%0,%3)\n\t"
"sub $2, %2 \n\t"
"lea (%0,%3,2), %0 \n\t"
"jg 1b \n\t"
:"+r"(dst), "+r"(src), "+r"(h)
:"r"((x86_reg)stride)
);
}
static void H264_CHROMA_MC4_TMPL(uint8_t *dst/*align 4*/, uint8_t *src/*align 1*/, int stride, int h, int x, int y)
{
asm volatile(
"movd %0, %%mm7 \n\t"
"movd %1, %%mm6 \n\t"
"movq %2, %%mm5 \n\t"
"pshufw $0, %%mm7, %%mm7 \n\t"
"pshufw $0, %%mm6, %%mm6 \n\t"
:: "r"((x*255+8)*(8-y)), "r"((x*255+8)*y), "m"(ff_pw_32)
);
asm volatile(
"movd (%1), %%mm0 \n\t"
"punpcklbw 1(%1), %%mm0 \n\t"
"add %3, %1 \n\t"
"1: \n\t"
"movd (%1), %%mm1 \n\t"
"movd (%1,%3), %%mm3 \n\t"
"punpcklbw 1(%1), %%mm1 \n\t"
"punpcklbw 1(%1,%3), %%mm3 \n\t"
"lea (%1,%3,2), %1 \n\t"
"movq %%mm1, %%mm2 \n\t"
"movq %%mm3, %%mm4 \n\t"
"pmaddubsw %%mm7, %%mm0 \n\t"
"pmaddubsw %%mm6, %%mm1 \n\t"
"pmaddubsw %%mm7, %%mm2 \n\t"
"pmaddubsw %%mm6, %%mm3 \n\t"
"paddw %%mm5, %%mm0 \n\t"
"paddw %%mm5, %%mm2 \n\t"
"paddw %%mm0, %%mm1 \n\t"
"paddw %%mm2, %%mm3 \n\t"
"movq %%mm4, %%mm0 \n\t"
"psrlw $6, %%mm1 \n\t"
"psrlw $6, %%mm3 \n\t"
"packuswb %%mm1, %%mm1 \n\t"
"packuswb %%mm3, %%mm3 \n\t"
AVG_OP("pavgb (%0), %%mm1 \n\t")
AVG_OP("pavgb (%0,%3), %%mm3 \n\t")
"movd %%mm1, (%0)\n\t"
"movd %%mm3, (%0,%3)\n\t"
"sub $2, %2 \n\t"
"lea (%0,%3,2), %0 \n\t"
"jg 1b \n\t"
:"+r"(dst), "+r"(src), "+r"(h)
:"r"((x86_reg)stride)
);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,136 @@
/*
* MMX optimized DSP utils
* Copyright (c) 2007 Aurelien Jacobs <[email protected]>
*
* 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
*/
#ifndef FFMPEG_DSPUTIL_MMX_H
#define FFMPEG_DSPUTIL_MMX_H
#include <stdint.h>
#include "libavcodec/dsputil.h"
typedef struct { uint64_t a, b; } xmm_t;
extern const uint64_t ff_bone;
extern const uint64_t ff_wtwo;
extern const uint64_t ff_pdw_80000000[2];
extern const uint64_t ff_pw_3;
extern const uint64_t ff_pw_4;
extern const xmm_t ff_pw_5;
extern const uint64_t ff_pw_8;
extern const uint64_t ff_pw_15;
extern const xmm_t ff_pw_16;
extern const uint64_t ff_pw_20;
extern const xmm_t ff_pw_28;
extern const xmm_t ff_pw_32;
extern const uint64_t ff_pw_42;
extern const uint64_t ff_pw_64;
extern const uint64_t ff_pw_96;
extern const uint64_t ff_pw_128;
extern const uint64_t ff_pw_255;
extern const uint64_t ff_pb_1;
extern const uint64_t ff_pb_3;
extern const uint64_t ff_pb_7;
extern const uint64_t ff_pb_3F;
extern const uint64_t ff_pb_A1;
extern const uint64_t ff_pb_FC;
extern const double ff_pd_1[2];
extern const double ff_pd_2[2];
#define LOAD4(stride,in,a,b,c,d)\
"movq 0*"#stride"+"#in", "#a"\n\t"\
"movq 1*"#stride"+"#in", "#b"\n\t"\
"movq 2*"#stride"+"#in", "#c"\n\t"\
"movq 3*"#stride"+"#in", "#d"\n\t"
#define STORE4(stride,out,a,b,c,d)\
"movq "#a", 0*"#stride"+"#out"\n\t"\
"movq "#b", 1*"#stride"+"#out"\n\t"\
"movq "#c", 2*"#stride"+"#out"\n\t"\
"movq "#d", 3*"#stride"+"#out"\n\t"
/* in/out: mma=mma+mmb, mmb=mmb-mma */
#define SUMSUB_BA( a, b ) \
"paddw "#b", "#a" \n\t"\
"paddw "#b", "#b" \n\t"\
"psubw "#a", "#b" \n\t"
#define SBUTTERFLY(a,b,t,n,m)\
"mov" #m " " #a ", " #t " \n\t" /* abcd */\
"punpckl" #n " " #b ", " #a " \n\t" /* aebf */\
"punpckh" #n " " #b ", " #t " \n\t" /* cgdh */\
#define TRANSPOSE4(a,b,c,d,t)\
SBUTTERFLY(a,b,t,wd,q) /* a=aebf t=cgdh */\
SBUTTERFLY(c,d,b,wd,q) /* c=imjn b=kolp */\
SBUTTERFLY(a,c,d,dq,q) /* a=aeim d=bfjn */\
SBUTTERFLY(t,b,c,dq,q) /* t=cgko c=dhlp */
#ifdef ARCH_X86_64
// permutes 01234567 -> 05736421
#define TRANSPOSE8(a,b,c,d,e,f,g,h,t)\
SBUTTERFLY(a,b,%%xmm8,wd,dqa)\
SBUTTERFLY(c,d,b,wd,dqa)\
SBUTTERFLY(e,f,d,wd,dqa)\
SBUTTERFLY(g,h,f,wd,dqa)\
SBUTTERFLY(a,c,h,dq,dqa)\
SBUTTERFLY(%%xmm8,b,c,dq,dqa)\
SBUTTERFLY(e,g,b,dq,dqa)\
SBUTTERFLY(d,f,g,dq,dqa)\
SBUTTERFLY(a,e,f,qdq,dqa)\
SBUTTERFLY(%%xmm8,d,e,qdq,dqa)\
SBUTTERFLY(h,b,d,qdq,dqa)\
SBUTTERFLY(c,g,b,qdq,dqa)\
"movdqa %%xmm8, "#g" \n\t"
#else
#define TRANSPOSE8(a,b,c,d,e,f,g,h,t)\
"movdqa "#h", "#t" \n\t"\
SBUTTERFLY(a,b,h,wd,dqa)\
"movdqa "#h", 16"#t" \n\t"\
"movdqa "#t", "#h" \n\t"\
SBUTTERFLY(c,d,b,wd,dqa)\
SBUTTERFLY(e,f,d,wd,dqa)\
SBUTTERFLY(g,h,f,wd,dqa)\
SBUTTERFLY(a,c,h,dq,dqa)\
"movdqa "#h", "#t" \n\t"\
"movdqa 16"#t", "#h" \n\t"\
SBUTTERFLY(h,b,c,dq,dqa)\
SBUTTERFLY(e,g,b,dq,dqa)\
SBUTTERFLY(d,f,g,dq,dqa)\
SBUTTERFLY(a,e,f,qdq,dqa)\
SBUTTERFLY(h,d,e,qdq,dqa)\
"movdqa "#h", 16"#t" \n\t"\
"movdqa "#t", "#h" \n\t"\
SBUTTERFLY(h,b,d,qdq,dqa)\
SBUTTERFLY(c,g,b,qdq,dqa)\
"movdqa 16"#t", "#g" \n\t"
#endif
#define MOVQ_WONE(regd) \
asm volatile ( \
"pcmpeqd %%" #regd ", %%" #regd " \n\t" \
"psrlw $15, %%" #regd ::)
void dsputilenc_init_mmx(DSPContext* c, AVCodecContext *avctx);
#endif /* FFMPEG_DSPUTIL_MMX_H */
@@ -0,0 +1,900 @@
/*
* DSP utils : average functions are compiled twice for 3dnow/mmx2
* Copyright (c) 2000, 2001 Fabrice Bellard.
* Copyright (c) 2002-2004 Michael Niedermayer
*
* MMX optimization by Nick Kurshev <[email protected]>
* mostly rewritten by Michael Niedermayer <[email protected]>
* and improved by Zdenek Kabelac <[email protected]>
*
* 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
*/
/* This header intentionally has no multiple inclusion guards. It is meant to
* be included multiple times and generates different code depending on the
* value of certain #defines. */
/* XXX: we use explicit registers to avoid a gcc 2.95.2 register asm
clobber bug - now it will work with 2.95.2 and also with -fPIC
*/
static void DEF(put_pixels8_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm1 \n\t"
PAVGB" 1(%1), %%mm0 \n\t"
PAVGB" 1(%1, %3), %%mm1 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm1 \n\t"
PAVGB" 1(%1), %%mm0 \n\t"
PAVGB" 1(%1, %3), %%mm1 \n\t"
"add %%"REG_a", %1 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
static void DEF(put_pixels4_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
asm volatile(
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movd (%1), %%mm0 \n\t"
"movd (%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"add $4, %2 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
"movd %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
"1: \n\t"
"movd (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movd (%1), %%mm1 \n\t"
"movd (%2), %%mm2 \n\t"
"movd 4(%2), %%mm3 \n\t"
"add %4, %1 \n\t"
PAVGB" %%mm2, %%mm0 \n\t"
PAVGB" %%mm3, %%mm1 \n\t"
"movd %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"movd %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"movd (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movd (%1), %%mm1 \n\t"
"movd 8(%2), %%mm2 \n\t"
"movd 12(%2), %%mm3 \n\t"
"add %4, %1 \n\t"
PAVGB" %%mm2, %%mm0 \n\t"
PAVGB" %%mm3, %%mm1 \n\t"
"movd %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"movd %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"add $16, %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
}
static void DEF(put_pixels8_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
asm volatile(
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"add $8, %2 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movq (%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" 8(%2), %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"movq %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"movq (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movq (%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" 16(%2), %%mm0 \n\t"
PAVGB" 24(%2), %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"movq %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"add $32, %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
//the following should be used, though better not with gcc ...
/* :"+g"(h), "+r"(src1), "+r"(src2), "+r"(dst)
:"r"(src1Stride), "r"(dstStride)
:"memory");*/
}
static void DEF(put_no_rnd_pixels8_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
asm volatile(
"pcmpeqb %%mm6, %%mm6 \n\t"
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"add $8, %2 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movq (%1), %%mm1 \n\t"
"add %4, %1 \n\t"
"movq (%2), %%mm2 \n\t"
"movq 8(%2), %%mm3 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"pxor %%mm6, %%mm2 \n\t"
"pxor %%mm6, %%mm3 \n\t"
PAVGB" %%mm2, %%mm0 \n\t"
PAVGB" %%mm3, %%mm1 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"movq %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"movq (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movq (%1), %%mm1 \n\t"
"add %4, %1 \n\t"
"movq 16(%2), %%mm2 \n\t"
"movq 24(%2), %%mm3 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"pxor %%mm6, %%mm2 \n\t"
"pxor %%mm6, %%mm3 \n\t"
PAVGB" %%mm2, %%mm0 \n\t"
PAVGB" %%mm3, %%mm1 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"movq %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"add $32, %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
//the following should be used, though better not with gcc ...
/* :"+g"(h), "+r"(src1), "+r"(src2), "+r"(dst)
:"r"(src1Stride), "r"(dstStride)
:"memory");*/
}
static void DEF(avg_pixels4_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
asm volatile(
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movd (%1), %%mm0 \n\t"
"movd (%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"add $4, %2 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
PAVGB" (%3), %%mm0 \n\t"
"movd %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
"1: \n\t"
"movd (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movd (%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" 4(%2), %%mm1 \n\t"
PAVGB" (%3), %%mm0 \n\t"
"movd %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
PAVGB" (%3), %%mm1 \n\t"
"movd %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"movd (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movd (%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" 8(%2), %%mm0 \n\t"
PAVGB" 12(%2), %%mm1 \n\t"
PAVGB" (%3), %%mm0 \n\t"
"movd %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
PAVGB" (%3), %%mm1 \n\t"
"movd %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"add $16, %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
}
static void DEF(avg_pixels8_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
asm volatile(
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"add $8, %2 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
PAVGB" (%3), %%mm0 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movq (%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" 8(%2), %%mm1 \n\t"
PAVGB" (%3), %%mm0 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
PAVGB" (%3), %%mm1 \n\t"
"movq %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"movq (%1), %%mm0 \n\t"
"add %4, %1 \n\t"
"movq (%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" 16(%2), %%mm0 \n\t"
PAVGB" 24(%2), %%mm1 \n\t"
PAVGB" (%3), %%mm0 \n\t"
"movq %%mm0, (%3) \n\t"
"add %5, %3 \n\t"
PAVGB" (%3), %%mm1 \n\t"
"movq %%mm1, (%3) \n\t"
"add %5, %3 \n\t"
"add $32, %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
//the following should be used, though better not with gcc ...
/* :"+g"(h), "+r"(src1), "+r"(src2), "+r"(dst)
:"r"(src1Stride), "r"(dstStride)
:"memory");*/
}
static void DEF(put_pixels16_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq 8(%1), %%mm2 \n\t"
"movq 8(%1, %3), %%mm3 \n\t"
PAVGB" 1(%1), %%mm0 \n\t"
PAVGB" 1(%1, %3), %%mm1 \n\t"
PAVGB" 9(%1), %%mm2 \n\t"
PAVGB" 9(%1, %3), %%mm3 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"movq %%mm2, 8(%2) \n\t"
"movq %%mm3, 8(%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq 8(%1), %%mm2 \n\t"
"movq 8(%1, %3), %%mm3 \n\t"
PAVGB" 1(%1), %%mm0 \n\t"
PAVGB" 1(%1, %3), %%mm1 \n\t"
PAVGB" 9(%1), %%mm2 \n\t"
PAVGB" 9(%1, %3), %%mm3 \n\t"
"add %%"REG_a", %1 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"movq %%mm2, 8(%2) \n\t"
"movq %%mm3, 8(%2, %3) \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
static void DEF(put_pixels16_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
asm volatile(
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" 8(%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"add $16, %2 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" 8(%2), %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" 16(%2), %%mm0 \n\t"
PAVGB" 24(%2), %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"add $32, %2 \n\t"
"subl $2, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
//the following should be used, though better not with gcc ...
/* :"+g"(h), "+r"(src1), "+r"(src2), "+r"(dst)
:"r"(src1Stride), "r"(dstStride)
:"memory");*/
}
static void DEF(avg_pixels16_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
asm volatile(
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" 8(%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"add $16, %2 \n\t"
PAVGB" (%3), %%mm0 \n\t"
PAVGB" 8(%3), %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" 8(%2), %%mm1 \n\t"
PAVGB" (%3), %%mm0 \n\t"
PAVGB" 8(%3), %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
"add %4, %1 \n\t"
PAVGB" 16(%2), %%mm0 \n\t"
PAVGB" 24(%2), %%mm1 \n\t"
PAVGB" (%3), %%mm0 \n\t"
PAVGB" 8(%3), %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"add $32, %2 \n\t"
"subl $2, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
//the following should be used, though better not with gcc ...
/* :"+g"(h), "+r"(src1), "+r"(src2), "+r"(dst)
:"r"(src1Stride), "r"(dstStride)
:"memory");*/
}
static void DEF(put_no_rnd_pixels16_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
asm volatile(
"pcmpeqb %%mm6, %%mm6 \n\t"
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
"movq (%2), %%mm2 \n\t"
"movq 8(%2), %%mm3 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"pxor %%mm6, %%mm2 \n\t"
"pxor %%mm6, %%mm3 \n\t"
PAVGB" %%mm2, %%mm0 \n\t"
PAVGB" %%mm3, %%mm1 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"add %4, %1 \n\t"
"add $16, %2 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
"add %4, %1 \n\t"
"movq (%2), %%mm2 \n\t"
"movq 8(%2), %%mm3 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"pxor %%mm6, %%mm2 \n\t"
"pxor %%mm6, %%mm3 \n\t"
PAVGB" %%mm2, %%mm0 \n\t"
PAVGB" %%mm3, %%mm1 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm1 \n\t"
"add %4, %1 \n\t"
"movq 16(%2), %%mm2 \n\t"
"movq 24(%2), %%mm3 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"pxor %%mm6, %%mm2 \n\t"
"pxor %%mm6, %%mm3 \n\t"
PAVGB" %%mm2, %%mm0 \n\t"
PAVGB" %%mm3, %%mm1 \n\t"
"pxor %%mm6, %%mm0 \n\t"
"pxor %%mm6, %%mm1 \n\t"
"movq %%mm0, (%3) \n\t"
"movq %%mm1, 8(%3) \n\t"
"add %5, %3 \n\t"
"add $32, %2 \n\t"
"subl $2, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
//the following should be used, though better not with gcc ...
/* :"+g"(h), "+r"(src1), "+r"(src2), "+r"(dst)
:"r"(src1Stride), "r"(dstStride)
:"memory");*/
}
/* GL: this function does incorrect rounding if overflow */
static void DEF(put_no_rnd_pixels8_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BONE(mm6);
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm2 \n\t"
"movq 1(%1), %%mm1 \n\t"
"movq 1(%1, %3), %%mm3 \n\t"
"add %%"REG_a", %1 \n\t"
"psubusb %%mm6, %%mm0 \n\t"
"psubusb %%mm6, %%mm2 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
PAVGB" %%mm3, %%mm2 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm2, (%2, %3) \n\t"
"movq (%1), %%mm0 \n\t"
"movq 1(%1), %%mm1 \n\t"
"movq (%1, %3), %%mm2 \n\t"
"movq 1(%1, %3), %%mm3 \n\t"
"add %%"REG_a", %2 \n\t"
"add %%"REG_a", %1 \n\t"
"psubusb %%mm6, %%mm0 \n\t"
"psubusb %%mm6, %%mm2 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
PAVGB" %%mm3, %%mm2 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm2, (%2, %3) \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
static void DEF(put_pixels8_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"movq (%1), %%mm0 \n\t"
"sub %3, %2 \n\t"
"1: \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm2 \n\t"
"add %%"REG_a", %1 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
PAVGB" %%mm2, %%mm1 \n\t"
"movq %%mm0, (%2, %3) \n\t"
"movq %%mm1, (%2, %%"REG_a") \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"add %%"REG_a", %2 \n\t"
"add %%"REG_a", %1 \n\t"
PAVGB" %%mm1, %%mm2 \n\t"
PAVGB" %%mm0, %%mm1 \n\t"
"movq %%mm2, (%2, %3) \n\t"
"movq %%mm1, (%2, %%"REG_a") \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D" (block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
/* GL: this function does incorrect rounding if overflow */
static void DEF(put_no_rnd_pixels8_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BONE(mm6);
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"movq (%1), %%mm0 \n\t"
"sub %3, %2 \n\t"
"1: \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm2 \n\t"
"add %%"REG_a", %1 \n\t"
"psubusb %%mm6, %%mm1 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
PAVGB" %%mm2, %%mm1 \n\t"
"movq %%mm0, (%2, %3) \n\t"
"movq %%mm1, (%2, %%"REG_a") \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"add %%"REG_a", %2 \n\t"
"add %%"REG_a", %1 \n\t"
"psubusb %%mm6, %%mm1 \n\t"
PAVGB" %%mm1, %%mm2 \n\t"
PAVGB" %%mm0, %%mm1 \n\t"
"movq %%mm2, (%2, %3) \n\t"
"movq %%mm1, (%2, %%"REG_a") \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D" (block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
static void DEF(avg_pixels8)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"1: \n\t"
"movq (%2), %%mm0 \n\t"
"movq (%2, %3), %%mm1 \n\t"
PAVGB" (%1), %%mm0 \n\t"
PAVGB" (%1, %3), %%mm1 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"movq (%2), %%mm0 \n\t"
"movq (%2, %3), %%mm1 \n\t"
PAVGB" (%1), %%mm0 \n\t"
PAVGB" (%1, %3), %%mm1 \n\t"
"add %%"REG_a", %1 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
static void DEF(avg_pixels8_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm2 \n\t"
PAVGB" 1(%1), %%mm0 \n\t"
PAVGB" 1(%1, %3), %%mm2 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" (%2, %3), %%mm2 \n\t"
"add %%"REG_a", %1 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm2, (%2, %3) \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm2 \n\t"
PAVGB" 1(%1), %%mm0 \n\t"
PAVGB" 1(%1, %3), %%mm2 \n\t"
"add %%"REG_a", %2 \n\t"
"add %%"REG_a", %1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" (%2, %3), %%mm2 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm2, (%2, %3) \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
static void DEF(avg_pixels8_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"movq (%1), %%mm0 \n\t"
"sub %3, %2 \n\t"
"1: \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm2 \n\t"
"add %%"REG_a", %1 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
PAVGB" %%mm2, %%mm1 \n\t"
"movq (%2, %3), %%mm3 \n\t"
"movq (%2, %%"REG_a"), %%mm4 \n\t"
PAVGB" %%mm3, %%mm0 \n\t"
PAVGB" %%mm4, %%mm1 \n\t"
"movq %%mm0, (%2, %3) \n\t"
"movq %%mm1, (%2, %%"REG_a") \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
PAVGB" %%mm1, %%mm2 \n\t"
PAVGB" %%mm0, %%mm1 \n\t"
"add %%"REG_a", %2 \n\t"
"add %%"REG_a", %1 \n\t"
"movq (%2, %3), %%mm3 \n\t"
"movq (%2, %%"REG_a"), %%mm4 \n\t"
PAVGB" %%mm3, %%mm2 \n\t"
PAVGB" %%mm4, %%mm1 \n\t"
"movq %%mm2, (%2, %3) \n\t"
"movq %%mm1, (%2, %%"REG_a") \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
/* Note this is not correctly rounded, but this function is only
* used for B-frames so it does not matter. */
static void DEF(avg_pixels8_xy2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BONE(mm6);
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"movq (%1), %%mm0 \n\t"
PAVGB" 1(%1), %%mm0 \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1, %%"REG_a"), %%mm2 \n\t"
"movq (%1, %3), %%mm1 \n\t"
"psubusb %%mm6, %%mm2 \n\t"
PAVGB" 1(%1, %3), %%mm1 \n\t"
PAVGB" 1(%1, %%"REG_a"), %%mm2 \n\t"
"add %%"REG_a", %1 \n\t"
PAVGB" %%mm1, %%mm0 \n\t"
PAVGB" %%mm2, %%mm1 \n\t"
PAVGB" (%2), %%mm0 \n\t"
PAVGB" (%2, %3), %%mm1 \n\t"
"movq %%mm0, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
PAVGB" 1(%1, %3), %%mm1 \n\t"
PAVGB" 1(%1, %%"REG_a"), %%mm0 \n\t"
"add %%"REG_a", %2 \n\t"
"add %%"REG_a", %1 \n\t"
PAVGB" %%mm1, %%mm2 \n\t"
PAVGB" %%mm0, %%mm1 \n\t"
PAVGB" (%2), %%mm2 \n\t"
PAVGB" (%2, %3), %%mm1 \n\t"
"movq %%mm2, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r" ((x86_reg)line_size)
:"%"REG_a, "memory");
}
static void DEF(avg_pixels4)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
do {
asm volatile(
"movd (%1), %%mm0 \n\t"
"movd (%1, %2), %%mm1 \n\t"
"movd (%1, %2, 2), %%mm2 \n\t"
"movd (%1, %3), %%mm3 \n\t"
PAVGB" (%0), %%mm0 \n\t"
PAVGB" (%0, %2), %%mm1 \n\t"
PAVGB" (%0, %2, 2), %%mm2 \n\t"
PAVGB" (%0, %3), %%mm3 \n\t"
"movd %%mm0, (%1) \n\t"
"movd %%mm1, (%1, %2) \n\t"
"movd %%mm2, (%1, %2, 2) \n\t"
"movd %%mm3, (%1, %3) \n\t"
::"S"(pixels), "D"(block),
"r" ((x86_reg)line_size), "r"((x86_reg)3L*line_size)
:"memory");
block += 4*line_size;
pixels += 4*line_size;
h -= 4;
} while(h > 0);
}
//FIXME the following could be optimized too ...
static void DEF(put_no_rnd_pixels16_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(put_no_rnd_pixels8_x2)(block , pixels , line_size, h);
DEF(put_no_rnd_pixels8_x2)(block+8, pixels+8, line_size, h);
}
static void DEF(put_pixels16_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(put_pixels8_y2)(block , pixels , line_size, h);
DEF(put_pixels8_y2)(block+8, pixels+8, line_size, h);
}
static void DEF(put_no_rnd_pixels16_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(put_no_rnd_pixels8_y2)(block , pixels , line_size, h);
DEF(put_no_rnd_pixels8_y2)(block+8, pixels+8, line_size, h);
}
static void DEF(avg_pixels16)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(avg_pixels8)(block , pixels , line_size, h);
DEF(avg_pixels8)(block+8, pixels+8, line_size, h);
}
static void DEF(avg_pixels16_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(avg_pixels8_x2)(block , pixels , line_size, h);
DEF(avg_pixels8_x2)(block+8, pixels+8, line_size, h);
}
static void DEF(avg_pixels16_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(avg_pixels8_y2)(block , pixels , line_size, h);
DEF(avg_pixels8_y2)(block+8, pixels+8, line_size, h);
}
static void DEF(avg_pixels16_xy2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(avg_pixels8_xy2)(block , pixels , line_size, h);
DEF(avg_pixels8_xy2)(block+8, pixels+8, line_size, h);
}
#define QPEL_2TAP_L3(OPNAME) \
static void DEF(OPNAME ## 2tap_qpel16_l3)(uint8_t *dst, uint8_t *src, int stride, int h, int off1, int off2){\
asm volatile(\
"1: \n\t"\
"movq (%1,%2), %%mm0 \n\t"\
"movq 8(%1,%2), %%mm1 \n\t"\
PAVGB" (%1,%3), %%mm0 \n\t"\
PAVGB" 8(%1,%3), %%mm1 \n\t"\
PAVGB" (%1), %%mm0 \n\t"\
PAVGB" 8(%1), %%mm1 \n\t"\
STORE_OP( (%1,%4),%%mm0)\
STORE_OP(8(%1,%4),%%mm1)\
"movq %%mm0, (%1,%4) \n\t"\
"movq %%mm1, 8(%1,%4) \n\t"\
"add %5, %1 \n\t"\
"decl %0 \n\t"\
"jnz 1b \n\t"\
:"+g"(h), "+r"(src)\
:"r"((x86_reg)off1), "r"((x86_reg)off2),\
"r"((x86_reg)(dst-src)), "r"((x86_reg)stride)\
:"memory"\
);\
}\
static void DEF(OPNAME ## 2tap_qpel8_l3)(uint8_t *dst, uint8_t *src, int stride, int h, int off1, int off2){\
asm volatile(\
"1: \n\t"\
"movq (%1,%2), %%mm0 \n\t"\
PAVGB" (%1,%3), %%mm0 \n\t"\
PAVGB" (%1), %%mm0 \n\t"\
STORE_OP((%1,%4),%%mm0)\
"movq %%mm0, (%1,%4) \n\t"\
"add %5, %1 \n\t"\
"decl %0 \n\t"\
"jnz 1b \n\t"\
:"+g"(h), "+r"(src)\
:"r"((x86_reg)off1), "r"((x86_reg)off2),\
"r"((x86_reg)(dst-src)), "r"((x86_reg)stride)\
:"memory"\
);\
}
#define STORE_OP(a,b) PAVGB" "#a","#b" \n\t"
QPEL_2TAP_L3(avg_)
#undef STORE_OP
#define STORE_OP(a,b)
QPEL_2TAP_L3(put_)
#undef STORE_OP
#undef QPEL_2TAP_L3
@@ -0,0 +1,105 @@
/*
* DSP utils : QNS functions are compiled 3 times for mmx/3dnow/ssse3
* Copyright (c) 2004 Michael Niedermayer
*
* MMX optimization by Michael Niedermayer <[email protected]>
* 3DNow! and SSSE3 optimization by Zuxy Meng <[email protected]>
*
* 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
*/
/* This header intentionally has no multiple inclusion guards. It is meant to
* be included multiple times and generates different code depending on the
* value of certain #defines. */
#define MAX_ABS (512 >> (SCALE_OFFSET>0 ? SCALE_OFFSET : 0))
static int DEF(try_8x8basis)(int16_t rem[64], int16_t weight[64], int16_t basis[64], int scale)
{
x86_reg i=0;
assert(FFABS(scale) < MAX_ABS);
scale<<= 16 + SCALE_OFFSET - BASIS_SHIFT + RECON_SHIFT;
SET_RND(mm6);
asm volatile(
"pxor %%mm7, %%mm7 \n\t"
"movd %4, %%mm5 \n\t"
"punpcklwd %%mm5, %%mm5 \n\t"
"punpcklwd %%mm5, %%mm5 \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%1, %0), %%mm0 \n\t"
"movq 8(%1, %0), %%mm1 \n\t"
PMULHRW(%%mm0, %%mm1, %%mm5, %%mm6)
"paddw (%2, %0), %%mm0 \n\t"
"paddw 8(%2, %0), %%mm1 \n\t"
"psraw $6, %%mm0 \n\t"
"psraw $6, %%mm1 \n\t"
"pmullw (%3, %0), %%mm0 \n\t"
"pmullw 8(%3, %0), %%mm1 \n\t"
"pmaddwd %%mm0, %%mm0 \n\t"
"pmaddwd %%mm1, %%mm1 \n\t"
"paddd %%mm1, %%mm0 \n\t"
"psrld $4, %%mm0 \n\t"
"paddd %%mm0, %%mm7 \n\t"
"add $16, %0 \n\t"
"cmp $128, %0 \n\t" //FIXME optimize & bench
" jb 1b \n\t"
PHADDD(%%mm7, %%mm6)
"psrld $2, %%mm7 \n\t"
"movd %%mm7, %0 \n\t"
: "+r" (i)
: "r"(basis), "r"(rem), "r"(weight), "g"(scale)
);
return i;
}
static void DEF(add_8x8basis)(int16_t rem[64], int16_t basis[64], int scale)
{
x86_reg i=0;
if(FFABS(scale) < MAX_ABS){
scale<<= 16 + SCALE_OFFSET - BASIS_SHIFT + RECON_SHIFT;
SET_RND(mm6);
asm volatile(
"movd %3, %%mm5 \n\t"
"punpcklwd %%mm5, %%mm5 \n\t"
"punpcklwd %%mm5, %%mm5 \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%1, %0), %%mm0 \n\t"
"movq 8(%1, %0), %%mm1 \n\t"
PMULHRW(%%mm0, %%mm1, %%mm5, %%mm6)
"paddw (%2, %0), %%mm0 \n\t"
"paddw 8(%2, %0), %%mm1 \n\t"
"movq %%mm0, (%2, %0) \n\t"
"movq %%mm1, 8(%2, %0) \n\t"
"add $16, %0 \n\t"
"cmp $128, %0 \n\t" // FIXME optimize & bench
" jb 1b \n\t"
: "+r" (i)
: "r"(basis), "r"(rem), "g"(scale)
);
}else{
for(i=0; i<8*8; i++){
rem[i] += (basis[i]*scale + (1<<(BASIS_SHIFT - RECON_SHIFT-1)))>>(BASIS_SHIFT - RECON_SHIFT);
}
}
}
@@ -0,0 +1,594 @@
/*
* DSP utils mmx functions are compiled twice for rnd/no_rnd
* Copyright (c) 2000, 2001 Fabrice Bellard.
* Copyright (c) 2003-2004 Michael Niedermayer <[email protected]>
*
* MMX optimization by Nick Kurshev <[email protected]>
* mostly rewritten by Michael Niedermayer <[email protected]>
* and improved by Zdenek Kabelac <[email protected]>
*
* 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
*/
/* This header intentionally has no multiple inclusion guards. It is meant to
* be included multiple times and generates different code depending on the
* value of certain #defines. */
// put_pixels
static void DEF(put, pixels8_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq 1(%1), %%mm1 \n\t"
"movq (%1, %3), %%mm2 \n\t"
"movq 1(%1, %3), %%mm3 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%2) \n\t"
"movq %%mm5, (%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"movq (%1), %%mm0 \n\t"
"movq 1(%1), %%mm1 \n\t"
"movq (%1, %3), %%mm2 \n\t"
"movq 1(%1, %3), %%mm3 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%2) \n\t"
"movq %%mm5, (%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r"((x86_reg)line_size)
:REG_a, "memory");
}
static void av_unused DEF(put, pixels8_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
MOVQ_BFE(mm6);
asm volatile(
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"add $8, %2 \n\t"
PAVGB(%%mm0, %%mm1, %%mm4, %%mm6)
"movq %%mm4, (%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"movq (%1), %%mm2 \n\t"
"movq 8(%2), %%mm3 \n\t"
"add %4, %1 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%3) \n\t"
"add %5, %3 \n\t"
"movq %%mm5, (%3) \n\t"
"add %5, %3 \n\t"
"movq (%1), %%mm0 \n\t"
"movq 16(%2), %%mm1 \n\t"
"add %4, %1 \n\t"
"movq (%1), %%mm2 \n\t"
"movq 24(%2), %%mm3 \n\t"
"add %4, %1 \n\t"
"add $32, %2 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%3) \n\t"
"add %5, %3 \n\t"
"movq %%mm5, (%3) \n\t"
"add %5, %3 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
}
static void DEF(put, pixels16_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq 1(%1), %%mm1 \n\t"
"movq (%1, %3), %%mm2 \n\t"
"movq 1(%1, %3), %%mm3 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%2) \n\t"
"movq %%mm5, (%2, %3) \n\t"
"movq 8(%1), %%mm0 \n\t"
"movq 9(%1), %%mm1 \n\t"
"movq 8(%1, %3), %%mm2 \n\t"
"movq 9(%1, %3), %%mm3 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, 8(%2) \n\t"
"movq %%mm5, 8(%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"movq (%1), %%mm0 \n\t"
"movq 1(%1), %%mm1 \n\t"
"movq (%1, %3), %%mm2 \n\t"
"movq 1(%1, %3), %%mm3 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%2) \n\t"
"movq %%mm5, (%2, %3) \n\t"
"movq 8(%1), %%mm0 \n\t"
"movq 9(%1), %%mm1 \n\t"
"movq 8(%1, %3), %%mm2 \n\t"
"movq 9(%1, %3), %%mm3 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, 8(%2) \n\t"
"movq %%mm5, 8(%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r"((x86_reg)line_size)
:REG_a, "memory");
}
static void av_unused DEF(put, pixels16_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
MOVQ_BFE(mm6);
asm volatile(
"testl $1, %0 \n\t"
" jz 1f \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%2), %%mm1 \n\t"
"movq 8(%1), %%mm2 \n\t"
"movq 8(%2), %%mm3 \n\t"
"add %4, %1 \n\t"
"add $16, %2 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%3) \n\t"
"movq %%mm5, 8(%3) \n\t"
"add %5, %3 \n\t"
"decl %0 \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%2), %%mm1 \n\t"
"movq 8(%1), %%mm2 \n\t"
"movq 8(%2), %%mm3 \n\t"
"add %4, %1 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%3) \n\t"
"movq %%mm5, 8(%3) \n\t"
"add %5, %3 \n\t"
"movq (%1), %%mm0 \n\t"
"movq 16(%2), %%mm1 \n\t"
"movq 8(%1), %%mm2 \n\t"
"movq 24(%2), %%mm3 \n\t"
"add %4, %1 \n\t"
PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5)
"movq %%mm4, (%3) \n\t"
"movq %%mm5, 8(%3) \n\t"
"add %5, %3 \n\t"
"add $32, %2 \n\t"
"subl $2, %0 \n\t"
"jnz 1b \n\t"
#ifdef PIC //Note "+bm" and "+mb" are buggy too (with gcc 3.2.2 at least) and cannot be used
:"+m"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#else
:"+b"(h), "+a"(src1), "+c"(src2), "+d"(dst)
#endif
:"S"((x86_reg)src1Stride), "D"((x86_reg)dstStride)
:"memory");
}
static void DEF(put, pixels8_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"movq (%1), %%mm0 \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"),%%mm2 \n\t"
PAVGBP(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5)
"movq %%mm4, (%2) \n\t"
"movq %%mm5, (%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"),%%mm0 \n\t"
PAVGBP(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5)
"movq %%mm4, (%2) \n\t"
"movq %%mm5, (%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r"((x86_reg)line_size)
:REG_a, "memory");
}
static void DEF(put, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_ZERO(mm7);
SET_RND(mm6); // =2 for rnd and =1 for no_rnd version
asm volatile(
"movq (%1), %%mm0 \n\t"
"movq 1(%1), %%mm4 \n\t"
"movq %%mm0, %%mm1 \n\t"
"movq %%mm4, %%mm5 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpcklbw %%mm7, %%mm4 \n\t"
"punpckhbw %%mm7, %%mm1 \n\t"
"punpckhbw %%mm7, %%mm5 \n\t"
"paddusw %%mm0, %%mm4 \n\t"
"paddusw %%mm1, %%mm5 \n\t"
"xor %%"REG_a", %%"REG_a" \n\t"
"add %3, %1 \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"movq 1(%1, %%"REG_a"), %%mm2 \n\t"
"movq %%mm0, %%mm1 \n\t"
"movq %%mm2, %%mm3 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpcklbw %%mm7, %%mm2 \n\t"
"punpckhbw %%mm7, %%mm1 \n\t"
"punpckhbw %%mm7, %%mm3 \n\t"
"paddusw %%mm2, %%mm0 \n\t"
"paddusw %%mm3, %%mm1 \n\t"
"paddusw %%mm6, %%mm4 \n\t"
"paddusw %%mm6, %%mm5 \n\t"
"paddusw %%mm0, %%mm4 \n\t"
"paddusw %%mm1, %%mm5 \n\t"
"psrlw $2, %%mm4 \n\t"
"psrlw $2, %%mm5 \n\t"
"packuswb %%mm5, %%mm4 \n\t"
"movq %%mm4, (%2, %%"REG_a") \n\t"
"add %3, %%"REG_a" \n\t"
"movq (%1, %%"REG_a"), %%mm2 \n\t" // 0 <-> 2 1 <-> 3
"movq 1(%1, %%"REG_a"), %%mm4 \n\t"
"movq %%mm2, %%mm3 \n\t"
"movq %%mm4, %%mm5 \n\t"
"punpcklbw %%mm7, %%mm2 \n\t"
"punpcklbw %%mm7, %%mm4 \n\t"
"punpckhbw %%mm7, %%mm3 \n\t"
"punpckhbw %%mm7, %%mm5 \n\t"
"paddusw %%mm2, %%mm4 \n\t"
"paddusw %%mm3, %%mm5 \n\t"
"paddusw %%mm6, %%mm0 \n\t"
"paddusw %%mm6, %%mm1 \n\t"
"paddusw %%mm4, %%mm0 \n\t"
"paddusw %%mm5, %%mm1 \n\t"
"psrlw $2, %%mm0 \n\t"
"psrlw $2, %%mm1 \n\t"
"packuswb %%mm1, %%mm0 \n\t"
"movq %%mm0, (%2, %%"REG_a") \n\t"
"add %3, %%"REG_a" \n\t"
"subl $2, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels)
:"D"(block), "r"((x86_reg)line_size)
:REG_a, "memory");
}
// avg_pixels
static void av_unused DEF(avg, pixels4)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
JUMPALIGN();
do {
asm volatile(
"movd %0, %%mm0 \n\t"
"movd %1, %%mm1 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
"movd %%mm2, %0 \n\t"
:"+m"(*block)
:"m"(*pixels)
:"memory");
pixels += line_size;
block += line_size;
}
while (--h);
}
// in case more speed is needed - unroling would certainly help
static void DEF(avg, pixels8)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
JUMPALIGN();
do {
asm volatile(
"movq %0, %%mm0 \n\t"
"movq %1, %%mm1 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
"movq %%mm2, %0 \n\t"
:"+m"(*block)
:"m"(*pixels)
:"memory");
pixels += line_size;
block += line_size;
}
while (--h);
}
static void DEF(avg, pixels16)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
JUMPALIGN();
do {
asm volatile(
"movq %0, %%mm0 \n\t"
"movq %1, %%mm1 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
"movq %%mm2, %0 \n\t"
"movq 8%0, %%mm0 \n\t"
"movq 8%1, %%mm1 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
"movq %%mm2, 8%0 \n\t"
:"+m"(*block)
:"m"(*pixels)
:"memory");
pixels += line_size;
block += line_size;
}
while (--h);
}
static void DEF(avg, pixels8_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
JUMPALIGN();
do {
asm volatile(
"movq %1, %%mm0 \n\t"
"movq 1%1, %%mm1 \n\t"
"movq %0, %%mm3 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
PAVGB(%%mm3, %%mm2, %%mm0, %%mm6)
"movq %%mm0, %0 \n\t"
:"+m"(*block)
:"m"(*pixels)
:"memory");
pixels += line_size;
block += line_size;
} while (--h);
}
static av_unused void DEF(avg, pixels8_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
MOVQ_BFE(mm6);
JUMPALIGN();
do {
asm volatile(
"movq %1, %%mm0 \n\t"
"movq %2, %%mm1 \n\t"
"movq %0, %%mm3 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
PAVGB(%%mm3, %%mm2, %%mm0, %%mm6)
"movq %%mm0, %0 \n\t"
:"+m"(*dst)
:"m"(*src1), "m"(*src2)
:"memory");
dst += dstStride;
src1 += src1Stride;
src2 += 8;
} while (--h);
}
static void DEF(avg, pixels16_x2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
JUMPALIGN();
do {
asm volatile(
"movq %1, %%mm0 \n\t"
"movq 1%1, %%mm1 \n\t"
"movq %0, %%mm3 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
PAVGB(%%mm3, %%mm2, %%mm0, %%mm6)
"movq %%mm0, %0 \n\t"
"movq 8%1, %%mm0 \n\t"
"movq 9%1, %%mm1 \n\t"
"movq 8%0, %%mm3 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
PAVGB(%%mm3, %%mm2, %%mm0, %%mm6)
"movq %%mm0, 8%0 \n\t"
:"+m"(*block)
:"m"(*pixels)
:"memory");
pixels += line_size;
block += line_size;
} while (--h);
}
static av_unused void DEF(avg, pixels16_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int dstStride, int src1Stride, int h)
{
MOVQ_BFE(mm6);
JUMPALIGN();
do {
asm volatile(
"movq %1, %%mm0 \n\t"
"movq %2, %%mm1 \n\t"
"movq %0, %%mm3 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
PAVGB(%%mm3, %%mm2, %%mm0, %%mm6)
"movq %%mm0, %0 \n\t"
"movq 8%1, %%mm0 \n\t"
"movq 8%2, %%mm1 \n\t"
"movq 8%0, %%mm3 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
PAVGB(%%mm3, %%mm2, %%mm0, %%mm6)
"movq %%mm0, 8%0 \n\t"
:"+m"(*dst)
:"m"(*src1), "m"(*src2)
:"memory");
dst += dstStride;
src1 += src1Stride;
src2 += 16;
} while (--h);
}
static void DEF(avg, pixels8_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_BFE(mm6);
asm volatile(
"lea (%3, %3), %%"REG_a" \n\t"
"movq (%1), %%mm0 \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm2 \n\t"
PAVGBP(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5)
"movq (%2), %%mm3 \n\t"
PAVGB(%%mm3, %%mm4, %%mm0, %%mm6)
"movq (%2, %3), %%mm3 \n\t"
PAVGB(%%mm3, %%mm5, %%mm1, %%mm6)
"movq %%mm0, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"movq (%1, %3), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
PAVGBP(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5)
"movq (%2), %%mm3 \n\t"
PAVGB(%%mm3, %%mm4, %%mm2, %%mm6)
"movq (%2, %3), %%mm3 \n\t"
PAVGB(%%mm3, %%mm5, %%mm1, %%mm6)
"movq %%mm2, (%2) \n\t"
"movq %%mm1, (%2, %3) \n\t"
"add %%"REG_a", %1 \n\t"
"add %%"REG_a", %2 \n\t"
"subl $4, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels), "+D"(block)
:"r"((x86_reg)line_size)
:REG_a, "memory");
}
// this routine is 'slightly' suboptimal but mostly unused
static void DEF(avg, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, int line_size, int h)
{
MOVQ_ZERO(mm7);
SET_RND(mm6); // =2 for rnd and =1 for no_rnd version
asm volatile(
"movq (%1), %%mm0 \n\t"
"movq 1(%1), %%mm4 \n\t"
"movq %%mm0, %%mm1 \n\t"
"movq %%mm4, %%mm5 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpcklbw %%mm7, %%mm4 \n\t"
"punpckhbw %%mm7, %%mm1 \n\t"
"punpckhbw %%mm7, %%mm5 \n\t"
"paddusw %%mm0, %%mm4 \n\t"
"paddusw %%mm1, %%mm5 \n\t"
"xor %%"REG_a", %%"REG_a" \n\t"
"add %3, %1 \n\t"
ASMALIGN(3)
"1: \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"movq 1(%1, %%"REG_a"), %%mm2 \n\t"
"movq %%mm0, %%mm1 \n\t"
"movq %%mm2, %%mm3 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpcklbw %%mm7, %%mm2 \n\t"
"punpckhbw %%mm7, %%mm1 \n\t"
"punpckhbw %%mm7, %%mm3 \n\t"
"paddusw %%mm2, %%mm0 \n\t"
"paddusw %%mm3, %%mm1 \n\t"
"paddusw %%mm6, %%mm4 \n\t"
"paddusw %%mm6, %%mm5 \n\t"
"paddusw %%mm0, %%mm4 \n\t"
"paddusw %%mm1, %%mm5 \n\t"
"psrlw $2, %%mm4 \n\t"
"psrlw $2, %%mm5 \n\t"
"movq (%2, %%"REG_a"), %%mm3 \n\t"
"packuswb %%mm5, %%mm4 \n\t"
"pcmpeqd %%mm2, %%mm2 \n\t"
"paddb %%mm2, %%mm2 \n\t"
PAVGB(%%mm3, %%mm4, %%mm5, %%mm2)
"movq %%mm5, (%2, %%"REG_a") \n\t"
"add %3, %%"REG_a" \n\t"
"movq (%1, %%"REG_a"), %%mm2 \n\t" // 0 <-> 2 1 <-> 3
"movq 1(%1, %%"REG_a"), %%mm4 \n\t"
"movq %%mm2, %%mm3 \n\t"
"movq %%mm4, %%mm5 \n\t"
"punpcklbw %%mm7, %%mm2 \n\t"
"punpcklbw %%mm7, %%mm4 \n\t"
"punpckhbw %%mm7, %%mm3 \n\t"
"punpckhbw %%mm7, %%mm5 \n\t"
"paddusw %%mm2, %%mm4 \n\t"
"paddusw %%mm3, %%mm5 \n\t"
"paddusw %%mm6, %%mm0 \n\t"
"paddusw %%mm6, %%mm1 \n\t"
"paddusw %%mm4, %%mm0 \n\t"
"paddusw %%mm5, %%mm1 \n\t"
"psrlw $2, %%mm0 \n\t"
"psrlw $2, %%mm1 \n\t"
"movq (%2, %%"REG_a"), %%mm3 \n\t"
"packuswb %%mm1, %%mm0 \n\t"
"pcmpeqd %%mm2, %%mm2 \n\t"
"paddb %%mm2, %%mm2 \n\t"
PAVGB(%%mm3, %%mm0, %%mm1, %%mm2)
"movq %%mm1, (%2, %%"REG_a") \n\t"
"add %3, %%"REG_a" \n\t"
"subl $2, %0 \n\t"
"jnz 1b \n\t"
:"+g"(h), "+S"(pixels)
:"D"(block), "r"((x86_reg)line_size)
:REG_a, "memory");
}
//FIXME optimize
static void DEF(put, pixels16_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(put, pixels8_y2)(block , pixels , line_size, h);
DEF(put, pixels8_y2)(block+8, pixels+8, line_size, h);
}
static void DEF(put, pixels16_xy2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(put, pixels8_xy2)(block , pixels , line_size, h);
DEF(put, pixels8_xy2)(block+8, pixels+8, line_size, h);
}
static void DEF(avg, pixels16_y2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(avg, pixels8_y2)(block , pixels , line_size, h);
DEF(avg, pixels8_y2)(block+8, pixels+8, line_size, h);
}
static void DEF(avg, pixels16_xy2)(uint8_t *block, const uint8_t *pixels, int line_size, int h){
DEF(avg, pixels8_xy2)(block , pixels , line_size, h);
DEF(avg, pixels8_xy2)(block+8, pixels+8, line_size, h);
}
@@ -0,0 +1,92 @@
;******************************************************************************
;* MMX optimized DSP utils
;* Copyright (c) 2008 Loren Merritt
;*
;* 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
;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
%include "x86inc.asm"
section .text align=16
%macro PSWAPD_SSE 2
pshufw %1, %2, 0x4e
%endmacro
%macro PSWAPD_3DN1 2
movq %1, %2
psrlq %1, 32
punpckldq %1, %2
%endmacro
%macro FLOAT_TO_INT16_INTERLEAVE6 1
; void ff_float_to_int16_interleave6_sse(int16_t *dst, const float **src, int len)
cglobal ff_float_to_int16_interleave6_%1, 2,7,0, dst, src, src1, src2, src3, src4, src5
%ifdef ARCH_X86_64
%define lend r10d
mov lend, r2d
%else
%define lend dword r2m
%endif
mov src1q, [srcq+1*gprsize]
mov src2q, [srcq+2*gprsize]
mov src3q, [srcq+3*gprsize]
mov src4q, [srcq+4*gprsize]
mov src5q, [srcq+5*gprsize]
mov srcq, [srcq]
sub src1q, srcq
sub src2q, srcq
sub src3q, srcq
sub src4q, srcq
sub src5q, srcq
.loop:
cvtps2pi mm0, [srcq]
cvtps2pi mm1, [srcq+src1q]
cvtps2pi mm2, [srcq+src2q]
cvtps2pi mm3, [srcq+src3q]
cvtps2pi mm4, [srcq+src4q]
cvtps2pi mm5, [srcq+src5q]
packssdw mm0, mm3
packssdw mm1, mm4
packssdw mm2, mm5
pswapd mm3, mm0
punpcklwd mm0, mm1
punpckhwd mm1, mm2
punpcklwd mm2, mm3
pswapd mm3, mm0
punpckldq mm0, mm2
punpckhdq mm2, mm1
punpckldq mm1, mm3
movq [dstq ], mm0
movq [dstq+16], mm2
movq [dstq+ 8], mm1
add srcq, 8
add dstq, 24
sub lend, 2
jg .loop
emms
RET
%endmacro ; FLOAT_TO_INT16_INTERLEAVE6
%define pswapd PSWAPD_SSE
FLOAT_TO_INT16_INTERLEAVE6 sse
%define cvtps2pi pf2id
%define pswapd PSWAPD_3DN1
FLOAT_TO_INT16_INTERLEAVE6 3dnow
%undef pswapd
FLOAT_TO_INT16_INTERLEAVE6 3dn2
%undef cvtps2pi
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,569 @@
/*
* MMX optimized forward DCT
* The gcc porting is Copyright (c) 2001 Fabrice Bellard.
* cleanup/optimizations are Copyright (c) 2002-2004 Michael Niedermayer <[email protected]>
* SSE2 optimization is Copyright (c) 2004 Denes Balatoni.
*
* from fdctam32.c - AP922 MMX(3D-Now) forward-DCT
*
* Intel Application Note AP-922 - fast, precise implementation of DCT
* http://developer.intel.com/vtune/cbts/appnotes.htm
*
* Also of inspiration:
* a page about fdct at http://www.geocities.com/ssavekar/dct.htm
* Skal's fdct at http://skal.planet-d.net/coding/dct.html
*
* 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/common.h"
#include "libavcodec/dsputil.h"
#include "mmx.h"
#define ATTR_ALIGN(align) __attribute__ ((__aligned__ (align)))
//////////////////////////////////////////////////////////////////////
//
// constants for the forward DCT
// -----------------------------
//
// Be sure to check that your compiler is aligning all constants to QWORD
// (8-byte) memory boundaries! Otherwise the unaligned memory access will
// severely stall MMX execution.
//
//////////////////////////////////////////////////////////////////////
#define BITS_FRW_ACC 3 //; 2 or 3 for accuracy
#define SHIFT_FRW_COL BITS_FRW_ACC
#define SHIFT_FRW_ROW (BITS_FRW_ACC + 17 - 3)
#define RND_FRW_ROW (1 << (SHIFT_FRW_ROW-1))
//#define RND_FRW_COL (1 << (SHIFT_FRW_COL-1))
#define X8(x) x,x,x,x,x,x,x,x
//concatenated table, for forward DCT transformation
static const int16_t fdct_tg_all_16[24] ATTR_ALIGN(16) = {
X8(13036), // tg * (2<<16) + 0.5
X8(27146), // tg * (2<<16) + 0.5
X8(-21746) // tg * (2<<16) + 0.5
};
static const int16_t ocos_4_16[8] ATTR_ALIGN(16) = {
X8(23170) //cos * (2<<15) + 0.5
};
static const int16_t fdct_one_corr[8] ATTR_ALIGN(16) = { X8(1) };
static const int32_t fdct_r_row[2] ATTR_ALIGN(8) = {RND_FRW_ROW, RND_FRW_ROW };
static struct
{
const int32_t fdct_r_row_sse2[4] ATTR_ALIGN(16);
} fdct_r_row_sse2 ATTR_ALIGN(16)=
{{
RND_FRW_ROW, RND_FRW_ROW, RND_FRW_ROW, RND_FRW_ROW
}};
//static const long fdct_r_row_sse2[4] ATTR_ALIGN(16) = {RND_FRW_ROW, RND_FRW_ROW, RND_FRW_ROW, RND_FRW_ROW};
static const int16_t tab_frw_01234567[] ATTR_ALIGN(8) = { // forward_dct coeff table
16384, 16384, 22725, 19266,
16384, 16384, 12873, 4520,
21407, 8867, 19266, -4520,
-8867, -21407, -22725, -12873,
16384, -16384, 12873, -22725,
-16384, 16384, 4520, 19266,
8867, -21407, 4520, -12873,
21407, -8867, 19266, -22725,
22725, 22725, 31521, 26722,
22725, 22725, 17855, 6270,
29692, 12299, 26722, -6270,
-12299, -29692, -31521, -17855,
22725, -22725, 17855, -31521,
-22725, 22725, 6270, 26722,
12299, -29692, 6270, -17855,
29692, -12299, 26722, -31521,
21407, 21407, 29692, 25172,
21407, 21407, 16819, 5906,
27969, 11585, 25172, -5906,
-11585, -27969, -29692, -16819,
21407, -21407, 16819, -29692,
-21407, 21407, 5906, 25172,
11585, -27969, 5906, -16819,
27969, -11585, 25172, -29692,
19266, 19266, 26722, 22654,
19266, 19266, 15137, 5315,
25172, 10426, 22654, -5315,
-10426, -25172, -26722, -15137,
19266, -19266, 15137, -26722,
-19266, 19266, 5315, 22654,
10426, -25172, 5315, -15137,
25172, -10426, 22654, -26722,
16384, 16384, 22725, 19266,
16384, 16384, 12873, 4520,
21407, 8867, 19266, -4520,
-8867, -21407, -22725, -12873,
16384, -16384, 12873, -22725,
-16384, 16384, 4520, 19266,
8867, -21407, 4520, -12873,
21407, -8867, 19266, -22725,
19266, 19266, 26722, 22654,
19266, 19266, 15137, 5315,
25172, 10426, 22654, -5315,
-10426, -25172, -26722, -15137,
19266, -19266, 15137, -26722,
-19266, 19266, 5315, 22654,
10426, -25172, 5315, -15137,
25172, -10426, 22654, -26722,
21407, 21407, 29692, 25172,
21407, 21407, 16819, 5906,
27969, 11585, 25172, -5906,
-11585, -27969, -29692, -16819,
21407, -21407, 16819, -29692,
-21407, 21407, 5906, 25172,
11585, -27969, 5906, -16819,
27969, -11585, 25172, -29692,
22725, 22725, 31521, 26722,
22725, 22725, 17855, 6270,
29692, 12299, 26722, -6270,
-12299, -29692, -31521, -17855,
22725, -22725, 17855, -31521,
-22725, 22725, 6270, 26722,
12299, -29692, 6270, -17855,
29692, -12299, 26722, -31521,
};
static struct
{
const int16_t tab_frw_01234567_sse2[256] ATTR_ALIGN(16);
} tab_frw_01234567_sse2 ATTR_ALIGN(16) =
{{
//static const int16_t tab_frw_01234567_sse2[] ATTR_ALIGN(16) = { // forward_dct coeff table
#define TABLE_SSE2 C4, C4, C1, C3, -C6, -C2, -C1, -C5, \
C4, C4, C5, C7, C2, C6, C3, -C7, \
-C4, C4, C7, C3, C6, -C2, C7, -C5, \
C4, -C4, C5, -C1, C2, -C6, C3, -C1,
// c1..c7 * cos(pi/4) * 2^15
#define C1 22725
#define C2 21407
#define C3 19266
#define C4 16384
#define C5 12873
#define C6 8867
#define C7 4520
TABLE_SSE2
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
#define C1 31521
#define C2 29692
#define C3 26722
#define C4 22725
#define C5 17855
#define C6 12299
#define C7 6270
TABLE_SSE2
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
#define C1 29692
#define C2 27969
#define C3 25172
#define C4 21407
#define C5 16819
#define C6 11585
#define C7 5906
TABLE_SSE2
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
#define C1 26722
#define C2 25172
#define C3 22654
#define C4 19266
#define C5 15137
#define C6 10426
#define C7 5315
TABLE_SSE2
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
#define C1 22725
#define C2 21407
#define C3 19266
#define C4 16384
#define C5 12873
#define C6 8867
#define C7 4520
TABLE_SSE2
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
#define C1 26722
#define C2 25172
#define C3 22654
#define C4 19266
#define C5 15137
#define C6 10426
#define C7 5315
TABLE_SSE2
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
#define C1 29692
#define C2 27969
#define C3 25172
#define C4 21407
#define C5 16819
#define C6 11585
#define C7 5906
TABLE_SSE2
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
#define C1 31521
#define C2 29692
#define C3 26722
#define C4 22725
#define C5 17855
#define C6 12299
#define C7 6270
TABLE_SSE2
}};
#define FDCT_COL(cpu, mm, mov)\
static av_always_inline void fdct_col_##cpu(const int16_t *in, int16_t *out, int offset)\
{\
mov##_m2r(*(in + offset + 1 * 8), mm##0);\
mov##_m2r(*(in + offset + 6 * 8), mm##1);\
mov##_r2r(mm##0, mm##2);\
mov##_m2r(*(in + offset + 2 * 8), mm##3);\
paddsw_r2r(mm##1, mm##0);\
mov##_m2r(*(in + offset + 5 * 8), mm##4);\
psllw_i2r(SHIFT_FRW_COL, mm##0);\
mov##_m2r(*(in + offset + 0 * 8), mm##5);\
paddsw_r2r(mm##3, mm##4);\
paddsw_m2r(*(in + offset + 7 * 8), mm##5);\
psllw_i2r(SHIFT_FRW_COL, mm##4);\
mov##_r2r(mm##0, mm##6);\
psubsw_r2r(mm##1, mm##2);\
mov##_m2r(*(fdct_tg_all_16 + 8), mm##1);\
psubsw_r2r(mm##4, mm##0);\
mov##_m2r(*(in + offset + 3 * 8), mm##7);\
pmulhw_r2r(mm##0, mm##1);\
paddsw_m2r(*(in + offset + 4 * 8), mm##7);\
psllw_i2r(SHIFT_FRW_COL, mm##5);\
paddsw_r2r(mm##4, mm##6);\
psllw_i2r(SHIFT_FRW_COL, mm##7);\
mov##_r2r(mm##5, mm##4);\
psubsw_r2r(mm##7, mm##5);\
paddsw_r2r(mm##5, mm##1);\
paddsw_r2r(mm##7, mm##4);\
por_m2r(*fdct_one_corr, mm##1);\
psllw_i2r(SHIFT_FRW_COL + 1, mm##2);\
pmulhw_m2r(*(fdct_tg_all_16 + 8), mm##5);\
mov##_r2r(mm##4, mm##7);\
psubsw_m2r(*(in + offset + 5 * 8), mm##3);\
psubsw_r2r(mm##6, mm##4);\
mov##_r2m(mm##1, *(out + offset + 2 * 8));\
paddsw_r2r(mm##6, mm##7);\
mov##_m2r(*(in + offset + 3 * 8), mm##1);\
psllw_i2r(SHIFT_FRW_COL + 1, mm##3);\
psubsw_m2r(*(in + offset + 4 * 8), mm##1);\
mov##_r2r(mm##2, mm##6);\
mov##_r2m(mm##4, *(out + offset + 4 * 8));\
paddsw_r2r(mm##3, mm##2);\
pmulhw_m2r(*ocos_4_16, mm##2);\
psubsw_r2r(mm##3, mm##6);\
pmulhw_m2r(*ocos_4_16, mm##6);\
psubsw_r2r(mm##0, mm##5);\
por_m2r(*fdct_one_corr, mm##5);\
psllw_i2r(SHIFT_FRW_COL, mm##1);\
por_m2r(*fdct_one_corr, mm##2);\
mov##_r2r(mm##1, mm##4);\
mov##_m2r(*(in + offset + 0 * 8), mm##3);\
paddsw_r2r(mm##6, mm##1);\
psubsw_m2r(*(in + offset + 7 * 8), mm##3);\
psubsw_r2r(mm##6, mm##4);\
mov##_m2r(*(fdct_tg_all_16 + 0), mm##0);\
psllw_i2r(SHIFT_FRW_COL, mm##3);\
mov##_m2r(*(fdct_tg_all_16 + 16), mm##6);\
pmulhw_r2r(mm##1, mm##0);\
mov##_r2m(mm##7, *(out + offset + 0 * 8));\
pmulhw_r2r(mm##4, mm##6);\
mov##_r2m(mm##5, *(out + offset + 6 * 8));\
mov##_r2r(mm##3, mm##7);\
mov##_m2r(*(fdct_tg_all_16 + 16), mm##5);\
psubsw_r2r(mm##2, mm##7);\
paddsw_r2r(mm##2, mm##3);\
pmulhw_r2r(mm##7, mm##5);\
paddsw_r2r(mm##3, mm##0);\
paddsw_r2r(mm##4, mm##6);\
pmulhw_m2r(*(fdct_tg_all_16 + 0), mm##3);\
por_m2r(*fdct_one_corr, mm##0);\
paddsw_r2r(mm##7, mm##5);\
psubsw_r2r(mm##6, mm##7);\
mov##_r2m(mm##0, *(out + offset + 1 * 8));\
paddsw_r2r(mm##4, mm##5);\
mov##_r2m(mm##7, *(out + offset + 3 * 8));\
psubsw_r2r(mm##1, mm##3);\
mov##_r2m(mm##5, *(out + offset + 5 * 8));\
mov##_r2m(mm##3, *(out + offset + 7 * 8));\
}
FDCT_COL(mmx, mm, movq)
FDCT_COL(sse2, xmm, movdqa)
static av_always_inline void fdct_row_sse2(const int16_t *in, int16_t *out)
{
asm volatile(
#define FDCT_ROW_SSE2_H1(i,t) \
"movq " #i "(%0), %%xmm2 \n\t" \
"movq " #i "+8(%0), %%xmm0 \n\t" \
"movdqa " #t "+32(%1), %%xmm3 \n\t" \
"movdqa " #t "+48(%1), %%xmm7 \n\t" \
"movdqa " #t "(%1), %%xmm4 \n\t" \
"movdqa " #t "+16(%1), %%xmm5 \n\t"
#define FDCT_ROW_SSE2_H2(i,t) \
"movq " #i "(%0), %%xmm2 \n\t" \
"movq " #i "+8(%0), %%xmm0 \n\t" \
"movdqa " #t "+32(%1), %%xmm3 \n\t" \
"movdqa " #t "+48(%1), %%xmm7 \n\t"
#define FDCT_ROW_SSE2(i) \
"movq %%xmm2, %%xmm1 \n\t" \
"pshuflw $27, %%xmm0, %%xmm0 \n\t" \
"paddsw %%xmm0, %%xmm1 \n\t" \
"psubsw %%xmm0, %%xmm2 \n\t" \
"punpckldq %%xmm2, %%xmm1 \n\t" \
"pshufd $78, %%xmm1, %%xmm2 \n\t" \
"pmaddwd %%xmm2, %%xmm3 \n\t" \
"pmaddwd %%xmm1, %%xmm7 \n\t" \
"pmaddwd %%xmm5, %%xmm2 \n\t" \
"pmaddwd %%xmm4, %%xmm1 \n\t" \
"paddd %%xmm7, %%xmm3 \n\t" \
"paddd %%xmm2, %%xmm1 \n\t" \
"paddd %%xmm6, %%xmm3 \n\t" \
"paddd %%xmm6, %%xmm1 \n\t" \
"psrad %3, %%xmm3 \n\t" \
"psrad %3, %%xmm1 \n\t" \
"packssdw %%xmm3, %%xmm1 \n\t" \
"movdqa %%xmm1, " #i "(%4) \n\t"
"movdqa (%2), %%xmm6 \n\t"
FDCT_ROW_SSE2_H1(0,0)
FDCT_ROW_SSE2(0)
FDCT_ROW_SSE2_H2(64,0)
FDCT_ROW_SSE2(64)
FDCT_ROW_SSE2_H1(16,64)
FDCT_ROW_SSE2(16)
FDCT_ROW_SSE2_H2(112,64)
FDCT_ROW_SSE2(112)
FDCT_ROW_SSE2_H1(32,128)
FDCT_ROW_SSE2(32)
FDCT_ROW_SSE2_H2(96,128)
FDCT_ROW_SSE2(96)
FDCT_ROW_SSE2_H1(48,192)
FDCT_ROW_SSE2(48)
FDCT_ROW_SSE2_H2(80,192)
FDCT_ROW_SSE2(80)
:
: "r" (in), "r" (tab_frw_01234567_sse2.tab_frw_01234567_sse2), "r" (fdct_r_row_sse2.fdct_r_row_sse2), "i" (SHIFT_FRW_ROW), "r" (out)
);
}
static av_always_inline void fdct_row_mmx2(const int16_t *in, int16_t *out, const int16_t *table)
{
pshufw_m2r(*(in + 4), mm5, 0x1B);
movq_m2r(*(in + 0), mm0);
movq_r2r(mm0, mm1);
paddsw_r2r(mm5, mm0);
psubsw_r2r(mm5, mm1);
movq_r2r(mm0, mm2);
punpckldq_r2r(mm1, mm0);
punpckhdq_r2r(mm1, mm2);
movq_m2r(*(table + 0), mm1);
movq_m2r(*(table + 4), mm3);
movq_m2r(*(table + 8), mm4);
movq_m2r(*(table + 12), mm5);
movq_m2r(*(table + 16), mm6);
movq_m2r(*(table + 20), mm7);
pmaddwd_r2r(mm0, mm1);
pmaddwd_r2r(mm2, mm3);
pmaddwd_r2r(mm0, mm4);
pmaddwd_r2r(mm2, mm5);
pmaddwd_r2r(mm0, mm6);
pmaddwd_r2r(mm2, mm7);
pmaddwd_m2r(*(table + 24), mm0);
pmaddwd_m2r(*(table + 28), mm2);
paddd_r2r(mm1, mm3);
paddd_r2r(mm4, mm5);
paddd_r2r(mm6, mm7);
paddd_r2r(mm0, mm2);
movq_m2r(*fdct_r_row, mm0);
paddd_r2r(mm0, mm3);
paddd_r2r(mm0, mm5);
paddd_r2r(mm0, mm7);
paddd_r2r(mm0, mm2);
psrad_i2r(SHIFT_FRW_ROW, mm3);
psrad_i2r(SHIFT_FRW_ROW, mm5);
psrad_i2r(SHIFT_FRW_ROW, mm7);
psrad_i2r(SHIFT_FRW_ROW, mm2);
packssdw_r2r(mm5, mm3);
packssdw_r2r(mm2, mm7);
movq_r2m(mm3, *(out + 0));
movq_r2m(mm7, *(out + 4));
}
static av_always_inline void fdct_row_mmx(const int16_t *in, int16_t *out, const int16_t *table)
{
//FIXME reorder (I do not have an old MMX-only CPU here to benchmark ...)
movd_m2r(*(in + 6), mm1);
punpcklwd_m2r(*(in + 4), mm1);
movq_r2r(mm1, mm2);
psrlq_i2r(0x20, mm1);
movq_m2r(*(in + 0), mm0);
punpcklwd_r2r(mm2, mm1);
movq_r2r(mm0, mm5);
paddsw_r2r(mm1, mm0);
psubsw_r2r(mm1, mm5);
movq_r2r(mm0, mm2);
punpckldq_r2r(mm5, mm0);
punpckhdq_r2r(mm5, mm2);
movq_m2r(*(table + 0), mm1);
movq_m2r(*(table + 4), mm3);
movq_m2r(*(table + 8), mm4);
movq_m2r(*(table + 12), mm5);
movq_m2r(*(table + 16), mm6);
movq_m2r(*(table + 20), mm7);
pmaddwd_r2r(mm0, mm1);
pmaddwd_r2r(mm2, mm3);
pmaddwd_r2r(mm0, mm4);
pmaddwd_r2r(mm2, mm5);
pmaddwd_r2r(mm0, mm6);
pmaddwd_r2r(mm2, mm7);
pmaddwd_m2r(*(table + 24), mm0);
pmaddwd_m2r(*(table + 28), mm2);
paddd_r2r(mm1, mm3);
paddd_r2r(mm4, mm5);
paddd_r2r(mm6, mm7);
paddd_r2r(mm0, mm2);
movq_m2r(*fdct_r_row, mm0);
paddd_r2r(mm0, mm3);
paddd_r2r(mm0, mm5);
paddd_r2r(mm0, mm7);
paddd_r2r(mm0, mm2);
psrad_i2r(SHIFT_FRW_ROW, mm3);
psrad_i2r(SHIFT_FRW_ROW, mm5);
psrad_i2r(SHIFT_FRW_ROW, mm7);
psrad_i2r(SHIFT_FRW_ROW, mm2);
packssdw_r2r(mm5, mm3);
packssdw_r2r(mm2, mm7);
movq_r2m(mm3, *(out + 0));
movq_r2m(mm7, *(out + 4));
}
void ff_fdct_mmx(int16_t *block)
{
int64_t align_tmp[16] ATTR_ALIGN(8);
int16_t * block1= (int16_t*)align_tmp;
const int16_t *table= tab_frw_01234567;
int i;
fdct_col_mmx(block, block1, 0);
fdct_col_mmx(block, block1, 4);
for(i=8;i>0;i--) {
fdct_row_mmx(block1, block, table);
block1 += 8;
table += 32;
block += 8;
}
}
void ff_fdct_mmx2(int16_t *block)
{
int64_t align_tmp[16] ATTR_ALIGN(8);
int16_t *block1= (int16_t*)align_tmp;
const int16_t *table= tab_frw_01234567;
int i;
fdct_col_mmx(block, block1, 0);
fdct_col_mmx(block, block1, 4);
for(i=8;i>0;i--) {
fdct_row_mmx2(block1, block, table);
block1 += 8;
table += 32;
block += 8;
}
}
void ff_fdct_sse2(int16_t *block)
{
int64_t align_tmp[16] ATTR_ALIGN(16);
int16_t * const block1= (int16_t*)align_tmp;
fdct_col_sse2(block, block1, 0);
fdct_row_sse2(block1, block);
}
@@ -0,0 +1,23 @@
/*
* FFT/MDCT transform with 3DNow! optimizations
* Copyright (c) 2008 Loren Merritt
*
* 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 EMULATE_3DNOWEXT
#include "fft_3dn2.c"
@@ -0,0 +1,173 @@
/*
* FFT/MDCT transform with Extended 3DNow! optimizations
* Copyright (c) 2006-2008 Zuxy MENG Jie, Loren Merritt
*
* 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/x86_cpu.h"
#include "libavcodec/dsputil.h"
DECLARE_ALIGNED_8(static const int, m1m1[2]) = { 1<<31, 1<<31 };
#ifdef EMULATE_3DNOWEXT
#define PSWAPD(s,d)\
"movq "#s","#d"\n"\
"psrlq $32,"#d"\n"\
"punpckldq "#s","#d"\n"
#define ff_fft_calc_3dn2 ff_fft_calc_3dn
#define ff_fft_dispatch_3dn2 ff_fft_dispatch_3dn
#define ff_fft_dispatch_interleave_3dn2 ff_fft_dispatch_interleave_3dn
#define ff_imdct_calc_3dn2 ff_imdct_calc_3dn
#define ff_imdct_half_3dn2 ff_imdct_half_3dn
#else
#define PSWAPD(s,d) "pswapd "#s","#d"\n"
#endif
void ff_fft_dispatch_3dn2(FFTComplex *z, int nbits);
void ff_fft_dispatch_interleave_3dn2(FFTComplex *z, int nbits);
void ff_fft_calc_3dn2(FFTContext *s, FFTComplex *z)
{
int n = 1<<s->nbits;
int i;
ff_fft_dispatch_interleave_3dn2(z, s->nbits);
asm volatile("femms");
if(n <= 8)
for(i=0; i<n; i+=2)
FFSWAP(FFTSample, z[i].im, z[i+1].re);
}
void ff_imdct_half_3dn2(MDCTContext *s, FFTSample *output, const FFTSample *input)
{
x86_reg j, k;
long n = 1 << s->nbits;
long n2 = n >> 1;
long n4 = n >> 2;
long n8 = n >> 3;
const uint16_t *revtab = s->fft.revtab;
const FFTSample *tcos = s->tcos;
const FFTSample *tsin = s->tsin;
const FFTSample *in1, *in2;
FFTComplex *z = (FFTComplex *)output;
/* pre rotation */
in1 = input;
in2 = input + n2 - 1;
#ifdef EMULATE_3DNOWEXT
asm volatile("movd %0, %%mm7" ::"r"(1<<31));
#endif
for(k = 0; k < n4; k++) {
// FIXME a single block is faster, but gcc 2.95 and 3.4.x on 32bit can't compile it
asm volatile(
"movd %0, %%mm0 \n"
"movd %2, %%mm1 \n"
"punpckldq %1, %%mm0 \n"
"punpckldq %3, %%mm1 \n"
"movq %%mm0, %%mm2 \n"
PSWAPD( %%mm1, %%mm3 )
"pfmul %%mm1, %%mm0 \n"
"pfmul %%mm3, %%mm2 \n"
#ifdef EMULATE_3DNOWEXT
"movq %%mm0, %%mm1 \n"
"punpckhdq %%mm2, %%mm0 \n"
"punpckldq %%mm2, %%mm1 \n"
"pxor %%mm7, %%mm0 \n"
"pfadd %%mm1, %%mm0 \n"
#else
"pfpnacc %%mm2, %%mm0 \n"
#endif
::"m"(in2[-2*k]), "m"(in1[2*k]),
"m"(tcos[k]), "m"(tsin[k])
);
asm volatile(
"movq %%mm0, %0 \n\t"
:"=m"(z[revtab[k]])
);
}
ff_fft_dispatch_3dn2(z, s->fft.nbits);
#define CMUL(j,mm0,mm1)\
"movq (%2,"#j",2), %%mm6 \n"\
"movq 8(%2,"#j",2), "#mm0"\n"\
"movq %%mm6, "#mm1"\n"\
"movq "#mm0",%%mm7 \n"\
"pfmul (%3,"#j"), %%mm6 \n"\
"pfmul (%4,"#j"), "#mm0"\n"\
"pfmul (%4,"#j"), "#mm1"\n"\
"pfmul (%3,"#j"), %%mm7 \n"\
"pfsub %%mm6, "#mm0"\n"\
"pfadd %%mm7, "#mm1"\n"
/* post rotation */
j = -n2;
k = n2-8;
asm volatile(
"1: \n"
CMUL(%0, %%mm0, %%mm1)
CMUL(%1, %%mm2, %%mm3)
"movd %%mm0, (%2,%0,2) \n"
"movd %%mm1,12(%2,%1,2) \n"
"movd %%mm2, (%2,%1,2) \n"
"movd %%mm3,12(%2,%0,2) \n"
"psrlq $32, %%mm0 \n"
"psrlq $32, %%mm1 \n"
"psrlq $32, %%mm2 \n"
"psrlq $32, %%mm3 \n"
"movd %%mm0, 8(%2,%0,2) \n"
"movd %%mm1, 4(%2,%1,2) \n"
"movd %%mm2, 8(%2,%1,2) \n"
"movd %%mm3, 4(%2,%0,2) \n"
"sub $8, %1 \n"
"add $8, %0 \n"
"jl 1b \n"
:"+r"(j), "+r"(k)
:"r"(z+n8), "r"(tcos+n8), "r"(tsin+n8)
:"memory"
);
asm volatile("femms");
}
void ff_imdct_calc_3dn2(MDCTContext *s, FFTSample *output, const FFTSample *input)
{
x86_reg j, k;
long n = 1 << s->nbits;
long n4 = n >> 2;
ff_imdct_half_3dn2(s, output+n4, input);
j = -n;
k = n-8;
asm volatile(
"movq %4, %%mm7 \n"
"1: \n"
PSWAPD((%2,%1), %%mm0)
PSWAPD((%3,%0), %%mm1)
"pxor %%mm7, %%mm0 \n"
"movq %%mm1, (%3,%1) \n"
"movq %%mm0, (%2,%0) \n"
"sub $8, %1 \n"
"add $8, %0 \n"
"jl 1b \n"
:"+r"(j), "+r"(k)
:"r"(output+n4), "r"(output+n4*3),
"m"(*m1m1)
);
asm volatile("femms");
}
@@ -0,0 +1,467 @@
;******************************************************************************
;* FFT transform with SSE/3DNow optimizations
;* Copyright (c) 2008 Loren Merritt
;*
;* 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
;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
; These functions are not individually interchangeable with the C versions.
; While C takes arrays of FFTComplex, SSE/3DNow leave intermediate results
; in blocks as conventient to the vector size.
; i.e. {4x real, 4x imaginary, 4x real, ...} (or 2x respectively)
%include "x86inc.asm"
SECTION_RODATA
%define M_SQRT1_2 0.70710678118654752440
ps_root2: times 4 dd M_SQRT1_2
ps_root2mppm: dd -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2
ps_m1p1: dd 1<<31, 0
%assign i 16
%rep 13
cextern ff_cos_ %+ i
%assign i i<<1
%endrep
%ifdef ARCH_X86_64
%define pointer dq
%else
%define pointer dd
%endif
%macro IF0 1+
%endmacro
%macro IF1 1+
%1
%endmacro
section .text align=16
%macro T2_3DN 4 ; z0, z1, mem0, mem1
mova %1, %3
mova %2, %1
pfadd %1, %4
pfsub %2, %4
%endmacro
%macro T4_3DN 6 ; z0, z1, z2, z3, tmp0, tmp1
mova %5, %3
pfsub %3, %4
pfadd %5, %4 ; {t6,t5}
pxor %3, [ps_m1p1 GLOBAL] ; {t8,t7}
mova %6, %1
pswapd %3, %3
pfadd %1, %5 ; {r0,i0}
pfsub %6, %5 ; {r2,i2}
mova %4, %2
pfadd %2, %3 ; {r1,i1}
pfsub %4, %3 ; {r3,i3}
SWAP %3, %6
%endmacro
; in: %1={r0,i0,r1,i1} %2={r2,i2,r3,i3}
; out: %1={r0,r1,r2,r3} %2={i0,i1,i2,i3}
%macro T4_SSE 3
mova %3, %1
shufps %1, %2, 0x64 ; {r0,i0,r3,i2}
shufps %3, %2, 0xce ; {r1,i1,r2,i3}
mova %2, %1
addps %1, %3 ; {t1,t2,t6,t5}
subps %2, %3 ; {t3,t4,t8,t7}
mova %3, %1
shufps %1, %2, 0x44 ; {t1,t2,t3,t4}
shufps %3, %2, 0xbe ; {t6,t5,t7,t8}
mova %2, %1
addps %1, %3 ; {r0,i0,r1,i1}
subps %2, %3 ; {r2,i2,r3,i3}
mova %3, %1
shufps %1, %2, 0x88 ; {r0,r1,r2,r3}
shufps %3, %2, 0xdd ; {i0,i1,i2,i3}
SWAP %2, %3
%endmacro
%macro T8_SSE 6 ; r0,i0,r1,i1,t0,t1
mova %5, %3
shufps %3, %4, 0x44 ; {r4,i4,r6,i6}
shufps %5, %4, 0xee ; {r5,i5,r7,i7}
mova %6, %3
subps %3, %5 ; {r5,i5,r7,i7}
addps %6, %5 ; {t1,t2,t3,t4}
mova %5, %3
shufps %5, %5, 0xb1 ; {i5,r5,i7,r7}
mulps %3, [ps_root2mppm GLOBAL] ; {-r5,i5,r7,-i7}
mulps %5, [ps_root2 GLOBAL]
addps %3, %5 ; {t8,t7,ta,t9}
mova %5, %6
shufps %6, %3, 0x36 ; {t3,t2,t9,t8}
shufps %5, %3, 0x9c ; {t1,t4,t7,ta}
mova %3, %6
addps %6, %5 ; {t1,t2,t9,ta}
subps %3, %5 ; {t6,t5,tc,tb}
mova %5, %6
shufps %6, %3, 0xd8 ; {t1,t9,t5,tb}
shufps %5, %3, 0x8d ; {t2,ta,t6,tc}
mova %3, %1
mova %4, %2
addps %1, %6 ; {r0,r1,r2,r3}
addps %2, %5 ; {i0,i1,i2,i3}
subps %3, %6 ; {r4,r5,r6,r7}
subps %4, %5 ; {i4,i5,i6,i7}
%endmacro
; scheduled for cpu-bound sizes
%macro PASS_SMALL 3 ; (to load m4-m7), wre, wim
IF%1 mova m4, Z(4)
IF%1 mova m5, Z(5)
mova m0, %2 ; wre
mova m2, m4
mova m1, %3 ; wim
mova m3, m5
mulps m2, m0 ; r2*wre
IF%1 mova m6, Z(6)
mulps m3, m1 ; i2*wim
IF%1 mova m7, Z(7)
mulps m4, m1 ; r2*wim
mulps m5, m0 ; i2*wre
addps m2, m3 ; r2*wre + i2*wim
mova m3, m1
mulps m1, m6 ; r3*wim
subps m5, m4 ; i2*wre - r2*wim
mova m4, m0
mulps m3, m7 ; i3*wim
mulps m4, m6 ; r3*wre
mulps m0, m7 ; i3*wre
subps m4, m3 ; r3*wre - i3*wim
mova m3, Z(0)
addps m0, m1 ; i3*wre + r3*wim
mova m1, m4
addps m4, m2 ; t5
subps m1, m2 ; t3
subps m3, m4 ; r2
addps m4, Z(0) ; r0
mova m6, Z(2)
mova Z(4), m3
mova Z(0), m4
mova m3, m5
subps m5, m0 ; t4
mova m4, m6
subps m6, m5 ; r3
addps m5, m4 ; r1
mova Z(6), m6
mova Z(2), m5
mova m2, Z(3)
addps m3, m0 ; t6
subps m2, m1 ; i3
mova m7, Z(1)
addps m1, Z(3) ; i1
mova Z(7), m2
mova Z(3), m1
mova m4, m7
subps m7, m3 ; i2
addps m3, m4 ; i0
mova Z(5), m7
mova Z(1), m3
%endmacro
; scheduled to avoid store->load aliasing
%macro PASS_BIG 1 ; (!interleave)
mova m4, Z(4) ; r2
mova m5, Z(5) ; i2
mova m2, m4
mova m0, [wq] ; wre
mova m3, m5
mova m1, [wq+o1q] ; wim
mulps m2, m0 ; r2*wre
mova m6, Z(6) ; r3
mulps m3, m1 ; i2*wim
mova m7, Z(7) ; i3
mulps m4, m1 ; r2*wim
mulps m5, m0 ; i2*wre
addps m2, m3 ; r2*wre + i2*wim
mova m3, m1
mulps m1, m6 ; r3*wim
subps m5, m4 ; i2*wre - r2*wim
mova m4, m0
mulps m3, m7 ; i3*wim
mulps m4, m6 ; r3*wre
mulps m0, m7 ; i3*wre
subps m4, m3 ; r3*wre - i3*wim
mova m3, Z(0)
addps m0, m1 ; i3*wre + r3*wim
mova m1, m4
addps m4, m2 ; t5
subps m1, m2 ; t3
subps m3, m4 ; r2
addps m4, Z(0) ; r0
mova m6, Z(2)
mova Z(4), m3
mova Z(0), m4
mova m3, m5
subps m5, m0 ; t4
mova m4, m6
subps m6, m5 ; r3
addps m5, m4 ; r1
IF%1 mova Z(6), m6
IF%1 mova Z(2), m5
mova m2, Z(3)
addps m3, m0 ; t6
subps m2, m1 ; i3
mova m7, Z(1)
addps m1, Z(3) ; i1
IF%1 mova Z(7), m2
IF%1 mova Z(3), m1
mova m4, m7
subps m7, m3 ; i2
addps m3, m4 ; i0
IF%1 mova Z(5), m7
IF%1 mova Z(1), m3
%if %1==0
mova m4, m5 ; r1
mova m0, m6 ; r3
unpcklps m5, m1
unpckhps m4, m1
unpcklps m6, m2
unpckhps m0, m2
mova m1, Z(0)
mova m2, Z(4)
mova Z(2), m5
mova Z(3), m4
mova Z(6), m6
mova Z(7), m0
mova m5, m1 ; r0
mova m4, m2 ; r2
unpcklps m1, m3
unpckhps m5, m3
unpcklps m2, m7
unpckhps m4, m7
mova Z(0), m1
mova Z(1), m5
mova Z(4), m2
mova Z(5), m4
%endif
%endmacro
%macro PUNPCK 3
mova %3, %1
punpckldq %1, %2
punpckhdq %3, %2
%endmacro
INIT_XMM
%define Z(x) [r0+mmsize*x]
align 16
fft4_sse:
mova m0, Z(0)
mova m1, Z(1)
T4_SSE m0, m1, m2
mova Z(0), m0
mova Z(1), m1
ret
align 16
fft8_sse:
mova m0, Z(0)
mova m1, Z(1)
T4_SSE m0, m1, m2
mova m2, Z(2)
mova m3, Z(3)
T8_SSE m0, m1, m2, m3, m4, m5
mova Z(0), m0
mova Z(1), m1
mova Z(2), m2
mova Z(3), m3
ret
align 16
fft16_sse:
mova m0, Z(0)
mova m1, Z(1)
T4_SSE m0, m1, m2
mova m2, Z(2)
mova m3, Z(3)
T8_SSE m0, m1, m2, m3, m4, m5
mova m4, Z(4)
mova m5, Z(5)
mova Z(0), m0
mova Z(1), m1
mova Z(2), m2
mova Z(3), m3
T4_SSE m4, m5, m6
mova m6, Z(6)
mova m7, Z(7)
T4_SSE m6, m7, m0
PASS_SMALL 0, [ff_cos_16 GLOBAL], [ff_cos_16+16 GLOBAL]
ret
INIT_MMX
%macro FFT48_3DN 1
align 16
fft4%1:
T2_3DN m0, m1, Z(0), Z(1)
mova m2, Z(2)
mova m3, Z(3)
T4_3DN m0, m1, m2, m3, m4, m5
PUNPCK m0, m1, m4
PUNPCK m2, m3, m5
mova Z(0), m0
mova Z(1), m4
mova Z(2), m2
mova Z(3), m5
ret
align 16
fft8%1:
T2_3DN m0, m1, Z(0), Z(1)
mova m2, Z(2)
mova m3, Z(3)
T4_3DN m0, m1, m2, m3, m4, m5
mova Z(0), m0
mova Z(2), m2
T2_3DN m4, m5, Z(4), Z(5)
T2_3DN m6, m7, Z(6), Z(7)
pswapd m0, m5
pswapd m2, m7
pxor m0, [ps_m1p1 GLOBAL]
pxor m2, [ps_m1p1 GLOBAL]
pfsub m5, m0
pfadd m7, m2
pfmul m5, [ps_root2 GLOBAL]
pfmul m7, [ps_root2 GLOBAL]
T4_3DN m1, m3, m5, m7, m0, m2
mova Z(5), m5
mova Z(7), m7
mova m0, Z(0)
mova m2, Z(2)
T4_3DN m0, m2, m4, m6, m5, m7
PUNPCK m0, m1, m5
PUNPCK m2, m3, m7
mova Z(0), m0
mova Z(1), m5
mova Z(2), m2
mova Z(3), m7
PUNPCK m4, Z(5), m5
PUNPCK m6, Z(7), m7
mova Z(4), m4
mova Z(5), m5
mova Z(6), m6
mova Z(7), m7
ret
%endmacro
FFT48_3DN _3dn2
%macro pswapd 2
%ifidn %1, %2
movd [r0+12], %1
punpckhdq %1, [r0+8]
%else
movq %1, %2
psrlq %1, 32
punpckldq %1, %2
%endif
%endmacro
FFT48_3DN _3dn
%define Z(x) [zq + o1q*(x&6)*((x/6)^1) + o3q*(x/6) + mmsize*(x&1)]
%macro DECL_PASS 2+ ; name, payload
align 16
%1:
DEFINE_ARGS z, w, n, o1, o3
lea o3q, [nq*3]
lea o1q, [nq*8]
shl o3q, 4
.loop:
%2
add zq, mmsize*2
add wq, mmsize
sub nd, mmsize/8
jg .loop
rep ret
%endmacro
INIT_XMM
DECL_PASS pass_sse, PASS_BIG 1
DECL_PASS pass_interleave_sse, PASS_BIG 0
INIT_MMX
%define mulps pfmul
%define addps pfadd
%define subps pfsub
%define unpcklps punpckldq
%define unpckhps punpckhdq
DECL_PASS pass_3dn, PASS_SMALL 1, [wq], [wq+o1q]
DECL_PASS pass_interleave_3dn, PASS_BIG 0
%define pass_3dn2 pass_3dn
%define pass_interleave_3dn2 pass_interleave_3dn
%macro DECL_FFT 2-3 ; nbits, cpu, suffix
%xdefine list_of_fft fft4%2, fft8%2
%if %1==5
%xdefine list_of_fft list_of_fft, fft16%2
%endif
%assign n 1<<%1
%rep 17-%1
%assign n2 n/2
%assign n4 n/4
%xdefine list_of_fft list_of_fft, fft %+ n %+ %3%2
align 16
fft %+ n %+ %3%2:
call fft %+ n2 %+ %2
add r0, n*4 - (n&(-2<<%1))
call fft %+ n4 %+ %2
add r0, n*2 - (n2&(-2<<%1))
call fft %+ n4 %+ %2
sub r0, n*6 + (n2&(-2<<%1))
lea r1, [ff_cos_ %+ n GLOBAL]
mov r2d, n4/2
jmp pass%3%2
%assign n n*2
%endrep
%undef n
align 8
dispatch_tab%3%2: pointer list_of_fft
; On x86_32, this function does the register saving and restoring for all of fft.
; The others pass args in registers and don't spill anything.
cglobal ff_fft_dispatch%3%2, 2,5,0, z, nbits
lea r2, [dispatch_tab%3%2 GLOBAL]
mov r2, [r2 + (nbitsq-2)*gprsize]
call r2
RET
%endmacro ; DECL_FFT
DECL_FFT 5, _sse
DECL_FFT 5, _sse, _interleave
DECL_FFT 4, _3dn
DECL_FFT 4, _3dn, _interleave
DECL_FFT 4, _3dn2
DECL_FFT 4, _3dn2, _interleave
@@ -0,0 +1,202 @@
/*
* FFT/MDCT transform with SSE optimizations
* Copyright (c) 2008 Loren Merritt
*
* 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/x86_cpu.h"
#include "libavcodec/dsputil.h"
static const int m1m1m1m1[4] __attribute__((aligned(16))) =
{ 1 << 31, 1 << 31, 1 << 31, 1 << 31 };
void ff_fft_dispatch_sse(FFTComplex *z, int nbits);
void ff_fft_dispatch_interleave_sse(FFTComplex *z, int nbits);
void ff_fft_calc_sse(FFTContext *s, FFTComplex *z)
{
int n = 1 << s->nbits;
ff_fft_dispatch_interleave_sse(z, s->nbits);
if(n <= 16) {
x86_reg i = -8*n;
asm volatile(
"1: \n"
"movaps (%0,%1), %%xmm0 \n"
"movaps %%xmm0, %%xmm1 \n"
"unpcklps 16(%0,%1), %%xmm0 \n"
"unpckhps 16(%0,%1), %%xmm1 \n"
"movaps %%xmm0, (%0,%1) \n"
"movaps %%xmm1, 16(%0,%1) \n"
"add $32, %0 \n"
"jl 1b \n"
:"+r"(i)
:"r"(z+n)
:"memory"
);
}
}
void ff_fft_permute_sse(FFTContext *s, FFTComplex *z)
{
int n = 1 << s->nbits;
int i;
for(i=0; i<n; i+=2) {
asm volatile(
"movaps %2, %%xmm0 \n"
"movlps %%xmm0, %0 \n"
"movhps %%xmm0, %1 \n"
:"=m"(s->tmp_buf[s->revtab[i]]),
"=m"(s->tmp_buf[s->revtab[i+1]])
:"m"(z[i])
);
}
memcpy(z, s->tmp_buf, n*sizeof(FFTComplex));
}
void ff_imdct_half_sse(MDCTContext *s, FFTSample *output, const FFTSample *input)
{
av_unused x86_reg i, j, k, l;
long n = 1 << s->nbits;
long n2 = n >> 1;
long n4 = n >> 2;
long n8 = n >> 3;
const uint16_t *revtab = s->fft.revtab + n8;
const FFTSample *tcos = s->tcos;
const FFTSample *tsin = s->tsin;
FFTComplex *z = (FFTComplex *)output;
/* pre rotation */
for(k=n8-2; k>=0; k-=2) {
asm volatile(
"movaps (%2,%1,2), %%xmm0 \n" // { z[k].re, z[k].im, z[k+1].re, z[k+1].im }
"movaps -16(%2,%0,2), %%xmm1 \n" // { z[-k-2].re, z[-k-2].im, z[-k-1].re, z[-k-1].im }
"movaps %%xmm0, %%xmm2 \n"
"shufps $0x88, %%xmm1, %%xmm0 \n" // { z[k].re, z[k+1].re, z[-k-2].re, z[-k-1].re }
"shufps $0x77, %%xmm2, %%xmm1 \n" // { z[-k-1].im, z[-k-2].im, z[k+1].im, z[k].im }
"movlps (%3,%1), %%xmm4 \n"
"movlps (%4,%1), %%xmm5 \n"
"movhps -8(%3,%0), %%xmm4 \n" // { cos[k], cos[k+1], cos[-k-2], cos[-k-1] }
"movhps -8(%4,%0), %%xmm5 \n" // { sin[k], sin[k+1], sin[-k-2], sin[-k-1] }
"movaps %%xmm0, %%xmm2 \n"
"movaps %%xmm1, %%xmm3 \n"
"mulps %%xmm5, %%xmm0 \n" // re*sin
"mulps %%xmm4, %%xmm1 \n" // im*cos
"mulps %%xmm4, %%xmm2 \n" // re*cos
"mulps %%xmm5, %%xmm3 \n" // im*sin
"subps %%xmm0, %%xmm1 \n" // -> re
"addps %%xmm3, %%xmm2 \n" // -> im
"movaps %%xmm1, %%xmm0 \n"
"unpcklps %%xmm2, %%xmm1 \n" // { z[k], z[k+1] }
"unpckhps %%xmm2, %%xmm0 \n" // { z[-k-2], z[-k-1] }
::"r"(-4*k), "r"(4*k),
"r"(input+n4), "r"(tcos+n8), "r"(tsin+n8)
);
#ifdef ARCH_X86_64
// if we have enough regs, don't let gcc make the luts latency-bound
// but if not, latency is faster than spilling
asm("movlps %%xmm0, %0 \n"
"movhps %%xmm0, %1 \n"
"movlps %%xmm1, %2 \n"
"movhps %%xmm1, %3 \n"
:"=m"(z[revtab[-k-2]]),
"=m"(z[revtab[-k-1]]),
"=m"(z[revtab[ k ]]),
"=m"(z[revtab[ k+1]])
);
#else
asm("movlps %%xmm0, %0" :"=m"(z[revtab[-k-2]]));
asm("movhps %%xmm0, %0" :"=m"(z[revtab[-k-1]]));
asm("movlps %%xmm1, %0" :"=m"(z[revtab[ k ]]));
asm("movhps %%xmm1, %0" :"=m"(z[revtab[ k+1]]));
#endif
}
ff_fft_dispatch_sse(z, s->fft.nbits);
/* post rotation + reinterleave + reorder */
#define CMUL(j,xmm0,xmm1)\
"movaps (%2,"#j",2), %%xmm6 \n"\
"movaps 16(%2,"#j",2), "#xmm0"\n"\
"movaps %%xmm6, "#xmm1"\n"\
"movaps "#xmm0",%%xmm7 \n"\
"mulps (%3,"#j"), %%xmm6 \n"\
"mulps (%4,"#j"), "#xmm0"\n"\
"mulps (%4,"#j"), "#xmm1"\n"\
"mulps (%3,"#j"), %%xmm7 \n"\
"subps %%xmm6, "#xmm0"\n"\
"addps %%xmm7, "#xmm1"\n"
j = -n2;
k = n2-16;
asm volatile(
"1: \n"
CMUL(%0, %%xmm0, %%xmm1)
CMUL(%1, %%xmm4, %%xmm5)
"shufps $0x1b, %%xmm1, %%xmm1 \n"
"shufps $0x1b, %%xmm5, %%xmm5 \n"
"movaps %%xmm4, %%xmm6 \n"
"unpckhps %%xmm1, %%xmm4 \n"
"unpcklps %%xmm1, %%xmm6 \n"
"movaps %%xmm0, %%xmm2 \n"
"unpcklps %%xmm5, %%xmm0 \n"
"unpckhps %%xmm5, %%xmm2 \n"
"movaps %%xmm6, (%2,%1,2) \n"
"movaps %%xmm4, 16(%2,%1,2) \n"
"movaps %%xmm0, (%2,%0,2) \n"
"movaps %%xmm2, 16(%2,%0,2) \n"
"sub $16, %1 \n"
"add $16, %0 \n"
"jl 1b \n"
:"+&r"(j), "+&r"(k)
:"r"(z+n8), "r"(tcos+n8), "r"(tsin+n8)
:"memory"
);
}
void ff_imdct_calc_sse(MDCTContext *s, FFTSample *output, const FFTSample *input)
{
x86_reg j, k;
long n = 1 << s->nbits;
long n4 = n >> 2;
ff_imdct_half_sse(s, output+n4, input);
j = -n;
k = n-16;
asm volatile(
"movaps %4, %%xmm7 \n"
"1: \n"
"movaps (%2,%1), %%xmm0 \n"
"movaps (%3,%0), %%xmm1 \n"
"shufps $0x1b, %%xmm0, %%xmm0 \n"
"shufps $0x1b, %%xmm1, %%xmm1 \n"
"xorps %%xmm7, %%xmm0 \n"
"movaps %%xmm1, (%3,%1) \n"
"movaps %%xmm0, (%2,%0) \n"
"sub $16, %1 \n"
"add $16, %0 \n"
"jl 1b \n"
:"+r"(j), "+r"(k)
:"r"(output+n4), "r"(output+n4*3),
"m"(*m1m1m1m1)
);
}
@@ -0,0 +1,139 @@
/*
* MMX optimized FLAC DSP utils
* Copyright (c) 2007 Loren Merritt
*
* 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/x86_cpu.h"
#include "dsputil_mmx.h"
static void apply_welch_window_sse2(const int32_t *data, int len, double *w_data)
{
double c = 2.0 / (len-1.0);
int n2 = len>>1;
x86_reg i = -n2*sizeof(int32_t);
x86_reg j = n2*sizeof(int32_t);
asm volatile(
"movsd %0, %%xmm7 \n\t"
"movapd "MANGLE(ff_pd_1)", %%xmm6 \n\t"
"movapd "MANGLE(ff_pd_2)", %%xmm5 \n\t"
"movlhps %%xmm7, %%xmm7 \n\t"
"subpd %%xmm5, %%xmm7 \n\t"
"addsd %%xmm6, %%xmm7 \n\t"
::"m"(c)
);
#define WELCH(MOVPD, offset)\
asm volatile(\
"1: \n\t"\
"movapd %%xmm7, %%xmm1 \n\t"\
"mulpd %%xmm1, %%xmm1 \n\t"\
"movapd %%xmm6, %%xmm0 \n\t"\
"subpd %%xmm1, %%xmm0 \n\t"\
"pshufd $0x4e, %%xmm0, %%xmm1 \n\t"\
"cvtpi2pd (%3,%0), %%xmm2 \n\t"\
"cvtpi2pd "#offset"*4(%3,%1), %%xmm3 \n\t"\
"mulpd %%xmm0, %%xmm2 \n\t"\
"mulpd %%xmm1, %%xmm3 \n\t"\
"movapd %%xmm2, (%2,%0,2) \n\t"\
MOVPD" %%xmm3, "#offset"*8(%2,%1,2) \n\t"\
"subpd %%xmm5, %%xmm7 \n\t"\
"sub $8, %1 \n\t"\
"add $8, %0 \n\t"\
"jl 1b \n\t"\
:"+&r"(i), "+&r"(j)\
:"r"(w_data+n2), "r"(data+n2)\
);
if(len&1)
WELCH("movupd", -1)
else
WELCH("movapd", -2)
#undef WELCH
}
void ff_flac_compute_autocorr_sse2(const int32_t *data, int len, int lag,
double *autoc)
{
double tmp[len + lag + 2];
double *data1 = tmp + lag;
int j;
if((x86_reg)data1 & 15)
data1++;
apply_welch_window_sse2(data, len, data1);
for(j=0; j<lag; j++)
data1[j-lag]= 0.0;
data1[len] = 0.0;
for(j=0; j<lag; j+=2){
x86_reg i = -len*sizeof(double);
if(j == lag-2) {
asm volatile(
"movsd "MANGLE(ff_pd_1)", %%xmm0 \n\t"
"movsd "MANGLE(ff_pd_1)", %%xmm1 \n\t"
"movsd "MANGLE(ff_pd_1)", %%xmm2 \n\t"
"1: \n\t"
"movapd (%4,%0), %%xmm3 \n\t"
"movupd -8(%5,%0), %%xmm4 \n\t"
"movapd (%5,%0), %%xmm5 \n\t"
"mulpd %%xmm3, %%xmm4 \n\t"
"mulpd %%xmm3, %%xmm5 \n\t"
"mulpd -16(%5,%0), %%xmm3 \n\t"
"addpd %%xmm4, %%xmm1 \n\t"
"addpd %%xmm5, %%xmm0 \n\t"
"addpd %%xmm3, %%xmm2 \n\t"
"add $16, %0 \n\t"
"jl 1b \n\t"
"movhlps %%xmm0, %%xmm3 \n\t"
"movhlps %%xmm1, %%xmm4 \n\t"
"movhlps %%xmm2, %%xmm5 \n\t"
"addsd %%xmm3, %%xmm0 \n\t"
"addsd %%xmm4, %%xmm1 \n\t"
"addsd %%xmm5, %%xmm2 \n\t"
"movsd %%xmm0, %1 \n\t"
"movsd %%xmm1, %2 \n\t"
"movsd %%xmm2, %3 \n\t"
:"+&r"(i), "=m"(autoc[j]), "=m"(autoc[j+1]), "=m"(autoc[j+2])
:"r"(data1+len), "r"(data1+len-j)
);
} else {
asm volatile(
"movsd "MANGLE(ff_pd_1)", %%xmm0 \n\t"
"movsd "MANGLE(ff_pd_1)", %%xmm1 \n\t"
"1: \n\t"
"movapd (%3,%0), %%xmm3 \n\t"
"movupd -8(%4,%0), %%xmm4 \n\t"
"mulpd %%xmm3, %%xmm4 \n\t"
"mulpd (%4,%0), %%xmm3 \n\t"
"addpd %%xmm4, %%xmm1 \n\t"
"addpd %%xmm3, %%xmm0 \n\t"
"add $16, %0 \n\t"
"jl 1b \n\t"
"movhlps %%xmm0, %%xmm3 \n\t"
"movhlps %%xmm1, %%xmm4 \n\t"
"addsd %%xmm3, %%xmm0 \n\t"
"addsd %%xmm4, %%xmm1 \n\t"
"movsd %%xmm0, %1 \n\t"
"movsd %%xmm1, %2 \n\t"
:"+&r"(i), "=m"(autoc[j]), "=m"(autoc[j+1])
:"r"(data1+len), "r"(data1+len-j)
);
}
}
}
@@ -0,0 +1,155 @@
/*
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <[email protected]>
*
* 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
*/
/**
* @file h264_i386.h
* H.264 / AVC / MPEG4 part10 codec.
* non-MMX i386-specific optimizations for H.264
* @author Michael Niedermayer <[email protected]>
*/
#ifndef FFMPEG_H264_I386_H
#define FFMPEG_H264_I386_H
#include "libavcodec/cabac.h"
//FIXME use some macros to avoid duplicating get_cabac (cannot be done yet
//as that would make optimization work hard)
#if defined(ARCH_X86) && defined(HAVE_7REGS) && \
defined(HAVE_EBX_AVAILABLE) && \
!defined(BROKEN_RELOCATIONS)
static int decode_significance_x86(CABACContext *c, int max_coeff,
uint8_t *significant_coeff_ctx_base,
int *index){
void *end= significant_coeff_ctx_base + max_coeff - 1;
int minusstart= -(int)significant_coeff_ctx_base;
int minusindex= 4-(int)index;
int coeff_count;
asm volatile(
"movl "RANGE "(%3), %%esi \n\t"
"movl "LOW "(%3), %%ebx \n\t"
"2: \n\t"
BRANCHLESS_GET_CABAC("%%edx", "%3", "(%1)", "%%ebx",
"%%bx", "%%esi", "%%eax", "%%al")
"test $1, %%edx \n\t"
" jz 3f \n\t"
BRANCHLESS_GET_CABAC("%%edx", "%3", "61(%1)", "%%ebx",
"%%bx", "%%esi", "%%eax", "%%al")
"mov %2, %%"REG_a" \n\t"
"movl %4, %%ecx \n\t"
"add %1, %%"REG_c" \n\t"
"movl %%ecx, (%%"REG_a") \n\t"
"test $1, %%edx \n\t"
" jnz 4f \n\t"
"add $4, %%"REG_a" \n\t"
"mov %%"REG_a", %2 \n\t"
"3: \n\t"
"add $1, %1 \n\t"
"cmp %5, %1 \n\t"
" jb 2b \n\t"
"mov %2, %%"REG_a" \n\t"
"movl %4, %%ecx \n\t"
"add %1, %%"REG_c" \n\t"
"movl %%ecx, (%%"REG_a") \n\t"
"4: \n\t"
"add %6, %%eax \n\t"
"shr $2, %%eax \n\t"
"movl %%esi, "RANGE "(%3) \n\t"
"movl %%ebx, "LOW "(%3) \n\t"
:"=&a"(coeff_count), "+r"(significant_coeff_ctx_base), "+m"(index)
:"r"(c), "m"(minusstart), "m"(end), "m"(minusindex)
: "%"REG_c, "%ebx", "%edx", "%esi", "memory"
);
return coeff_count;
}
static int decode_significance_8x8_x86(CABACContext *c,
uint8_t *significant_coeff_ctx_base,
int *index, const uint8_t *sig_off){
int minusindex= 4-(int)index;
int coeff_count;
x86_reg last=0;
asm volatile(
"movl "RANGE "(%3), %%esi \n\t"
"movl "LOW "(%3), %%ebx \n\t"
"mov %1, %%"REG_D" \n\t"
"2: \n\t"
"mov %6, %%"REG_a" \n\t"
"movzbl (%%"REG_a", %%"REG_D"), %%edi \n\t"
"add %5, %%"REG_D" \n\t"
BRANCHLESS_GET_CABAC("%%edx", "%3", "(%%"REG_D")", "%%ebx",
"%%bx", "%%esi", "%%eax", "%%al")
"mov %1, %%edi \n\t"
"test $1, %%edx \n\t"
" jz 3f \n\t"
"movzbl "MANGLE(last_coeff_flag_offset_8x8)"(%%edi), %%edi\n\t"
"add %5, %%"REG_D" \n\t"
BRANCHLESS_GET_CABAC("%%edx", "%3", "15(%%"REG_D")", "%%ebx",
"%%bx", "%%esi", "%%eax", "%%al")
"mov %2, %%"REG_a" \n\t"
"mov %1, %%edi \n\t"
"movl %%edi, (%%"REG_a") \n\t"
"test $1, %%edx \n\t"
" jnz 4f \n\t"
"add $4, %%"REG_a" \n\t"
"mov %%"REG_a", %2 \n\t"
"3: \n\t"
"addl $1, %%edi \n\t"
"mov %%edi, %1 \n\t"
"cmpl $63, %%edi \n\t"
" jb 2b \n\t"
"mov %2, %%"REG_a" \n\t"
"movl %%edi, (%%"REG_a") \n\t"
"4: \n\t"
"addl %4, %%eax \n\t"
"shr $2, %%eax \n\t"
"movl %%esi, "RANGE "(%3) \n\t"
"movl %%ebx, "LOW "(%3) \n\t"
:"=&a"(coeff_count),"+m"(last), "+m"(index)
:"r"(c), "m"(minusindex), "m"(significant_coeff_ctx_base), "m"(sig_off)
: "%"REG_c, "%ebx", "%edx", "%esi", "%"REG_D, "memory"
);
return coeff_count;
}
#endif /* defined(ARCH_X86) && defined(HAVE_7REGS) && */
/* defined(HAVE_EBX_AVAILABLE) && !defined(BROKEN_RELOCATIONS) */
#endif /* FFMPEG_H264_I386_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,597 @@
/*
* idct_mmx.c
* Copyright (C) 1999-2001 Aaron Holtzman <[email protected]>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
*
* mpeg2dec is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpeg2dec 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with mpeg2dec; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/common.h"
#include "libavcodec/dsputil.h"
#include "mmx.h"
#define ATTR_ALIGN(align) __attribute__ ((__aligned__ (align)))
#define ROW_SHIFT 11
#define COL_SHIFT 6
#define round(bias) ((int)(((bias)+0.5) * (1<<ROW_SHIFT)))
#define rounder(bias) {round (bias), round (bias)}
#if 0
/* C row IDCT - it is just here to document the MMXEXT and MMX versions */
static inline void idct_row (int16_t * row, int offset,
int16_t * table, int32_t * rounder)
{
int C1, C2, C3, C4, C5, C6, C7;
int a0, a1, a2, a3, b0, b1, b2, b3;
row += offset;
C1 = table[1];
C2 = table[2];
C3 = table[3];
C4 = table[4];
C5 = table[5];
C6 = table[6];
C7 = table[7];
a0 = C4*row[0] + C2*row[2] + C4*row[4] + C6*row[6] + *rounder;
a1 = C4*row[0] + C6*row[2] - C4*row[4] - C2*row[6] + *rounder;
a2 = C4*row[0] - C6*row[2] - C4*row[4] + C2*row[6] + *rounder;
a3 = C4*row[0] - C2*row[2] + C4*row[4] - C6*row[6] + *rounder;
b0 = C1*row[1] + C3*row[3] + C5*row[5] + C7*row[7];
b1 = C3*row[1] - C7*row[3] - C1*row[5] - C5*row[7];
b2 = C5*row[1] - C1*row[3] + C7*row[5] + C3*row[7];
b3 = C7*row[1] - C5*row[3] + C3*row[5] - C1*row[7];
row[0] = (a0 + b0) >> ROW_SHIFT;
row[1] = (a1 + b1) >> ROW_SHIFT;
row[2] = (a2 + b2) >> ROW_SHIFT;
row[3] = (a3 + b3) >> ROW_SHIFT;
row[4] = (a3 - b3) >> ROW_SHIFT;
row[5] = (a2 - b2) >> ROW_SHIFT;
row[6] = (a1 - b1) >> ROW_SHIFT;
row[7] = (a0 - b0) >> ROW_SHIFT;
}
#endif
/* MMXEXT row IDCT */
#define mmxext_table(c1,c2,c3,c4,c5,c6,c7) { c4, c2, -c4, -c2, \
c4, c6, c4, c6, \
c1, c3, -c1, -c5, \
c5, c7, c3, -c7, \
c4, -c6, c4, -c6, \
-c4, c2, c4, -c2, \
c5, -c1, c3, -c1, \
c7, c3, c7, -c5 }
static inline void mmxext_row_head (int16_t * row, int offset, const int16_t * table)
{
movq_m2r (*(row+offset), mm2); /* mm2 = x6 x4 x2 x0 */
movq_m2r (*(row+offset+4), mm5); /* mm5 = x7 x5 x3 x1 */
movq_r2r (mm2, mm0); /* mm0 = x6 x4 x2 x0 */
movq_m2r (*table, mm3); /* mm3 = -C2 -C4 C2 C4 */
movq_r2r (mm5, mm6); /* mm6 = x7 x5 x3 x1 */
movq_m2r (*(table+4), mm4); /* mm4 = C6 C4 C6 C4 */
pmaddwd_r2r (mm0, mm3); /* mm3 = -C4*x4-C2*x6 C4*x0+C2*x2 */
pshufw_r2r (mm2, mm2, 0x4e); /* mm2 = x2 x0 x6 x4 */
}
static inline void mmxext_row (const int16_t * table, const int32_t * rounder)
{
movq_m2r (*(table+8), mm1); /* mm1 = -C5 -C1 C3 C1 */
pmaddwd_r2r (mm2, mm4); /* mm4 = C4*x0+C6*x2 C4*x4+C6*x6 */
pmaddwd_m2r (*(table+16), mm0); /* mm0 = C4*x4-C6*x6 C4*x0-C6*x2 */
pshufw_r2r (mm6, mm6, 0x4e); /* mm6 = x3 x1 x7 x5 */
movq_m2r (*(table+12), mm7); /* mm7 = -C7 C3 C7 C5 */
pmaddwd_r2r (mm5, mm1); /* mm1 = -C1*x5-C5*x7 C1*x1+C3*x3 */
paddd_m2r (*rounder, mm3); /* mm3 += rounder */
pmaddwd_r2r (mm6, mm7); /* mm7 = C3*x1-C7*x3 C5*x5+C7*x7 */
pmaddwd_m2r (*(table+20), mm2); /* mm2 = C4*x0-C2*x2 -C4*x4+C2*x6 */
paddd_r2r (mm4, mm3); /* mm3 = a1 a0 + rounder */
pmaddwd_m2r (*(table+24), mm5); /* mm5 = C3*x5-C1*x7 C5*x1-C1*x3 */
movq_r2r (mm3, mm4); /* mm4 = a1 a0 + rounder */
pmaddwd_m2r (*(table+28), mm6); /* mm6 = C7*x1-C5*x3 C7*x5+C3*x7 */
paddd_r2r (mm7, mm1); /* mm1 = b1 b0 */
paddd_m2r (*rounder, mm0); /* mm0 += rounder */
psubd_r2r (mm1, mm3); /* mm3 = a1-b1 a0-b0 + rounder */
psrad_i2r (ROW_SHIFT, mm3); /* mm3 = y6 y7 */
paddd_r2r (mm4, mm1); /* mm1 = a1+b1 a0+b0 + rounder */
paddd_r2r (mm2, mm0); /* mm0 = a3 a2 + rounder */
psrad_i2r (ROW_SHIFT, mm1); /* mm1 = y1 y0 */
paddd_r2r (mm6, mm5); /* mm5 = b3 b2 */
movq_r2r (mm0, mm4); /* mm4 = a3 a2 + rounder */
paddd_r2r (mm5, mm0); /* mm0 = a3+b3 a2+b2 + rounder */
psubd_r2r (mm5, mm4); /* mm4 = a3-b3 a2-b2 + rounder */
}
static inline void mmxext_row_tail (int16_t * row, int store)
{
psrad_i2r (ROW_SHIFT, mm0); /* mm0 = y3 y2 */
psrad_i2r (ROW_SHIFT, mm4); /* mm4 = y4 y5 */
packssdw_r2r (mm0, mm1); /* mm1 = y3 y2 y1 y0 */
packssdw_r2r (mm3, mm4); /* mm4 = y6 y7 y4 y5 */
movq_r2m (mm1, *(row+store)); /* save y3 y2 y1 y0 */
pshufw_r2r (mm4, mm4, 0xb1); /* mm4 = y7 y6 y5 y4 */
/* slot */
movq_r2m (mm4, *(row+store+4)); /* save y7 y6 y5 y4 */
}
static inline void mmxext_row_mid (int16_t * row, int store,
int offset, const int16_t * table)
{
movq_m2r (*(row+offset), mm2); /* mm2 = x6 x4 x2 x0 */
psrad_i2r (ROW_SHIFT, mm0); /* mm0 = y3 y2 */
movq_m2r (*(row+offset+4), mm5); /* mm5 = x7 x5 x3 x1 */
psrad_i2r (ROW_SHIFT, mm4); /* mm4 = y4 y5 */
packssdw_r2r (mm0, mm1); /* mm1 = y3 y2 y1 y0 */
movq_r2r (mm5, mm6); /* mm6 = x7 x5 x3 x1 */
packssdw_r2r (mm3, mm4); /* mm4 = y6 y7 y4 y5 */
movq_r2r (mm2, mm0); /* mm0 = x6 x4 x2 x0 */
movq_r2m (mm1, *(row+store)); /* save y3 y2 y1 y0 */
pshufw_r2r (mm4, mm4, 0xb1); /* mm4 = y7 y6 y5 y4 */
movq_m2r (*table, mm3); /* mm3 = -C2 -C4 C2 C4 */
movq_r2m (mm4, *(row+store+4)); /* save y7 y6 y5 y4 */
pmaddwd_r2r (mm0, mm3); /* mm3 = -C4*x4-C2*x6 C4*x0+C2*x2 */
movq_m2r (*(table+4), mm4); /* mm4 = C6 C4 C6 C4 */
pshufw_r2r (mm2, mm2, 0x4e); /* mm2 = x2 x0 x6 x4 */
}
/* MMX row IDCT */
#define mmx_table(c1,c2,c3,c4,c5,c6,c7) { c4, c2, c4, c6, \
c4, c6, -c4, -c2, \
c1, c3, c3, -c7, \
c5, c7, -c1, -c5, \
c4, -c6, c4, -c2, \
-c4, c2, c4, -c6, \
c5, -c1, c7, -c5, \
c7, c3, c3, -c1 }
static inline void mmx_row_head (int16_t * row, int offset, const int16_t * table)
{
movq_m2r (*(row+offset), mm2); /* mm2 = x6 x4 x2 x0 */
movq_m2r (*(row+offset+4), mm5); /* mm5 = x7 x5 x3 x1 */
movq_r2r (mm2, mm0); /* mm0 = x6 x4 x2 x0 */
movq_m2r (*table, mm3); /* mm3 = C6 C4 C2 C4 */
movq_r2r (mm5, mm6); /* mm6 = x7 x5 x3 x1 */
punpckldq_r2r (mm0, mm0); /* mm0 = x2 x0 x2 x0 */
movq_m2r (*(table+4), mm4); /* mm4 = -C2 -C4 C6 C4 */
pmaddwd_r2r (mm0, mm3); /* mm3 = C4*x0+C6*x2 C4*x0+C2*x2 */
movq_m2r (*(table+8), mm1); /* mm1 = -C7 C3 C3 C1 */
punpckhdq_r2r (mm2, mm2); /* mm2 = x6 x4 x6 x4 */
}
static inline void mmx_row (const int16_t * table, const int32_t * rounder)
{
pmaddwd_r2r (mm2, mm4); /* mm4 = -C4*x4-C2*x6 C4*x4+C6*x6 */
punpckldq_r2r (mm5, mm5); /* mm5 = x3 x1 x3 x1 */
pmaddwd_m2r (*(table+16), mm0); /* mm0 = C4*x0-C2*x2 C4*x0-C6*x2 */
punpckhdq_r2r (mm6, mm6); /* mm6 = x7 x5 x7 x5 */
movq_m2r (*(table+12), mm7); /* mm7 = -C5 -C1 C7 C5 */
pmaddwd_r2r (mm5, mm1); /* mm1 = C3*x1-C7*x3 C1*x1+C3*x3 */
paddd_m2r (*rounder, mm3); /* mm3 += rounder */
pmaddwd_r2r (mm6, mm7); /* mm7 = -C1*x5-C5*x7 C5*x5+C7*x7 */
pmaddwd_m2r (*(table+20), mm2); /* mm2 = C4*x4-C6*x6 -C4*x4+C2*x6 */
paddd_r2r (mm4, mm3); /* mm3 = a1 a0 + rounder */
pmaddwd_m2r (*(table+24), mm5); /* mm5 = C7*x1-C5*x3 C5*x1-C1*x3 */
movq_r2r (mm3, mm4); /* mm4 = a1 a0 + rounder */
pmaddwd_m2r (*(table+28), mm6); /* mm6 = C3*x5-C1*x7 C7*x5+C3*x7 */
paddd_r2r (mm7, mm1); /* mm1 = b1 b0 */
paddd_m2r (*rounder, mm0); /* mm0 += rounder */
psubd_r2r (mm1, mm3); /* mm3 = a1-b1 a0-b0 + rounder */
psrad_i2r (ROW_SHIFT, mm3); /* mm3 = y6 y7 */
paddd_r2r (mm4, mm1); /* mm1 = a1+b1 a0+b0 + rounder */
paddd_r2r (mm2, mm0); /* mm0 = a3 a2 + rounder */
psrad_i2r (ROW_SHIFT, mm1); /* mm1 = y1 y0 */
paddd_r2r (mm6, mm5); /* mm5 = b3 b2 */
movq_r2r (mm0, mm7); /* mm7 = a3 a2 + rounder */
paddd_r2r (mm5, mm0); /* mm0 = a3+b3 a2+b2 + rounder */
psubd_r2r (mm5, mm7); /* mm7 = a3-b3 a2-b2 + rounder */
}
static inline void mmx_row_tail (int16_t * row, int store)
{
psrad_i2r (ROW_SHIFT, mm0); /* mm0 = y3 y2 */
psrad_i2r (ROW_SHIFT, mm7); /* mm7 = y4 y5 */
packssdw_r2r (mm0, mm1); /* mm1 = y3 y2 y1 y0 */
packssdw_r2r (mm3, mm7); /* mm7 = y6 y7 y4 y5 */
movq_r2m (mm1, *(row+store)); /* save y3 y2 y1 y0 */
movq_r2r (mm7, mm4); /* mm4 = y6 y7 y4 y5 */
pslld_i2r (16, mm7); /* mm7 = y7 0 y5 0 */
psrld_i2r (16, mm4); /* mm4 = 0 y6 0 y4 */
por_r2r (mm4, mm7); /* mm7 = y7 y6 y5 y4 */
/* slot */
movq_r2m (mm7, *(row+store+4)); /* save y7 y6 y5 y4 */
}
static inline void mmx_row_mid (int16_t * row, int store,
int offset, const int16_t * table)
{
movq_m2r (*(row+offset), mm2); /* mm2 = x6 x4 x2 x0 */
psrad_i2r (ROW_SHIFT, mm0); /* mm0 = y3 y2 */
movq_m2r (*(row+offset+4), mm5); /* mm5 = x7 x5 x3 x1 */
psrad_i2r (ROW_SHIFT, mm7); /* mm7 = y4 y5 */
packssdw_r2r (mm0, mm1); /* mm1 = y3 y2 y1 y0 */
movq_r2r (mm5, mm6); /* mm6 = x7 x5 x3 x1 */
packssdw_r2r (mm3, mm7); /* mm7 = y6 y7 y4 y5 */
movq_r2r (mm2, mm0); /* mm0 = x6 x4 x2 x0 */
movq_r2m (mm1, *(row+store)); /* save y3 y2 y1 y0 */
movq_r2r (mm7, mm1); /* mm1 = y6 y7 y4 y5 */
punpckldq_r2r (mm0, mm0); /* mm0 = x2 x0 x2 x0 */
psrld_i2r (16, mm7); /* mm7 = 0 y6 0 y4 */
movq_m2r (*table, mm3); /* mm3 = C6 C4 C2 C4 */
pslld_i2r (16, mm1); /* mm1 = y7 0 y5 0 */
movq_m2r (*(table+4), mm4); /* mm4 = -C2 -C4 C6 C4 */
por_r2r (mm1, mm7); /* mm7 = y7 y6 y5 y4 */
movq_m2r (*(table+8), mm1); /* mm1 = -C7 C3 C3 C1 */
punpckhdq_r2r (mm2, mm2); /* mm2 = x6 x4 x6 x4 */
movq_r2m (mm7, *(row+store+4)); /* save y7 y6 y5 y4 */
pmaddwd_r2r (mm0, mm3); /* mm3 = C4*x0+C6*x2 C4*x0+C2*x2 */
}
#if 0
/* C column IDCT - it is just here to document the MMXEXT and MMX versions */
static inline void idct_col (int16_t * col, int offset)
{
/* multiplication - as implemented on mmx */
#define F(c,x) (((c) * (x)) >> 16)
/* saturation - it helps us handle torture test cases */
#define S(x) (((x)>32767) ? 32767 : ((x)<-32768) ? -32768 : (x))
int16_t x0, x1, x2, x3, x4, x5, x6, x7;
int16_t y0, y1, y2, y3, y4, y5, y6, y7;
int16_t a0, a1, a2, a3, b0, b1, b2, b3;
int16_t u04, v04, u26, v26, u17, v17, u35, v35, u12, v12;
col += offset;
x0 = col[0*8];
x1 = col[1*8];
x2 = col[2*8];
x3 = col[3*8];
x4 = col[4*8];
x5 = col[5*8];
x6 = col[6*8];
x7 = col[7*8];
u04 = S (x0 + x4);
v04 = S (x0 - x4);
u26 = S (F (T2, x6) + x2);
v26 = S (F (T2, x2) - x6);
a0 = S (u04 + u26);
a1 = S (v04 + v26);
a2 = S (v04 - v26);
a3 = S (u04 - u26);
u17 = S (F (T1, x7) + x1);
v17 = S (F (T1, x1) - x7);
u35 = S (F (T3, x5) + x3);
v35 = S (F (T3, x3) - x5);
b0 = S (u17 + u35);
b3 = S (v17 - v35);
u12 = S (u17 - u35);
v12 = S (v17 + v35);
u12 = S (2 * F (C4, u12));
v12 = S (2 * F (C4, v12));
b1 = S (u12 + v12);
b2 = S (u12 - v12);
y0 = S (a0 + b0) >> COL_SHIFT;
y1 = S (a1 + b1) >> COL_SHIFT;
y2 = S (a2 + b2) >> COL_SHIFT;
y3 = S (a3 + b3) >> COL_SHIFT;
y4 = S (a3 - b3) >> COL_SHIFT;
y5 = S (a2 - b2) >> COL_SHIFT;
y6 = S (a1 - b1) >> COL_SHIFT;
y7 = S (a0 - b0) >> COL_SHIFT;
col[0*8] = y0;
col[1*8] = y1;
col[2*8] = y2;
col[3*8] = y3;
col[4*8] = y4;
col[5*8] = y5;
col[6*8] = y6;
col[7*8] = y7;
}
#endif
/* MMX column IDCT */
static inline void idct_col (int16_t * col, int offset)
{
#define T1 13036
#define T2 27146
#define T3 43790
#define C4 23170
static const short t1_vector[] ATTR_ALIGN(8) = {T1,T1,T1,T1};
static const short t2_vector[] ATTR_ALIGN(8) = {T2,T2,T2,T2};
static const short t3_vector[] ATTR_ALIGN(8) = {T3,T3,T3,T3};
static const short c4_vector[] ATTR_ALIGN(8) = {C4,C4,C4,C4};
/* column code adapted from Peter Gubanov */
/* http://www.elecard.com/peter/idct.shtml */
movq_m2r (*t1_vector, mm0); /* mm0 = T1 */
movq_m2r (*(col+offset+1*8), mm1); /* mm1 = x1 */
movq_r2r (mm0, mm2); /* mm2 = T1 */
movq_m2r (*(col+offset+7*8), mm4); /* mm4 = x7 */
pmulhw_r2r (mm1, mm0); /* mm0 = T1*x1 */
movq_m2r (*t3_vector, mm5); /* mm5 = T3 */
pmulhw_r2r (mm4, mm2); /* mm2 = T1*x7 */
movq_m2r (*(col+offset+5*8), mm6); /* mm6 = x5 */
movq_r2r (mm5, mm7); /* mm7 = T3-1 */
movq_m2r (*(col+offset+3*8), mm3); /* mm3 = x3 */
psubsw_r2r (mm4, mm0); /* mm0 = v17 */
movq_m2r (*t2_vector, mm4); /* mm4 = T2 */
pmulhw_r2r (mm3, mm5); /* mm5 = (T3-1)*x3 */
paddsw_r2r (mm2, mm1); /* mm1 = u17 */
pmulhw_r2r (mm6, mm7); /* mm7 = (T3-1)*x5 */
/* slot */
movq_r2r (mm4, mm2); /* mm2 = T2 */
paddsw_r2r (mm3, mm5); /* mm5 = T3*x3 */
pmulhw_m2r (*(col+offset+2*8), mm4);/* mm4 = T2*x2 */
paddsw_r2r (mm6, mm7); /* mm7 = T3*x5 */
psubsw_r2r (mm6, mm5); /* mm5 = v35 */
paddsw_r2r (mm3, mm7); /* mm7 = u35 */
movq_m2r (*(col+offset+6*8), mm3); /* mm3 = x6 */
movq_r2r (mm0, mm6); /* mm6 = v17 */
pmulhw_r2r (mm3, mm2); /* mm2 = T2*x6 */
psubsw_r2r (mm5, mm0); /* mm0 = b3 */
psubsw_r2r (mm3, mm4); /* mm4 = v26 */
paddsw_r2r (mm6, mm5); /* mm5 = v12 */
movq_r2m (mm0, *(col+offset+3*8)); /* save b3 in scratch0 */
movq_r2r (mm1, mm6); /* mm6 = u17 */
paddsw_m2r (*(col+offset+2*8), mm2);/* mm2 = u26 */
paddsw_r2r (mm7, mm6); /* mm6 = b0 */
psubsw_r2r (mm7, mm1); /* mm1 = u12 */
movq_r2r (mm1, mm7); /* mm7 = u12 */
movq_m2r (*(col+offset+0*8), mm3); /* mm3 = x0 */
paddsw_r2r (mm5, mm1); /* mm1 = u12+v12 */
movq_m2r (*c4_vector, mm0); /* mm0 = C4/2 */
psubsw_r2r (mm5, mm7); /* mm7 = u12-v12 */
movq_r2m (mm6, *(col+offset+5*8)); /* save b0 in scratch1 */
pmulhw_r2r (mm0, mm1); /* mm1 = b1/2 */
movq_r2r (mm4, mm6); /* mm6 = v26 */
pmulhw_r2r (mm0, mm7); /* mm7 = b2/2 */
movq_m2r (*(col+offset+4*8), mm5); /* mm5 = x4 */
movq_r2r (mm3, mm0); /* mm0 = x0 */
psubsw_r2r (mm5, mm3); /* mm3 = v04 */
paddsw_r2r (mm5, mm0); /* mm0 = u04 */
paddsw_r2r (mm3, mm4); /* mm4 = a1 */
movq_r2r (mm0, mm5); /* mm5 = u04 */
psubsw_r2r (mm6, mm3); /* mm3 = a2 */
paddsw_r2r (mm2, mm5); /* mm5 = a0 */
paddsw_r2r (mm1, mm1); /* mm1 = b1 */
psubsw_r2r (mm2, mm0); /* mm0 = a3 */
paddsw_r2r (mm7, mm7); /* mm7 = b2 */
movq_r2r (mm3, mm2); /* mm2 = a2 */
movq_r2r (mm4, mm6); /* mm6 = a1 */
paddsw_r2r (mm7, mm3); /* mm3 = a2+b2 */
psraw_i2r (COL_SHIFT, mm3); /* mm3 = y2 */
paddsw_r2r (mm1, mm4); /* mm4 = a1+b1 */
psraw_i2r (COL_SHIFT, mm4); /* mm4 = y1 */
psubsw_r2r (mm1, mm6); /* mm6 = a1-b1 */
movq_m2r (*(col+offset+5*8), mm1); /* mm1 = b0 */
psubsw_r2r (mm7, mm2); /* mm2 = a2-b2 */
psraw_i2r (COL_SHIFT, mm6); /* mm6 = y6 */
movq_r2r (mm5, mm7); /* mm7 = a0 */
movq_r2m (mm4, *(col+offset+1*8)); /* save y1 */
psraw_i2r (COL_SHIFT, mm2); /* mm2 = y5 */
movq_r2m (mm3, *(col+offset+2*8)); /* save y2 */
paddsw_r2r (mm1, mm5); /* mm5 = a0+b0 */
movq_m2r (*(col+offset+3*8), mm4); /* mm4 = b3 */
psubsw_r2r (mm1, mm7); /* mm7 = a0-b0 */
psraw_i2r (COL_SHIFT, mm5); /* mm5 = y0 */
movq_r2r (mm0, mm3); /* mm3 = a3 */
movq_r2m (mm2, *(col+offset+5*8)); /* save y5 */
psubsw_r2r (mm4, mm3); /* mm3 = a3-b3 */
psraw_i2r (COL_SHIFT, mm7); /* mm7 = y7 */
paddsw_r2r (mm0, mm4); /* mm4 = a3+b3 */
movq_r2m (mm5, *(col+offset+0*8)); /* save y0 */
psraw_i2r (COL_SHIFT, mm3); /* mm3 = y4 */
movq_r2m (mm6, *(col+offset+6*8)); /* save y6 */
psraw_i2r (COL_SHIFT, mm4); /* mm4 = y3 */
movq_r2m (mm7, *(col+offset+7*8)); /* save y7 */
movq_r2m (mm3, *(col+offset+4*8)); /* save y4 */
movq_r2m (mm4, *(col+offset+3*8)); /* save y3 */
#undef T1
#undef T2
#undef T3
#undef C4
}
static const int32_t rounder0[] ATTR_ALIGN(8) =
rounder ((1 << (COL_SHIFT - 1)) - 0.5);
static const int32_t rounder4[] ATTR_ALIGN(8) = rounder (0);
static const int32_t rounder1[] ATTR_ALIGN(8) =
rounder (1.25683487303); /* C1*(C1/C4+C1+C7)/2 */
static const int32_t rounder7[] ATTR_ALIGN(8) =
rounder (-0.25); /* C1*(C7/C4+C7-C1)/2 */
static const int32_t rounder2[] ATTR_ALIGN(8) =
rounder (0.60355339059); /* C2 * (C6+C2)/2 */
static const int32_t rounder6[] ATTR_ALIGN(8) =
rounder (-0.25); /* C2 * (C6-C2)/2 */
static const int32_t rounder3[] ATTR_ALIGN(8) =
rounder (0.087788325588); /* C3*(-C3/C4+C3+C5)/2 */
static const int32_t rounder5[] ATTR_ALIGN(8) =
rounder (-0.441341716183); /* C3*(-C5/C4+C5-C3)/2 */
#undef COL_SHIFT
#undef ROW_SHIFT
#define declare_idct(idct,table,idct_row_head,idct_row,idct_row_tail,idct_row_mid) \
void idct (int16_t * block) \
{ \
static const int16_t table04[] ATTR_ALIGN(16) = \
table (22725, 21407, 19266, 16384, 12873, 8867, 4520); \
static const int16_t table17[] ATTR_ALIGN(16) = \
table (31521, 29692, 26722, 22725, 17855, 12299, 6270); \
static const int16_t table26[] ATTR_ALIGN(16) = \
table (29692, 27969, 25172, 21407, 16819, 11585, 5906); \
static const int16_t table35[] ATTR_ALIGN(16) = \
table (26722, 25172, 22654, 19266, 15137, 10426, 5315); \
\
idct_row_head (block, 0*8, table04); \
idct_row (table04, rounder0); \
idct_row_mid (block, 0*8, 4*8, table04); \
idct_row (table04, rounder4); \
idct_row_mid (block, 4*8, 1*8, table17); \
idct_row (table17, rounder1); \
idct_row_mid (block, 1*8, 7*8, table17); \
idct_row (table17, rounder7); \
idct_row_mid (block, 7*8, 2*8, table26); \
idct_row (table26, rounder2); \
idct_row_mid (block, 2*8, 6*8, table26); \
idct_row (table26, rounder6); \
idct_row_mid (block, 6*8, 3*8, table35); \
idct_row (table35, rounder3); \
idct_row_mid (block, 3*8, 5*8, table35); \
idct_row (table35, rounder5); \
idct_row_tail (block, 5*8); \
\
idct_col (block, 0); \
idct_col (block, 4); \
}
void ff_mmx_idct(DCTELEM *block);
void ff_mmxext_idct(DCTELEM *block);
declare_idct (ff_mmxext_idct, mmxext_table,
mmxext_row_head, mmxext_row, mmxext_row_tail, mmxext_row_mid)
declare_idct (ff_mmx_idct, mmx_table,
mmx_row_head, mmx_row, mmx_row_tail, mmx_row_mid)
@@ -0,0 +1,525 @@
/*
* XVID MPEG-4 VIDEO CODEC
* - MMX and XMM forward discrete cosine transform -
*
* Copyright(C) 2001 Peter Ross <[email protected]>
*
* Originally provided by Intel at AP-922
* http://developer.intel.com/vtune/cbts/strmsimd/922down.htm
* (See more app notes at http://developer.intel.com/vtune/cbts/strmsimd/appnotes.htm)
* but in a limited edition.
* New macro implements a column part for precise iDCT
* The routine precision now satisfies IEEE standard 1180-1990.
*
* Copyright(C) 2000-2001 Peter Gubanov <[email protected]>
* Rounding trick Copyright(C) 2000 Michel Lespinasse <[email protected]>
*
* http://www.elecard.com/peter/idct.html
* http://www.linuxvideo.org/mpeg2dec/
*
* These examples contain code fragments for first stage iDCT 8x8
* (for rows) and first stage DCT 8x8 (for columns)
*
* conversion to gcc syntax by Michael Niedermayer
*
* 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 <inttypes.h>
#include "libavcodec/avcodec.h"
//=============================================================================
// Macros and other preprocessor constants
//=============================================================================
#define BITS_INV_ACC 5 // 4 or 5 for IEEE
#define SHIFT_INV_ROW (16 - BITS_INV_ACC) //11
#define SHIFT_INV_COL (1 + BITS_INV_ACC) //6
#define RND_INV_ROW (1024 * (6 - BITS_INV_ACC))
#define RND_INV_COL (16 * (BITS_INV_ACC - 3))
#define RND_INV_CORR (RND_INV_COL - 1)
#define BITS_FRW_ACC 3 // 2 or 3 for accuracy
#define SHIFT_FRW_COL BITS_FRW_ACC
#define SHIFT_FRW_ROW (BITS_FRW_ACC + 17)
#define RND_FRW_ROW (262144*(BITS_FRW_ACC - 1))
//-----------------------------------------------------------------------------
// Various memory constants (trigonometric values or rounding values)
//-----------------------------------------------------------------------------
DECLARE_ALIGNED(8, static const int16_t, tg_1_16[4*4]) = {
13036,13036,13036,13036, // tg * (2<<16) + 0.5
27146,27146,27146,27146, // tg * (2<<16) + 0.5
-21746,-21746,-21746,-21746, // tg * (2<<16) + 0.5
23170,23170,23170,23170}; // cos * (2<<15) + 0.5
DECLARE_ALIGNED(8, static const int32_t, rounder_0[2*8]) = {
65536,65536,
3597,3597,
2260,2260,
1203,1203,
0,0,
120,120,
512,512,
512,512};
//-----------------------------------------------------------------------------
//
// The first stage iDCT 8x8 - inverse DCTs of rows
//
//-----------------------------------------------------------------------------
// The 8-point inverse DCT direct algorithm
//-----------------------------------------------------------------------------
//
// static const short w[32] = {
// FIX(cos_4_16), FIX(cos_2_16), FIX(cos_4_16), FIX(cos_6_16),
// FIX(cos_4_16), FIX(cos_6_16), -FIX(cos_4_16), -FIX(cos_2_16),
// FIX(cos_4_16), -FIX(cos_6_16), -FIX(cos_4_16), FIX(cos_2_16),
// FIX(cos_4_16), -FIX(cos_2_16), FIX(cos_4_16), -FIX(cos_6_16),
// FIX(cos_1_16), FIX(cos_3_16), FIX(cos_5_16), FIX(cos_7_16),
// FIX(cos_3_16), -FIX(cos_7_16), -FIX(cos_1_16), -FIX(cos_5_16),
// FIX(cos_5_16), -FIX(cos_1_16), FIX(cos_7_16), FIX(cos_3_16),
// FIX(cos_7_16), -FIX(cos_5_16), FIX(cos_3_16), -FIX(cos_1_16) };
//
// #define DCT_8_INV_ROW(x, y)
// {
// int a0, a1, a2, a3, b0, b1, b2, b3;
//
// a0 =x[0]*w[0]+x[2]*w[1]+x[4]*w[2]+x[6]*w[3];
// a1 =x[0]*w[4]+x[2]*w[5]+x[4]*w[6]+x[6]*w[7];
// a2 = x[0] * w[ 8] + x[2] * w[ 9] + x[4] * w[10] + x[6] * w[11];
// a3 = x[0] * w[12] + x[2] * w[13] + x[4] * w[14] + x[6] * w[15];
// b0 = x[1] * w[16] + x[3] * w[17] + x[5] * w[18] + x[7] * w[19];
// b1 = x[1] * w[20] + x[3] * w[21] + x[5] * w[22] + x[7] * w[23];
// b2 = x[1] * w[24] + x[3] * w[25] + x[5] * w[26] + x[7] * w[27];
// b3 = x[1] * w[28] + x[3] * w[29] + x[5] * w[30] + x[7] * w[31];
//
// y[0] = SHIFT_ROUND ( a0 + b0 );
// y[1] = SHIFT_ROUND ( a1 + b1 );
// y[2] = SHIFT_ROUND ( a2 + b2 );
// y[3] = SHIFT_ROUND ( a3 + b3 );
// y[4] = SHIFT_ROUND ( a3 - b3 );
// y[5] = SHIFT_ROUND ( a2 - b2 );
// y[6] = SHIFT_ROUND ( a1 - b1 );
// y[7] = SHIFT_ROUND ( a0 - b0 );
// }
//
//-----------------------------------------------------------------------------
//
// In this implementation the outputs of the iDCT-1D are multiplied
// for rows 0,4 - by cos_4_16,
// for rows 1,7 - by cos_1_16,
// for rows 2,6 - by cos_2_16,
// for rows 3,5 - by cos_3_16
// and are shifted to the left for better accuracy
//
// For the constants used,
// FIX(float_const) = (short) (float_const * (1<<15) + 0.5)
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Tables for mmx processors
//-----------------------------------------------------------------------------
// Table for rows 0,4 - constants are multiplied by cos_4_16
DECLARE_ALIGNED(8, static const int16_t, tab_i_04_mmx[32*4]) = {
16384,16384,16384,-16384, // movq-> w06 w04 w02 w00
21407,8867,8867,-21407, // w07 w05 w03 w01
16384,-16384,16384,16384, // w14 w12 w10 w08
-8867,21407,-21407,-8867, // w15 w13 w11 w09
22725,12873,19266,-22725, // w22 w20 w18 w16
19266,4520,-4520,-12873, // w23 w21 w19 w17
12873,4520,4520,19266, // w30 w28 w26 w24
-22725,19266,-12873,-22725, // w31 w29 w27 w25
// Table for rows 1,7 - constants are multiplied by cos_1_16
22725,22725,22725,-22725, // movq-> w06 w04 w02 w00
29692,12299,12299,-29692, // w07 w05 w03 w01
22725,-22725,22725,22725, // w14 w12 w10 w08
-12299,29692,-29692,-12299, // w15 w13 w11 w09
31521,17855,26722,-31521, // w22 w20 w18 w16
26722,6270,-6270,-17855, // w23 w21 w19 w17
17855,6270,6270,26722, // w30 w28 w26 w24
-31521,26722,-17855,-31521, // w31 w29 w27 w25
// Table for rows 2,6 - constants are multiplied by cos_2_16
21407,21407,21407,-21407, // movq-> w06 w04 w02 w00
27969,11585,11585,-27969, // w07 w05 w03 w01
21407,-21407,21407,21407, // w14 w12 w10 w08
-11585,27969,-27969,-11585, // w15 w13 w11 w09
29692,16819,25172,-29692, // w22 w20 w18 w16
25172,5906,-5906,-16819, // w23 w21 w19 w17
16819,5906,5906,25172, // w30 w28 w26 w24
-29692,25172,-16819,-29692, // w31 w29 w27 w25
// Table for rows 3,5 - constants are multiplied by cos_3_16
19266,19266,19266,-19266, // movq-> w06 w04 w02 w00
25172,10426,10426,-25172, // w07 w05 w03 w01
19266,-19266,19266,19266, // w14 w12 w10 w08
-10426,25172,-25172,-10426, // w15 w13 w11 w09
26722,15137,22654,-26722, // w22 w20 w18 w16
22654,5315,-5315,-15137, // w23 w21 w19 w17
15137,5315,5315,22654, // w30 w28 w26 w24
-26722,22654,-15137,-26722, // w31 w29 w27 w25
};
//-----------------------------------------------------------------------------
// Tables for xmm processors
//-----------------------------------------------------------------------------
// %3 for rows 0,4 - constants are multiplied by cos_4_16
DECLARE_ALIGNED(8, static const int16_t, tab_i_04_xmm[32*4]) = {
16384,21407,16384,8867, // movq-> w05 w04 w01 w00
16384,8867,-16384,-21407, // w07 w06 w03 w02
16384,-8867,16384,-21407, // w13 w12 w09 w08
-16384,21407,16384,-8867, // w15 w14 w11 w10
22725,19266,19266,-4520, // w21 w20 w17 w16
12873,4520,-22725,-12873, // w23 w22 w19 w18
12873,-22725,4520,-12873, // w29 w28 w25 w24
4520,19266,19266,-22725, // w31 w30 w27 w26
// %3 for rows 1,7 - constants are multiplied by cos_1_16
22725,29692,22725,12299, // movq-> w05 w04 w01 w00
22725,12299,-22725,-29692, // w07 w06 w03 w02
22725,-12299,22725,-29692, // w13 w12 w09 w08
-22725,29692,22725,-12299, // w15 w14 w11 w10
31521,26722,26722,-6270, // w21 w20 w17 w16
17855,6270,-31521,-17855, // w23 w22 w19 w18
17855,-31521,6270,-17855, // w29 w28 w25 w24
6270,26722,26722,-31521, // w31 w30 w27 w26
// %3 for rows 2,6 - constants are multiplied by cos_2_16
21407,27969,21407,11585, // movq-> w05 w04 w01 w00
21407,11585,-21407,-27969, // w07 w06 w03 w02
21407,-11585,21407,-27969, // w13 w12 w09 w08
-21407,27969,21407,-11585, // w15 w14 w11 w10
29692,25172,25172,-5906, // w21 w20 w17 w16
16819,5906,-29692,-16819, // w23 w22 w19 w18
16819,-29692,5906,-16819, // w29 w28 w25 w24
5906,25172,25172,-29692, // w31 w30 w27 w26
// %3 for rows 3,5 - constants are multiplied by cos_3_16
19266,25172,19266,10426, // movq-> w05 w04 w01 w00
19266,10426,-19266,-25172, // w07 w06 w03 w02
19266,-10426,19266,-25172, // w13 w12 w09 w08
-19266,25172,19266,-10426, // w15 w14 w11 w10
26722,22654,22654,-5315, // w21 w20 w17 w16
15137,5315,-26722,-15137, // w23 w22 w19 w18
15137,-26722,5315,-15137, // w29 w28 w25 w24
5315,22654,22654,-26722, // w31 w30 w27 w26
};
//=============================================================================
// Helper macros for the code
//=============================================================================
//-----------------------------------------------------------------------------
// DCT_8_INV_ROW_MMX( INP, OUT, TABLE, ROUNDER
//-----------------------------------------------------------------------------
#define DCT_8_INV_ROW_MMX(A1,A2,A3,A4)\
"movq " #A1 ",%%mm0 \n\t"/* 0 ; x3 x2 x1 x0*/\
"movq 8+" #A1 ",%%mm1 \n\t"/* 1 ; x7 x6 x5 x4*/\
"movq %%mm0,%%mm2 \n\t"/* 2 ; x3 x2 x1 x0*/\
"movq " #A3 ",%%mm3 \n\t"/* 3 ; w06 w04 w02 w00*/\
"punpcklwd %%mm1,%%mm0 \n\t"/* x5 x1 x4 x0*/\
"movq %%mm0,%%mm5 \n\t"/* 5 ; x5 x1 x4 x0*/\
"punpckldq %%mm0,%%mm0 \n\t"/* x4 x0 x4 x0*/\
"movq 8+" #A3 ",%%mm4 \n\t"/* 4 ; w07 w05 w03 w01*/\
"punpckhwd %%mm1,%%mm2 \n\t"/* 1 ; x7 x3 x6 x2*/\
"pmaddwd %%mm0,%%mm3 \n\t"/* x4*w06+x0*w04 x4*w02+x0*w00*/\
"movq %%mm2,%%mm6 \n\t"/* 6 ; x7 x3 x6 x2*/\
"movq 32+" #A3 ",%%mm1 \n\t"/* 1 ; w22 w20 w18 w16*/\
"punpckldq %%mm2,%%mm2 \n\t"/* x6 x2 x6 x2*/\
"pmaddwd %%mm2,%%mm4 \n\t"/* x6*w07+x2*w05 x6*w03+x2*w01*/\
"punpckhdq %%mm5,%%mm5 \n\t"/* x5 x1 x5 x1*/\
"pmaddwd 16+" #A3 ",%%mm0 \n\t"/* x4*w14+x0*w12 x4*w10+x0*w08*/\
"punpckhdq %%mm6,%%mm6 \n\t"/* x7 x3 x7 x3*/\
"movq 40+" #A3 ",%%mm7 \n\t"/* 7 ; w23 w21 w19 w17*/\
"pmaddwd %%mm5,%%mm1 \n\t"/* x5*w22+x1*w20 x5*w18+x1*w16*/\
"paddd " #A4 ",%%mm3 \n\t"/* +%4*/\
"pmaddwd %%mm6,%%mm7 \n\t"/* x7*w23+x3*w21 x7*w19+x3*w17*/\
"pmaddwd 24+" #A3 ",%%mm2 \n\t"/* x6*w15+x2*w13 x6*w11+x2*w09*/\
"paddd %%mm4,%%mm3 \n\t"/* 4 ; a1=sum(even1) a0=sum(even0)*/\
"pmaddwd 48+" #A3 ",%%mm5 \n\t"/* x5*w30+x1*w28 x5*w26+x1*w24*/\
"movq %%mm3,%%mm4 \n\t"/* 4 ; a1 a0*/\
"pmaddwd 56+" #A3 ",%%mm6 \n\t"/* x7*w31+x3*w29 x7*w27+x3*w25*/\
"paddd %%mm7,%%mm1 \n\t"/* 7 ; b1=sum(odd1) b0=sum(odd0)*/\
"paddd " #A4 ",%%mm0 \n\t"/* +%4*/\
"psubd %%mm1,%%mm3 \n\t"/* a1-b1 a0-b0*/\
"psrad $11,%%mm3 \n\t"/* y6=a1-b1 y7=a0-b0*/\
"paddd %%mm4,%%mm1 \n\t"/* 4 ; a1+b1 a0+b0*/\
"paddd %%mm2,%%mm0 \n\t"/* 2 ; a3=sum(even3) a2=sum(even2)*/\
"psrad $11,%%mm1 \n\t"/* y1=a1+b1 y0=a0+b0*/\
"paddd %%mm6,%%mm5 \n\t"/* 6 ; b3=sum(odd3) b2=sum(odd2)*/\
"movq %%mm0,%%mm4 \n\t"/* 4 ; a3 a2*/\
"paddd %%mm5,%%mm0 \n\t"/* a3+b3 a2+b2*/\
"psubd %%mm5,%%mm4 \n\t"/* 5 ; a3-b3 a2-b2*/\
"psrad $11,%%mm0 \n\t"/* y3=a3+b3 y2=a2+b2*/\
"psrad $11,%%mm4 \n\t"/* y4=a3-b3 y5=a2-b2*/\
"packssdw %%mm0,%%mm1 \n\t"/* 0 ; y3 y2 y1 y0*/\
"packssdw %%mm3,%%mm4 \n\t"/* 3 ; y6 y7 y4 y5*/\
"movq %%mm4,%%mm7 \n\t"/* 7 ; y6 y7 y4 y5*/\
"psrld $16,%%mm4 \n\t"/* 0 y6 0 y4*/\
"pslld $16,%%mm7 \n\t"/* y7 0 y5 0*/\
"movq %%mm1," #A2 " \n\t"/* 1 ; save y3 y2 y1 y0*/\
"por %%mm4,%%mm7 \n\t"/* 4 ; y7 y6 y5 y4*/\
"movq %%mm7,8 +" #A2 "\n\t"/* 7 ; save y7 y6 y5 y4*/\
//-----------------------------------------------------------------------------
// DCT_8_INV_ROW_XMM( INP, OUT, TABLE, ROUNDER
//-----------------------------------------------------------------------------
#define DCT_8_INV_ROW_XMM(A1,A2,A3,A4)\
"movq " #A1 ",%%mm0 \n\t"/* 0 ; x3 x2 x1 x0*/\
"movq 8+" #A1 ",%%mm1 \n\t"/* 1 ; x7 x6 x5 x4*/\
"movq %%mm0,%%mm2 \n\t"/* 2 ; x3 x2 x1 x0*/\
"movq " #A3 ",%%mm3 \n\t"/* 3 ; w05 w04 w01 w00*/\
"pshufw $0x88,%%mm0,%%mm0 \n\t"/* x2 x0 x2 x0*/\
"movq 8+" #A3 ",%%mm4 \n\t"/* 4 ; w07 w06 w03 w02*/\
"movq %%mm1,%%mm5 \n\t"/* 5 ; x7 x6 x5 x4*/\
"pmaddwd %%mm0,%%mm3 \n\t"/* x2*w05+x0*w04 x2*w01+x0*w00*/\
"movq 32+" #A3 ",%%mm6 \n\t"/* 6 ; w21 w20 w17 w16*/\
"pshufw $0x88,%%mm1,%%mm1 \n\t"/* x6 x4 x6 x4*/\
"pmaddwd %%mm1,%%mm4 \n\t"/* x6*w07+x4*w06 x6*w03+x4*w02*/\
"movq 40+" #A3 ",%%mm7 \n\t"/* 7 ; w23 w22 w19 w18*/\
"pshufw $0xdd,%%mm2,%%mm2 \n\t"/* x3 x1 x3 x1*/\
"pmaddwd %%mm2,%%mm6 \n\t"/* x3*w21+x1*w20 x3*w17+x1*w16*/\
"pshufw $0xdd,%%mm5,%%mm5 \n\t"/* x7 x5 x7 x5*/\
"pmaddwd %%mm5,%%mm7 \n\t"/* x7*w23+x5*w22 x7*w19+x5*w18*/\
"paddd " #A4 ",%%mm3 \n\t"/* +%4*/\
"pmaddwd 16+" #A3 ",%%mm0 \n\t"/* x2*w13+x0*w12 x2*w09+x0*w08*/\
"paddd %%mm4,%%mm3 \n\t"/* 4 ; a1=sum(even1) a0=sum(even0)*/\
"pmaddwd 24+" #A3 ",%%mm1 \n\t"/* x6*w15+x4*w14 x6*w11+x4*w10*/\
"movq %%mm3,%%mm4 \n\t"/* 4 ; a1 a0*/\
"pmaddwd 48+" #A3 ",%%mm2 \n\t"/* x3*w29+x1*w28 x3*w25+x1*w24*/\
"paddd %%mm7,%%mm6 \n\t"/* 7 ; b1=sum(odd1) b0=sum(odd0)*/\
"pmaddwd 56+" #A3 ",%%mm5 \n\t"/* x7*w31+x5*w30 x7*w27+x5*w26*/\
"paddd %%mm6,%%mm3 \n\t"/* a1+b1 a0+b0*/\
"paddd " #A4 ",%%mm0 \n\t"/* +%4*/\
"psrad $11,%%mm3 \n\t"/* y1=a1+b1 y0=a0+b0*/\
"paddd %%mm1,%%mm0 \n\t"/* 1 ; a3=sum(even3) a2=sum(even2)*/\
"psubd %%mm6,%%mm4 \n\t"/* 6 ; a1-b1 a0-b0*/\
"movq %%mm0,%%mm7 \n\t"/* 7 ; a3 a2*/\
"paddd %%mm5,%%mm2 \n\t"/* 5 ; b3=sum(odd3) b2=sum(odd2)*/\
"paddd %%mm2,%%mm0 \n\t"/* a3+b3 a2+b2*/\
"psrad $11,%%mm4 \n\t"/* y6=a1-b1 y7=a0-b0*/\
"psubd %%mm2,%%mm7 \n\t"/* 2 ; a3-b3 a2-b2*/\
"psrad $11,%%mm0 \n\t"/* y3=a3+b3 y2=a2+b2*/\
"psrad $11,%%mm7 \n\t"/* y4=a3-b3 y5=a2-b2*/\
"packssdw %%mm0,%%mm3 \n\t"/* 0 ; y3 y2 y1 y0*/\
"packssdw %%mm4,%%mm7 \n\t"/* 4 ; y6 y7 y4 y5*/\
"movq %%mm3, " #A2 " \n\t"/* 3 ; save y3 y2 y1 y0*/\
"pshufw $0xb1,%%mm7,%%mm7 \n\t"/* y7 y6 y5 y4*/\
"movq %%mm7,8 +" #A2 "\n\t"/* 7 ; save y7 y6 y5 y4*/\
//-----------------------------------------------------------------------------
//
// The first stage DCT 8x8 - forward DCTs of columns
//
// The %2puts are multiplied
// for rows 0,4 - on cos_4_16,
// for rows 1,7 - on cos_1_16,
// for rows 2,6 - on cos_2_16,
// for rows 3,5 - on cos_3_16
// and are shifted to the left for rise of accuracy
//
//-----------------------------------------------------------------------------
//
// The 8-point scaled forward DCT algorithm (26a8m)
//
//-----------------------------------------------------------------------------
//
// #define DCT_8_FRW_COL(x, y)
//{
// short t0, t1, t2, t3, t4, t5, t6, t7;
// short tp03, tm03, tp12, tm12, tp65, tm65;
// short tp465, tm465, tp765, tm765;
//
// t0 = LEFT_SHIFT ( x[0] + x[7] );
// t1 = LEFT_SHIFT ( x[1] + x[6] );
// t2 = LEFT_SHIFT ( x[2] + x[5] );
// t3 = LEFT_SHIFT ( x[3] + x[4] );
// t4 = LEFT_SHIFT ( x[3] - x[4] );
// t5 = LEFT_SHIFT ( x[2] - x[5] );
// t6 = LEFT_SHIFT ( x[1] - x[6] );
// t7 = LEFT_SHIFT ( x[0] - x[7] );
//
// tp03 = t0 + t3;
// tm03 = t0 - t3;
// tp12 = t1 + t2;
// tm12 = t1 - t2;
//
// y[0] = tp03 + tp12;
// y[4] = tp03 - tp12;
//
// y[2] = tm03 + tm12 * tg_2_16;
// y[6] = tm03 * tg_2_16 - tm12;
//
// tp65 =(t6 +t5 )*cos_4_16;
// tm65 =(t6 -t5 )*cos_4_16;
//
// tp765 = t7 + tp65;
// tm765 = t7 - tp65;
// tp465 = t4 + tm65;
// tm465 = t4 - tm65;
//
// y[1] = tp765 + tp465 * tg_1_16;
// y[7] = tp765 * tg_1_16 - tp465;
// y[5] = tm765 * tg_3_16 + tm465;
// y[3] = tm765 - tm465 * tg_3_16;
//}
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// DCT_8_INV_COL_4 INP,OUT
//-----------------------------------------------------------------------------
#define DCT_8_INV_COL(A1,A2)\
"movq 2*8(%3),%%mm0\n\t"\
"movq 16*3+" #A1 ",%%mm3\n\t"\
"movq %%mm0,%%mm1 \n\t"/* tg_3_16*/\
"movq 16*5+" #A1 ",%%mm5\n\t"\
"pmulhw %%mm3,%%mm0 \n\t"/* x3*(tg_3_16-1)*/\
"movq (%3),%%mm4\n\t"\
"pmulhw %%mm5,%%mm1 \n\t"/* x5*(tg_3_16-1)*/\
"movq 16*7+" #A1 ",%%mm7\n\t"\
"movq %%mm4,%%mm2 \n\t"/* tg_1_16*/\
"movq 16*1+" #A1 ",%%mm6\n\t"\
"pmulhw %%mm7,%%mm4 \n\t"/* x7*tg_1_16*/\
"paddsw %%mm3,%%mm0 \n\t"/* x3*tg_3_16*/\
"pmulhw %%mm6,%%mm2 \n\t"/* x1*tg_1_16*/\
"paddsw %%mm3,%%mm1 \n\t"/* x3+x5*(tg_3_16-1)*/\
"psubsw %%mm5,%%mm0 \n\t"/* x3*tg_3_16-x5 = tm35*/\
"movq 3*8(%3),%%mm3\n\t"\
"paddsw %%mm5,%%mm1 \n\t"/* x3+x5*tg_3_16 = tp35*/\
"paddsw %%mm6,%%mm4 \n\t"/* x1+tg_1_16*x7 = tp17*/\
"psubsw %%mm7,%%mm2 \n\t"/* x1*tg_1_16-x7 = tm17*/\
"movq %%mm4,%%mm5 \n\t"/* tp17*/\
"movq %%mm2,%%mm6 \n\t"/* tm17*/\
"paddsw %%mm1,%%mm5 \n\t"/* tp17+tp35 = b0*/\
"psubsw %%mm0,%%mm6 \n\t"/* tm17-tm35 = b3*/\
"psubsw %%mm1,%%mm4 \n\t"/* tp17-tp35 = t1*/\
"paddsw %%mm0,%%mm2 \n\t"/* tm17+tm35 = t2*/\
"movq 1*8(%3),%%mm7\n\t"\
"movq %%mm4,%%mm1 \n\t"/* t1*/\
"movq %%mm5,3*16 +" #A2 "\n\t"/* save b0*/\
"paddsw %%mm2,%%mm1 \n\t"/* t1+t2*/\
"movq %%mm6,5*16 +" #A2 "\n\t"/* save b3*/\
"psubsw %%mm2,%%mm4 \n\t"/* t1-t2*/\
"movq 2*16+" #A1 ",%%mm5\n\t"\
"movq %%mm7,%%mm0 \n\t"/* tg_2_16*/\
"movq 6*16+" #A1 ",%%mm6\n\t"\
"pmulhw %%mm5,%%mm0 \n\t"/* x2*tg_2_16*/\
"pmulhw %%mm6,%%mm7 \n\t"/* x6*tg_2_16*/\
"pmulhw %%mm3,%%mm1 \n\t"/* ocos_4_16*(t1+t2) = b1/2*/\
"movq 0*16+" #A1 ",%%mm2\n\t"\
"pmulhw %%mm3,%%mm4 \n\t"/* ocos_4_16*(t1-t2) = b2/2*/\
"psubsw %%mm6,%%mm0 \n\t"/* t2*tg_2_16-x6 = tm26*/\
"movq %%mm2,%%mm3 \n\t"/* x0*/\
"movq 4*16+" #A1 ",%%mm6\n\t"\
"paddsw %%mm5,%%mm7 \n\t"/* x2+x6*tg_2_16 = tp26*/\
"paddsw %%mm6,%%mm2 \n\t"/* x0+x4 = tp04*/\
"psubsw %%mm6,%%mm3 \n\t"/* x0-x4 = tm04*/\
"movq %%mm2,%%mm5 \n\t"/* tp04*/\
"movq %%mm3,%%mm6 \n\t"/* tm04*/\
"psubsw %%mm7,%%mm2 \n\t"/* tp04-tp26 = a3*/\
"paddsw %%mm0,%%mm3 \n\t"/* tm04+tm26 = a1*/\
"paddsw %%mm1,%%mm1 \n\t"/* b1*/\
"paddsw %%mm4,%%mm4 \n\t"/* b2*/\
"paddsw %%mm7,%%mm5 \n\t"/* tp04+tp26 = a0*/\
"psubsw %%mm0,%%mm6 \n\t"/* tm04-tm26 = a2*/\
"movq %%mm3,%%mm7 \n\t"/* a1*/\
"movq %%mm6,%%mm0 \n\t"/* a2*/\
"paddsw %%mm1,%%mm3 \n\t"/* a1+b1*/\
"paddsw %%mm4,%%mm6 \n\t"/* a2+b2*/\
"psraw $6,%%mm3 \n\t"/* dst1*/\
"psubsw %%mm1,%%mm7 \n\t"/* a1-b1*/\
"psraw $6,%%mm6 \n\t"/* dst2*/\
"psubsw %%mm4,%%mm0 \n\t"/* a2-b2*/\
"movq 3*16+" #A2 ",%%mm1 \n\t"/* load b0*/\
"psraw $6,%%mm7 \n\t"/* dst6*/\
"movq %%mm5,%%mm4 \n\t"/* a0*/\
"psraw $6,%%mm0 \n\t"/* dst5*/\
"movq %%mm3,1*16+" #A2 "\n\t"\
"paddsw %%mm1,%%mm5 \n\t"/* a0+b0*/\
"movq %%mm6,2*16+" #A2 "\n\t"\
"psubsw %%mm1,%%mm4 \n\t"/* a0-b0*/\
"movq 5*16+" #A2 ",%%mm3 \n\t"/* load b3*/\
"psraw $6,%%mm5 \n\t"/* dst0*/\
"movq %%mm2,%%mm6 \n\t"/* a3*/\
"psraw $6,%%mm4 \n\t"/* dst7*/\
"movq %%mm0,5*16+" #A2 "\n\t"\
"paddsw %%mm3,%%mm2 \n\t"/* a3+b3*/\
"movq %%mm7,6*16+" #A2 "\n\t"\
"psubsw %%mm3,%%mm6 \n\t"/* a3-b3*/\
"movq %%mm5,0*16+" #A2 "\n\t"\
"psraw $6,%%mm2 \n\t"/* dst3*/\
"movq %%mm4,7*16+" #A2 "\n\t"\
"psraw $6,%%mm6 \n\t"/* dst4*/\
"movq %%mm2,3*16+" #A2 "\n\t"\
"movq %%mm6,4*16+" #A2 "\n\t"
//=============================================================================
// Code
//=============================================================================
//-----------------------------------------------------------------------------
// void idct_mmx(uint16_t block[64]);
//-----------------------------------------------------------------------------
void ff_idct_xvid_mmx(short *block){
asm volatile(
//# Process each row
DCT_8_INV_ROW_MMX(0*16(%0), 0*16(%0), 64*0(%2), 8*0(%1))
DCT_8_INV_ROW_MMX(1*16(%0), 1*16(%0), 64*1(%2), 8*1(%1))
DCT_8_INV_ROW_MMX(2*16(%0), 2*16(%0), 64*2(%2), 8*2(%1))
DCT_8_INV_ROW_MMX(3*16(%0), 3*16(%0), 64*3(%2), 8*3(%1))
DCT_8_INV_ROW_MMX(4*16(%0), 4*16(%0), 64*0(%2), 8*4(%1))
DCT_8_INV_ROW_MMX(5*16(%0), 5*16(%0), 64*3(%2), 8*5(%1))
DCT_8_INV_ROW_MMX(6*16(%0), 6*16(%0), 64*2(%2), 8*6(%1))
DCT_8_INV_ROW_MMX(7*16(%0), 7*16(%0), 64*1(%2), 8*7(%1))
//# Process the columns (4 at a time)
DCT_8_INV_COL(0(%0), 0(%0))
DCT_8_INV_COL(8(%0), 8(%0))
:: "r"(block), "r"(rounder_0), "r"(tab_i_04_mmx), "r"(tg_1_16));
}
//-----------------------------------------------------------------------------
// void idct_xmm(uint16_t block[64]);
//-----------------------------------------------------------------------------
void ff_idct_xvid_mmx2(short *block){
asm volatile(
//# Process each row
DCT_8_INV_ROW_XMM(0*16(%0), 0*16(%0), 64*0(%2), 8*0(%1))
DCT_8_INV_ROW_XMM(1*16(%0), 1*16(%0), 64*1(%2), 8*1(%1))
DCT_8_INV_ROW_XMM(2*16(%0), 2*16(%0), 64*2(%2), 8*2(%1))
DCT_8_INV_ROW_XMM(3*16(%0), 3*16(%0), 64*3(%2), 8*3(%1))
DCT_8_INV_ROW_XMM(4*16(%0), 4*16(%0), 64*0(%2), 8*4(%1))
DCT_8_INV_ROW_XMM(5*16(%0), 5*16(%0), 64*3(%2), 8*5(%1))
DCT_8_INV_ROW_XMM(6*16(%0), 6*16(%0), 64*2(%2), 8*6(%1))
DCT_8_INV_ROW_XMM(7*16(%0), 7*16(%0), 64*1(%2), 8*7(%1))
//# Process the columns (4 at a time)
DCT_8_INV_COL(0(%0), 0(%0))
DCT_8_INV_COL(8(%0), 8(%0))
:: "r"(block), "r"(rounder_0), "r"(tab_i_04_xmm), "r"(tg_1_16));
}
@@ -0,0 +1,394 @@
/*
* XVID MPEG-4 VIDEO CODEC
* - SSE2 inverse discrete cosine transform -
*
* Copyright(C) 2003 Pascal Massimino <[email protected]>
*
* Conversion to gcc syntax with modifications
* by Alexander Strange <[email protected]>
*
* Originally from dct/x86_asm/fdct_sse2_skal.asm in Xvid.
*
* This file is part of FFmpeg.
*
* Vertical pass is an implementation of the scheme:
* Loeffler C., Ligtenberg A., and Moschytz C.S.:
* Practical Fast 1D DCT Algorithm with Eleven Multiplications,
* Proc. ICASSP 1989, 988-991.
*
* Horizontal pass is a double 4x4 vector/matrix multiplication,
* (see also Intel's Application Note 922:
* http://developer.intel.com/vtune/cbts/strmsimd/922down.htm
* Copyright (C) 1999 Intel Corporation)
*
* More details at http://skal.planet-d.net/coding/dct.html
*
* 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 "libavcodec/dsputil.h"
#include "libavcodec/i386/idct_xvid.h"
/*!
* @file idct_sse2_xvid.c
* @brief SSE2 idct compatible with xvidmmx
*/
#define X8(x) x,x,x,x,x,x,x,x
#define ROW_SHIFT 11
#define COL_SHIFT 6
DECLARE_ASM_CONST(16, int16_t, tan1[]) = {X8(13036)}; // tan( pi/16)
DECLARE_ASM_CONST(16, int16_t, tan2[]) = {X8(27146)}; // tan(2pi/16) = sqrt(2)-1
DECLARE_ASM_CONST(16, int16_t, tan3[]) = {X8(43790)}; // tan(3pi/16)-1
DECLARE_ASM_CONST(16, int16_t, sqrt2[])= {X8(23170)}; // 0.5/sqrt(2)
DECLARE_ASM_CONST(8, uint8_t, m127[]) = {X8(127)};
DECLARE_ASM_CONST(16, int16_t, iTab1[]) = {
0x4000, 0x539f, 0xc000, 0xac61, 0x4000, 0xdd5d, 0x4000, 0xdd5d,
0x4000, 0x22a3, 0x4000, 0x22a3, 0xc000, 0x539f, 0x4000, 0xac61,
0x3249, 0x11a8, 0x4b42, 0xee58, 0x11a8, 0x4b42, 0x11a8, 0xcdb7,
0x58c5, 0x4b42, 0xa73b, 0xcdb7, 0x3249, 0xa73b, 0x4b42, 0xa73b
};
DECLARE_ASM_CONST(16, int16_t, iTab2[]) = {
0x58c5, 0x73fc, 0xa73b, 0x8c04, 0x58c5, 0xcff5, 0x58c5, 0xcff5,
0x58c5, 0x300b, 0x58c5, 0x300b, 0xa73b, 0x73fc, 0x58c5, 0x8c04,
0x45bf, 0x187e, 0x6862, 0xe782, 0x187e, 0x6862, 0x187e, 0xba41,
0x7b21, 0x6862, 0x84df, 0xba41, 0x45bf, 0x84df, 0x6862, 0x84df
};
DECLARE_ASM_CONST(16, int16_t, iTab3[]) = {
0x539f, 0x6d41, 0xac61, 0x92bf, 0x539f, 0xd2bf, 0x539f, 0xd2bf,
0x539f, 0x2d41, 0x539f, 0x2d41, 0xac61, 0x6d41, 0x539f, 0x92bf,
0x41b3, 0x1712, 0x6254, 0xe8ee, 0x1712, 0x6254, 0x1712, 0xbe4d,
0x73fc, 0x6254, 0x8c04, 0xbe4d, 0x41b3, 0x8c04, 0x6254, 0x8c04
};
DECLARE_ASM_CONST(16, int16_t, iTab4[]) = {
0x4b42, 0x6254, 0xb4be, 0x9dac, 0x4b42, 0xd746, 0x4b42, 0xd746,
0x4b42, 0x28ba, 0x4b42, 0x28ba, 0xb4be, 0x6254, 0x4b42, 0x9dac,
0x3b21, 0x14c3, 0x587e, 0xeb3d, 0x14c3, 0x587e, 0x14c3, 0xc4df,
0x6862, 0x587e, 0x979e, 0xc4df, 0x3b21, 0x979e, 0x587e, 0x979e
};
DECLARE_ASM_CONST(16, int32_t, walkenIdctRounders[]) = {
65536, 65536, 65536, 65536,
3597, 3597, 3597, 3597,
2260, 2260, 2260, 2260,
1203, 1203, 1203, 1203,
120, 120, 120, 120,
512, 512, 512, 512
};
// Temporary storage before the column pass
#define ROW1 "%%xmm6"
#define ROW3 "%%xmm4"
#define ROW5 "%%xmm5"
#define ROW7 "%%xmm7"
#define CLEAR_ODD(r) "pxor "r","r" \n\t"
#define PUT_ODD(dst) "pshufhw $0x1B, %%xmm2, "dst" \n\t"
#ifdef ARCH_X86_64
# define ROW0 "%%xmm8"
# define REG0 ROW0
# define ROW2 "%%xmm9"
# define REG2 ROW2
# define ROW4 "%%xmm10"
# define REG4 ROW4
# define ROW6 "%%xmm11"
# define REG6 ROW6
# define CLEAR_EVEN(r) CLEAR_ODD(r)
# define PUT_EVEN(dst) PUT_ODD(dst)
# define XMMS "%%xmm12"
# define MOV_32_ONLY "#"
# define SREG2 REG2
# define TAN3 "%%xmm13"
# define TAN1 "%%xmm14"
#else
# define ROW0 "(%0)"
# define REG0 "%%xmm4"
# define ROW2 "2*16(%0)"
# define REG2 "%%xmm4"
# define ROW4 "4*16(%0)"
# define REG4 "%%xmm6"
# define ROW6 "6*16(%0)"
# define REG6 "%%xmm6"
# define CLEAR_EVEN(r)
# define PUT_EVEN(dst) \
"pshufhw $0x1B, %%xmm2, %%xmm2 \n\t" \
"movdqa %%xmm2, "dst" \n\t"
# define XMMS "%%xmm2"
# define MOV_32_ONLY "movdqa "
# define SREG2 "%%xmm7"
# define TAN3 "%%xmm0"
# define TAN1 "%%xmm2"
#endif
#define ROUND(x) "paddd "MANGLE(x)
#define JZ(reg, to) \
"testl "reg","reg" \n\t" \
"jz "to" \n\t"
#define JNZ(reg, to) \
"testl "reg","reg" \n\t" \
"jnz "to" \n\t"
#define TEST_ONE_ROW(src, reg, clear) \
clear \
"movq "src", %%mm1 \n\t" \
"por 8+"src", %%mm1 \n\t" \
"paddusb %%mm0, %%mm1 \n\t" \
"pmovmskb %%mm1, "reg" \n\t"
#define TEST_TWO_ROWS(row1, row2, reg1, reg2, clear1, clear2) \
clear1 \
clear2 \
"movq "row1", %%mm1 \n\t" \
"por 8+"row1", %%mm1 \n\t" \
"movq "row2", %%mm2 \n\t" \
"por 8+"row2", %%mm2 \n\t" \
"paddusb %%mm0, %%mm1 \n\t" \
"paddusb %%mm0, %%mm2 \n\t" \
"pmovmskb %%mm1, "reg1" \n\t" \
"pmovmskb %%mm2, "reg2" \n\t"
///IDCT pass on rows.
#define iMTX_MULT(src, table, rounder, put) \
"movdqa "src", %%xmm3 \n\t" \
"movdqa %%xmm3, %%xmm0 \n\t" \
"pshufd $0x11, %%xmm3, %%xmm1 \n\t" /* 4602 */ \
"punpcklqdq %%xmm0, %%xmm0 \n\t" /* 0246 */ \
"pmaddwd "table", %%xmm0 \n\t" \
"pmaddwd 16+"table", %%xmm1 \n\t" \
"pshufd $0xBB, %%xmm3, %%xmm2 \n\t" /* 5713 */ \
"punpckhqdq %%xmm3, %%xmm3 \n\t" /* 1357 */ \
"pmaddwd 32+"table", %%xmm2 \n\t" \
"pmaddwd 48+"table", %%xmm3 \n\t" \
"paddd %%xmm1, %%xmm0 \n\t" \
"paddd %%xmm3, %%xmm2 \n\t" \
rounder", %%xmm0 \n\t" \
"movdqa %%xmm2, %%xmm3 \n\t" \
"paddd %%xmm0, %%xmm2 \n\t" \
"psubd %%xmm3, %%xmm0 \n\t" \
"psrad $11, %%xmm2 \n\t" \
"psrad $11, %%xmm0 \n\t" \
"packssdw %%xmm0, %%xmm2 \n\t" \
put \
"1: \n\t"
#define iLLM_HEAD \
"movdqa "MANGLE(tan3)", "TAN3" \n\t" \
"movdqa "MANGLE(tan1)", "TAN1" \n\t" \
///IDCT pass on columns.
#define iLLM_PASS(dct) \
"movdqa "TAN3", %%xmm1 \n\t" \
"movdqa "TAN1", %%xmm3 \n\t" \
"pmulhw %%xmm4, "TAN3" \n\t" \
"pmulhw %%xmm5, %%xmm1 \n\t" \
"paddsw %%xmm4, "TAN3" \n\t" \
"paddsw %%xmm5, %%xmm1 \n\t" \
"psubsw %%xmm5, "TAN3" \n\t" \
"paddsw %%xmm4, %%xmm1 \n\t" \
"pmulhw %%xmm7, %%xmm3 \n\t" \
"pmulhw %%xmm6, "TAN1" \n\t" \
"paddsw %%xmm6, %%xmm3 \n\t" \
"psubsw %%xmm7, "TAN1" \n\t" \
"movdqa %%xmm3, %%xmm7 \n\t" \
"movdqa "TAN1", %%xmm6 \n\t" \
"psubsw %%xmm1, %%xmm3 \n\t" \
"psubsw "TAN3", "TAN1" \n\t" \
"paddsw %%xmm7, %%xmm1 \n\t" \
"paddsw %%xmm6, "TAN3" \n\t" \
"movdqa %%xmm3, %%xmm6 \n\t" \
"psubsw "TAN3", %%xmm3 \n\t" \
"paddsw %%xmm6, "TAN3" \n\t" \
"movdqa "MANGLE(sqrt2)", %%xmm4 \n\t" \
"pmulhw %%xmm4, %%xmm3 \n\t" \
"pmulhw %%xmm4, "TAN3" \n\t" \
"paddsw "TAN3", "TAN3" \n\t" \
"paddsw %%xmm3, %%xmm3 \n\t" \
"movdqa "MANGLE(tan2)", %%xmm7 \n\t" \
MOV_32_ONLY ROW2", "REG2" \n\t" \
MOV_32_ONLY ROW6", "REG6" \n\t" \
"movdqa %%xmm7, %%xmm5 \n\t" \
"pmulhw "REG6", %%xmm7 \n\t" \
"pmulhw "REG2", %%xmm5 \n\t" \
"paddsw "REG2", %%xmm7 \n\t" \
"psubsw "REG6", %%xmm5 \n\t" \
MOV_32_ONLY ROW0", "REG0" \n\t" \
MOV_32_ONLY ROW4", "REG4" \n\t" \
MOV_32_ONLY" "TAN1", (%0) \n\t" \
"movdqa "REG0", "XMMS" \n\t" \
"psubsw "REG4", "REG0" \n\t" \
"paddsw "XMMS", "REG4" \n\t" \
"movdqa "REG4", "XMMS" \n\t" \
"psubsw %%xmm7, "REG4" \n\t" \
"paddsw "XMMS", %%xmm7 \n\t" \
"movdqa "REG0", "XMMS" \n\t" \
"psubsw %%xmm5, "REG0" \n\t" \
"paddsw "XMMS", %%xmm5 \n\t" \
"movdqa %%xmm5, "XMMS" \n\t" \
"psubsw "TAN3", %%xmm5 \n\t" \
"paddsw "XMMS", "TAN3" \n\t" \
"movdqa "REG0", "XMMS" \n\t" \
"psubsw %%xmm3, "REG0" \n\t" \
"paddsw "XMMS", %%xmm3 \n\t" \
MOV_32_ONLY" (%0), "TAN1" \n\t" \
"psraw $6, %%xmm5 \n\t" \
"psraw $6, "REG0" \n\t" \
"psraw $6, "TAN3" \n\t" \
"psraw $6, %%xmm3 \n\t" \
"movdqa "TAN3", 1*16("dct") \n\t" \
"movdqa %%xmm3, 2*16("dct") \n\t" \
"movdqa "REG0", 5*16("dct") \n\t" \
"movdqa %%xmm5, 6*16("dct") \n\t" \
"movdqa %%xmm7, %%xmm0 \n\t" \
"movdqa "REG4", %%xmm4 \n\t" \
"psubsw %%xmm1, %%xmm7 \n\t" \
"psubsw "TAN1", "REG4" \n\t" \
"paddsw %%xmm0, %%xmm1 \n\t" \
"paddsw %%xmm4, "TAN1" \n\t" \
"psraw $6, %%xmm1 \n\t" \
"psraw $6, %%xmm7 \n\t" \
"psraw $6, "TAN1" \n\t" \
"psraw $6, "REG4" \n\t" \
"movdqa %%xmm1, ("dct") \n\t" \
"movdqa "TAN1", 3*16("dct") \n\t" \
"movdqa "REG4", 4*16("dct") \n\t" \
"movdqa %%xmm7, 7*16("dct") \n\t"
///IDCT pass on columns, assuming rows 4-7 are zero.
#define iLLM_PASS_SPARSE(dct) \
"pmulhw %%xmm4, "TAN3" \n\t" \
"paddsw %%xmm4, "TAN3" \n\t" \
"movdqa %%xmm6, %%xmm3 \n\t" \
"pmulhw %%xmm6, "TAN1" \n\t" \
"movdqa %%xmm4, %%xmm1 \n\t" \
"psubsw %%xmm1, %%xmm3 \n\t" \
"paddsw %%xmm6, %%xmm1 \n\t" \
"movdqa "TAN1", %%xmm6 \n\t" \
"psubsw "TAN3", "TAN1" \n\t" \
"paddsw %%xmm6, "TAN3" \n\t" \
"movdqa %%xmm3, %%xmm6 \n\t" \
"psubsw "TAN3", %%xmm3 \n\t" \
"paddsw %%xmm6, "TAN3" \n\t" \
"movdqa "MANGLE(sqrt2)", %%xmm4 \n\t" \
"pmulhw %%xmm4, %%xmm3 \n\t" \
"pmulhw %%xmm4, "TAN3" \n\t" \
"paddsw "TAN3", "TAN3" \n\t" \
"paddsw %%xmm3, %%xmm3 \n\t" \
"movdqa "MANGLE(tan2)", %%xmm5 \n\t" \
MOV_32_ONLY ROW2", "SREG2" \n\t" \
"pmulhw "SREG2", %%xmm5 \n\t" \
MOV_32_ONLY ROW0", "REG0" \n\t" \
"movdqa "REG0", %%xmm6 \n\t" \
"psubsw "SREG2", %%xmm6 \n\t" \
"paddsw "REG0", "SREG2" \n\t" \
MOV_32_ONLY" "TAN1", (%0) \n\t" \
"movdqa "REG0", "XMMS" \n\t" \
"psubsw %%xmm5, "REG0" \n\t" \
"paddsw "XMMS", %%xmm5 \n\t" \
"movdqa %%xmm5, "XMMS" \n\t" \
"psubsw "TAN3", %%xmm5 \n\t" \
"paddsw "XMMS", "TAN3" \n\t" \
"movdqa "REG0", "XMMS" \n\t" \
"psubsw %%xmm3, "REG0" \n\t" \
"paddsw "XMMS", %%xmm3 \n\t" \
MOV_32_ONLY" (%0), "TAN1" \n\t" \
"psraw $6, %%xmm5 \n\t" \
"psraw $6, "REG0" \n\t" \
"psraw $6, "TAN3" \n\t" \
"psraw $6, %%xmm3 \n\t" \
"movdqa "TAN3", 1*16("dct") \n\t" \
"movdqa %%xmm3, 2*16("dct") \n\t" \
"movdqa "REG0", 5*16("dct") \n\t" \
"movdqa %%xmm5, 6*16("dct") \n\t" \
"movdqa "SREG2", %%xmm0 \n\t" \
"movdqa %%xmm6, %%xmm4 \n\t" \
"psubsw %%xmm1, "SREG2" \n\t" \
"psubsw "TAN1", %%xmm6 \n\t" \
"paddsw %%xmm0, %%xmm1 \n\t" \
"paddsw %%xmm4, "TAN1" \n\t" \
"psraw $6, %%xmm1 \n\t" \
"psraw $6, "SREG2" \n\t" \
"psraw $6, "TAN1" \n\t" \
"psraw $6, %%xmm6 \n\t" \
"movdqa %%xmm1, ("dct") \n\t" \
"movdqa "TAN1", 3*16("dct") \n\t" \
"movdqa %%xmm6, 4*16("dct") \n\t" \
"movdqa "SREG2", 7*16("dct") \n\t"
inline void ff_idct_xvid_sse2(short *block)
{
asm volatile(
"movq "MANGLE(m127)", %%mm0 \n\t"
iMTX_MULT("(%0)", MANGLE(iTab1), ROUND(walkenIdctRounders), PUT_EVEN(ROW0))
iMTX_MULT("1*16(%0)", MANGLE(iTab2), ROUND(walkenIdctRounders+1*16), PUT_ODD(ROW1))
iMTX_MULT("2*16(%0)", MANGLE(iTab3), ROUND(walkenIdctRounders+2*16), PUT_EVEN(ROW2))
TEST_TWO_ROWS("3*16(%0)", "4*16(%0)", "%%eax", "%%ecx", CLEAR_ODD(ROW3), CLEAR_EVEN(ROW4))
JZ("%%eax", "1f")
iMTX_MULT("3*16(%0)", MANGLE(iTab4), ROUND(walkenIdctRounders+3*16), PUT_ODD(ROW3))
TEST_TWO_ROWS("5*16(%0)", "6*16(%0)", "%%eax", "%%edx", CLEAR_ODD(ROW5), CLEAR_EVEN(ROW6))
TEST_ONE_ROW("7*16(%0)", "%%esi", CLEAR_ODD(ROW7))
iLLM_HEAD
ASMALIGN(4)
JNZ("%%ecx", "2f")
JNZ("%%eax", "3f")
JNZ("%%edx", "4f")
JNZ("%%esi", "5f")
iLLM_PASS_SPARSE("%0")
"jmp 6f \n\t"
"2: \n\t"
iMTX_MULT("4*16(%0)", MANGLE(iTab1), "#", PUT_EVEN(ROW4))
"3: \n\t"
iMTX_MULT("5*16(%0)", MANGLE(iTab4), ROUND(walkenIdctRounders+4*16), PUT_ODD(ROW5))
JZ("%%edx", "1f")
"4: \n\t"
iMTX_MULT("6*16(%0)", MANGLE(iTab3), ROUND(walkenIdctRounders+5*16), PUT_EVEN(ROW6))
JZ("%%esi", "1f")
"5: \n\t"
iMTX_MULT("7*16(%0)", MANGLE(iTab2), ROUND(walkenIdctRounders+5*16), PUT_ODD(ROW7))
#ifndef ARCH_X86_64
iLLM_HEAD
#endif
iLLM_PASS("%0")
"6: \n\t"
: "+r"(block)
:
: "%eax", "%ecx", "%edx", "%esi", "memory");
}
void ff_idct_xvid_sse2_put(uint8_t *dest, int line_size, short *block)
{
ff_idct_xvid_sse2(block);
put_pixels_clamped_mmx(block, dest, line_size);
}
void ff_idct_xvid_sse2_add(uint8_t *dest, int line_size, short *block)
{
ff_idct_xvid_sse2(block);
add_pixels_clamped_mmx(block, dest, line_size);
}
@@ -0,0 +1,35 @@
/*
* XVID MPEG-4 VIDEO CODEC
*
* 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
*/
/*!
* @file idct_xvid.h
* header for Xvid IDCT functions
*/
#ifndef FFMPEG_IDCT_XVID_H
#define FFMPEG_IDCT_XVID_H
void ff_idct_xvid_mmx(short *block);
void ff_idct_xvid_mmx2(short *block);
void ff_idct_xvid_sse2(short *block);
void ff_idct_xvid_sse2_put(uint8_t *dest, int line_size, short *block);
void ff_idct_xvid_sse2_add(uint8_t *dest, int line_size, short *block);
#endif /* FFMPEG_IDCT_XVID_H */
@@ -0,0 +1,45 @@
/*
* simple math operations
* Copyright (c) 2006 Michael Niedermayer <[email protected]> et al
*
* 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
*/
#ifndef FFMPEG_I386_MATHOPS_H
#define FFMPEG_I386_MATHOPS_H
#ifdef FRAC_BITS
# define MULL(ra, rb) \
({ int rt, dummy; asm (\
"imull %3 \n\t"\
"shrdl %4, %%edx, %%eax \n\t"\
: "=a"(rt), "=d"(dummy)\
: "a" (ra), "rm" (rb), "i"(FRAC_BITS));\
rt; })
#endif
#define MULH(ra, rb) \
({ int rt, dummy;\
asm ("imull %3\n\t" : "=d"(rt), "=a"(dummy): "a" (ra), "rm" (rb));\
rt; })
#define MUL64(ra, rb) \
({ int64_t rt;\
asm ("imull %2\n\t" : "=A"(rt) : "a" (ra), "g" (rb));\
rt; })
#endif /* FFMPEG_I386_MATHOPS_H */
@@ -0,0 +1,285 @@
/*
* mmx.h
* Copyright (C) 1997-2001 H. Dietz and R. Fisher
*
* 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
*/
#ifndef FFMPEG_MMX_H
#define FFMPEG_MMX_H
#warning Everything in this header is deprecated, use plain asm()! New code using this header will be rejected.
/*
* The type of an value that fits in an MMX register (note that long
* long constant values MUST be suffixed by LL and unsigned long long
* values by ULL, lest they be truncated by the compiler)
*/
typedef union {
long long q; /* Quadword (64-bit) value */
unsigned long long uq; /* Unsigned Quadword */
int d[2]; /* 2 Doubleword (32-bit) values */
unsigned int ud[2]; /* 2 Unsigned Doubleword */
short w[4]; /* 4 Word (16-bit) values */
unsigned short uw[4]; /* 4 Unsigned Word */
char b[8]; /* 8 Byte (8-bit) values */
unsigned char ub[8]; /* 8 Unsigned Byte */
float s[2]; /* Single-precision (32-bit) value */
} mmx_t; /* On an 8-byte (64-bit) boundary */
#define mmx_i2r(op,imm,reg) \
asm volatile (#op " %0, %%" #reg \
: /* nothing */ \
: "i" (imm) )
#define mmx_m2r(op,mem,reg) \
asm volatile (#op " %0, %%" #reg \
: /* nothing */ \
: "m" (mem))
#define mmx_r2m(op,reg,mem) \
asm volatile (#op " %%" #reg ", %0" \
: "=m" (mem) \
: /* nothing */ )
#define mmx_r2r(op,regs,regd) \
asm volatile (#op " %" #regs ", %" #regd)
#define emms() asm volatile ("emms")
#define movd_m2r(var,reg) mmx_m2r (movd, var, reg)
#define movd_r2m(reg,var) mmx_r2m (movd, reg, var)
#define movd_r2r(regs,regd) mmx_r2r (movd, regs, regd)
#define movq_m2r(var,reg) mmx_m2r (movq, var, reg)
#define movq_r2m(reg,var) mmx_r2m (movq, reg, var)
#define movq_r2r(regs,regd) mmx_r2r (movq, regs, regd)
#define packssdw_m2r(var,reg) mmx_m2r (packssdw, var, reg)
#define packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd)
#define packsswb_m2r(var,reg) mmx_m2r (packsswb, var, reg)
#define packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd)
#define packuswb_m2r(var,reg) mmx_m2r (packuswb, var, reg)
#define packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd)
#define paddb_m2r(var,reg) mmx_m2r (paddb, var, reg)
#define paddb_r2r(regs,regd) mmx_r2r (paddb, regs, regd)
#define paddd_m2r(var,reg) mmx_m2r (paddd, var, reg)
#define paddd_r2r(regs,regd) mmx_r2r (paddd, regs, regd)
#define paddw_m2r(var,reg) mmx_m2r (paddw, var, reg)
#define paddw_r2r(regs,regd) mmx_r2r (paddw, regs, regd)
#define paddsb_m2r(var,reg) mmx_m2r (paddsb, var, reg)
#define paddsb_r2r(regs,regd) mmx_r2r (paddsb, regs, regd)
#define paddsw_m2r(var,reg) mmx_m2r (paddsw, var, reg)
#define paddsw_r2r(regs,regd) mmx_r2r (paddsw, regs, regd)
#define paddusb_m2r(var,reg) mmx_m2r (paddusb, var, reg)
#define paddusb_r2r(regs,regd) mmx_r2r (paddusb, regs, regd)
#define paddusw_m2r(var,reg) mmx_m2r (paddusw, var, reg)
#define paddusw_r2r(regs,regd) mmx_r2r (paddusw, regs, regd)
#define pand_m2r(var,reg) mmx_m2r (pand, var, reg)
#define pand_r2r(regs,regd) mmx_r2r (pand, regs, regd)
#define pandn_m2r(var,reg) mmx_m2r (pandn, var, reg)
#define pandn_r2r(regs,regd) mmx_r2r (pandn, regs, regd)
#define pcmpeqb_m2r(var,reg) mmx_m2r (pcmpeqb, var, reg)
#define pcmpeqb_r2r(regs,regd) mmx_r2r (pcmpeqb, regs, regd)
#define pcmpeqd_m2r(var,reg) mmx_m2r (pcmpeqd, var, reg)
#define pcmpeqd_r2r(regs,regd) mmx_r2r (pcmpeqd, regs, regd)
#define pcmpeqw_m2r(var,reg) mmx_m2r (pcmpeqw, var, reg)
#define pcmpeqw_r2r(regs,regd) mmx_r2r (pcmpeqw, regs, regd)
#define pcmpgtb_m2r(var,reg) mmx_m2r (pcmpgtb, var, reg)
#define pcmpgtb_r2r(regs,regd) mmx_r2r (pcmpgtb, regs, regd)
#define pcmpgtd_m2r(var,reg) mmx_m2r (pcmpgtd, var, reg)
#define pcmpgtd_r2r(regs,regd) mmx_r2r (pcmpgtd, regs, regd)
#define pcmpgtw_m2r(var,reg) mmx_m2r (pcmpgtw, var, reg)
#define pcmpgtw_r2r(regs,regd) mmx_r2r (pcmpgtw, regs, regd)
#define pmaddwd_m2r(var,reg) mmx_m2r (pmaddwd, var, reg)
#define pmaddwd_r2r(regs,regd) mmx_r2r (pmaddwd, regs, regd)
#define pmulhw_m2r(var,reg) mmx_m2r (pmulhw, var, reg)
#define pmulhw_r2r(regs,regd) mmx_r2r (pmulhw, regs, regd)
#define pmullw_m2r(var,reg) mmx_m2r (pmullw, var, reg)
#define pmullw_r2r(regs,regd) mmx_r2r (pmullw, regs, regd)
#define por_m2r(var,reg) mmx_m2r (por, var, reg)
#define por_r2r(regs,regd) mmx_r2r (por, regs, regd)
#define pslld_i2r(imm,reg) mmx_i2r (pslld, imm, reg)
#define pslld_m2r(var,reg) mmx_m2r (pslld, var, reg)
#define pslld_r2r(regs,regd) mmx_r2r (pslld, regs, regd)
#define psllq_i2r(imm,reg) mmx_i2r (psllq, imm, reg)
#define psllq_m2r(var,reg) mmx_m2r (psllq, var, reg)
#define psllq_r2r(regs,regd) mmx_r2r (psllq, regs, regd)
#define psllw_i2r(imm,reg) mmx_i2r (psllw, imm, reg)
#define psllw_m2r(var,reg) mmx_m2r (psllw, var, reg)
#define psllw_r2r(regs,regd) mmx_r2r (psllw, regs, regd)
#define psrad_i2r(imm,reg) mmx_i2r (psrad, imm, reg)
#define psrad_m2r(var,reg) mmx_m2r (psrad, var, reg)
#define psrad_r2r(regs,regd) mmx_r2r (psrad, regs, regd)
#define psraw_i2r(imm,reg) mmx_i2r (psraw, imm, reg)
#define psraw_m2r(var,reg) mmx_m2r (psraw, var, reg)
#define psraw_r2r(regs,regd) mmx_r2r (psraw, regs, regd)
#define psrld_i2r(imm,reg) mmx_i2r (psrld, imm, reg)
#define psrld_m2r(var,reg) mmx_m2r (psrld, var, reg)
#define psrld_r2r(regs,regd) mmx_r2r (psrld, regs, regd)
#define psrlq_i2r(imm,reg) mmx_i2r (psrlq, imm, reg)
#define psrlq_m2r(var,reg) mmx_m2r (psrlq, var, reg)
#define psrlq_r2r(regs,regd) mmx_r2r (psrlq, regs, regd)
#define psrlw_i2r(imm,reg) mmx_i2r (psrlw, imm, reg)
#define psrlw_m2r(var,reg) mmx_m2r (psrlw, var, reg)
#define psrlw_r2r(regs,regd) mmx_r2r (psrlw, regs, regd)
#define psubb_m2r(var,reg) mmx_m2r (psubb, var, reg)
#define psubb_r2r(regs,regd) mmx_r2r (psubb, regs, regd)
#define psubd_m2r(var,reg) mmx_m2r (psubd, var, reg)
#define psubd_r2r(regs,regd) mmx_r2r (psubd, regs, regd)
#define psubw_m2r(var,reg) mmx_m2r (psubw, var, reg)
#define psubw_r2r(regs,regd) mmx_r2r (psubw, regs, regd)
#define psubsb_m2r(var,reg) mmx_m2r (psubsb, var, reg)
#define psubsb_r2r(regs,regd) mmx_r2r (psubsb, regs, regd)
#define psubsw_m2r(var,reg) mmx_m2r (psubsw, var, reg)
#define psubsw_r2r(regs,regd) mmx_r2r (psubsw, regs, regd)
#define psubusb_m2r(var,reg) mmx_m2r (psubusb, var, reg)
#define psubusb_r2r(regs,regd) mmx_r2r (psubusb, regs, regd)
#define psubusw_m2r(var,reg) mmx_m2r (psubusw, var, reg)
#define psubusw_r2r(regs,regd) mmx_r2r (psubusw, regs, regd)
#define punpckhbw_m2r(var,reg) mmx_m2r (punpckhbw, var, reg)
#define punpckhbw_r2r(regs,regd) mmx_r2r (punpckhbw, regs, regd)
#define punpckhdq_m2r(var,reg) mmx_m2r (punpckhdq, var, reg)
#define punpckhdq_r2r(regs,regd) mmx_r2r (punpckhdq, regs, regd)
#define punpckhwd_m2r(var,reg) mmx_m2r (punpckhwd, var, reg)
#define punpckhwd_r2r(regs,regd) mmx_r2r (punpckhwd, regs, regd)
#define punpcklbw_m2r(var,reg) mmx_m2r (punpcklbw, var, reg)
#define punpcklbw_r2r(regs,regd) mmx_r2r (punpcklbw, regs, regd)
#define punpckldq_m2r(var,reg) mmx_m2r (punpckldq, var, reg)
#define punpckldq_r2r(regs,regd) mmx_r2r (punpckldq, regs, regd)
#define punpcklwd_m2r(var,reg) mmx_m2r (punpcklwd, var, reg)
#define punpcklwd_r2r(regs,regd) mmx_r2r (punpcklwd, regs, regd)
#define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg)
#define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd)
/* 3DNOW extensions */
#define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg)
#define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd)
/* AMD MMX extensions - also available in intel SSE */
#define mmx_m2ri(op,mem,reg,imm) \
asm volatile (#op " %1, %0, %%" #reg \
: /* nothing */ \
: "m" (mem), "i" (imm))
#define mmx_r2ri(op,regs,regd,imm) \
asm volatile (#op " %0, %%" #regs ", %%" #regd \
: /* nothing */ \
: "i" (imm) )
#define mmx_fetch(mem,hint) \
asm volatile ("prefetch" #hint " %0" \
: /* nothing */ \
: "m" (mem))
#define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg)
#define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var)
#define pavgb_m2r(var,reg) mmx_m2r (pavgb, var, reg)
#define pavgb_r2r(regs,regd) mmx_r2r (pavgb, regs, regd)
#define pavgw_m2r(var,reg) mmx_m2r (pavgw, var, reg)
#define pavgw_r2r(regs,regd) mmx_r2r (pavgw, regs, regd)
#define pextrw_r2r(mmreg,reg,imm) mmx_r2ri (pextrw, mmreg, reg, imm)
#define pinsrw_r2r(reg,mmreg,imm) mmx_r2ri (pinsrw, reg, mmreg, imm)
#define pmaxsw_m2r(var,reg) mmx_m2r (pmaxsw, var, reg)
#define pmaxsw_r2r(regs,regd) mmx_r2r (pmaxsw, regs, regd)
#define pmaxub_m2r(var,reg) mmx_m2r (pmaxub, var, reg)
#define pmaxub_r2r(regs,regd) mmx_r2r (pmaxub, regs, regd)
#define pminsw_m2r(var,reg) mmx_m2r (pminsw, var, reg)
#define pminsw_r2r(regs,regd) mmx_r2r (pminsw, regs, regd)
#define pminub_m2r(var,reg) mmx_m2r (pminub, var, reg)
#define pminub_r2r(regs,regd) mmx_r2r (pminub, regs, regd)
#define pmovmskb(mmreg,reg) \
asm volatile ("movmskps %" #mmreg ", %" #reg)
#define pmulhuw_m2r(var,reg) mmx_m2r (pmulhuw, var, reg)
#define pmulhuw_r2r(regs,regd) mmx_r2r (pmulhuw, regs, regd)
#define prefetcht0(mem) mmx_fetch (mem, t0)
#define prefetcht1(mem) mmx_fetch (mem, t1)
#define prefetcht2(mem) mmx_fetch (mem, t2)
#define prefetchnta(mem) mmx_fetch (mem, nta)
#define psadbw_m2r(var,reg) mmx_m2r (psadbw, var, reg)
#define psadbw_r2r(regs,regd) mmx_r2r (psadbw, regs, regd)
#define pshufw_m2r(var,reg,imm) mmx_m2ri(pshufw, var, reg, imm)
#define pshufw_r2r(regs,regd,imm) mmx_r2ri(pshufw, regs, regd, imm)
#define sfence() asm volatile ("sfence\n\t")
/* SSE2 */
#define pshufhw_m2r(var,reg,imm) mmx_m2ri(pshufhw, var, reg, imm)
#define pshufhw_r2r(regs,regd,imm) mmx_r2ri(pshufhw, regs, regd, imm)
#define pshuflw_m2r(var,reg,imm) mmx_m2ri(pshuflw, var, reg, imm)
#define pshuflw_r2r(regs,regd,imm) mmx_r2ri(pshuflw, regs, regd, imm)
#define pshufd_r2r(regs,regd,imm) mmx_r2ri(pshufd, regs, regd, imm)
#define movdqa_m2r(var,reg) mmx_m2r (movdqa, var, reg)
#define movdqa_r2m(reg,var) mmx_r2m (movdqa, reg, var)
#define movdqa_r2r(regs,regd) mmx_r2r (movdqa, regs, regd)
#define movdqu_m2r(var,reg) mmx_m2r (movdqu, var, reg)
#define movdqu_r2m(reg,var) mmx_r2m (movdqu, reg, var)
#define movdqu_r2r(regs,regd) mmx_r2r (movdqu, regs, regd)
#define pmullw_r2m(reg,var) mmx_r2m (pmullw, reg, var)
#define pslldq_i2r(imm,reg) mmx_i2r (pslldq, imm, reg)
#define psrldq_i2r(imm,reg) mmx_i2r (psrldq, imm, reg)
#define punpcklqdq_r2r(regs,regd) mmx_r2r (punpcklqdq, regs, regd)
#define punpckhqdq_r2r(regs,regd) mmx_r2r (punpckhqdq, regs, regd)
#endif /* FFMPEG_MMX_H */
@@ -0,0 +1,461 @@
/*
* MMX optimized motion estimation
* Copyright (c) 2001 Fabrice Bellard.
* Copyright (c) 2002-2004 Michael Niedermayer
*
* mostly by Michael Niedermayer <[email protected]>
*
* 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/x86_cpu.h"
#include "libavcodec/dsputil.h"
DECLARE_ASM_CONST(8, uint64_t, round_tab[3])={
0x0000000000000000ULL,
0x0001000100010001ULL,
0x0002000200020002ULL,
};
DECLARE_ASM_CONST(8, uint64_t, bone)= 0x0101010101010101LL;
static inline void sad8_1_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
{
x86_reg len= -(stride*h);
asm volatile(
ASMALIGN(4)
"1: \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"movq (%2, %%"REG_a"), %%mm2 \n\t"
"movq (%2, %%"REG_a"), %%mm4 \n\t"
"add %3, %%"REG_a" \n\t"
"psubusb %%mm0, %%mm2 \n\t"
"psubusb %%mm4, %%mm0 \n\t"
"movq (%1, %%"REG_a"), %%mm1 \n\t"
"movq (%2, %%"REG_a"), %%mm3 \n\t"
"movq (%2, %%"REG_a"), %%mm5 \n\t"
"psubusb %%mm1, %%mm3 \n\t"
"psubusb %%mm5, %%mm1 \n\t"
"por %%mm2, %%mm0 \n\t"
"por %%mm1, %%mm3 \n\t"
"movq %%mm0, %%mm1 \n\t"
"movq %%mm3, %%mm2 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpckhbw %%mm7, %%mm1 \n\t"
"punpcklbw %%mm7, %%mm3 \n\t"
"punpckhbw %%mm7, %%mm2 \n\t"
"paddw %%mm1, %%mm0 \n\t"
"paddw %%mm3, %%mm2 \n\t"
"paddw %%mm2, %%mm0 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"add %3, %%"REG_a" \n\t"
" js 1b \n\t"
: "+a" (len)
: "r" (blk1 - len), "r" (blk2 - len), "r" ((x86_reg)stride)
);
}
static inline void sad8_1_mmx2(uint8_t *blk1, uint8_t *blk2, int stride, int h)
{
asm volatile(
ASMALIGN(4)
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm1 \n\t"
"psadbw (%2), %%mm0 \n\t"
"psadbw (%2, %3), %%mm1 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"paddw %%mm1, %%mm6 \n\t"
"lea (%1,%3,2), %1 \n\t"
"lea (%2,%3,2), %2 \n\t"
"sub $2, %0 \n\t"
" jg 1b \n\t"
: "+r" (h), "+r" (blk1), "+r" (blk2)
: "r" ((x86_reg)stride)
);
}
static int sad16_sse2(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)
{
int ret;
asm volatile(
"pxor %%xmm6, %%xmm6 \n\t"
ASMALIGN(4)
"1: \n\t"
"movdqu (%1), %%xmm0 \n\t"
"movdqu (%1, %3), %%xmm1 \n\t"
"psadbw (%2), %%xmm0 \n\t"
"psadbw (%2, %3), %%xmm1 \n\t"
"paddw %%xmm0, %%xmm6 \n\t"
"paddw %%xmm1, %%xmm6 \n\t"
"lea (%1,%3,2), %1 \n\t"
"lea (%2,%3,2), %2 \n\t"
"sub $2, %0 \n\t"
" jg 1b \n\t"
: "+r" (h), "+r" (blk1), "+r" (blk2)
: "r" ((x86_reg)stride)
);
asm volatile(
"movhlps %%xmm6, %%xmm0 \n\t"
"paddw %%xmm0, %%xmm6 \n\t"
"movd %%xmm6, %0 \n\t"
: "=r"(ret)
);
return ret;
}
static inline void sad8_x2a_mmx2(uint8_t *blk1, uint8_t *blk2, int stride, int h)
{
asm volatile(
ASMALIGN(4)
"1: \n\t"
"movq (%1), %%mm0 \n\t"
"movq (%1, %3), %%mm1 \n\t"
"pavgb 1(%1), %%mm0 \n\t"
"pavgb 1(%1, %3), %%mm1 \n\t"
"psadbw (%2), %%mm0 \n\t"
"psadbw (%2, %3), %%mm1 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"paddw %%mm1, %%mm6 \n\t"
"lea (%1,%3,2), %1 \n\t"
"lea (%2,%3,2), %2 \n\t"
"sub $2, %0 \n\t"
" jg 1b \n\t"
: "+r" (h), "+r" (blk1), "+r" (blk2)
: "r" ((x86_reg)stride)
);
}
static inline void sad8_y2a_mmx2(uint8_t *blk1, uint8_t *blk2, int stride, int h)
{
asm volatile(
"movq (%1), %%mm0 \n\t"
"add %3, %1 \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%1), %%mm1 \n\t"
"movq (%1, %3), %%mm2 \n\t"
"pavgb %%mm1, %%mm0 \n\t"
"pavgb %%mm2, %%mm1 \n\t"
"psadbw (%2), %%mm0 \n\t"
"psadbw (%2, %3), %%mm1 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"paddw %%mm1, %%mm6 \n\t"
"movq %%mm2, %%mm0 \n\t"
"lea (%1,%3,2), %1 \n\t"
"lea (%2,%3,2), %2 \n\t"
"sub $2, %0 \n\t"
" jg 1b \n\t"
: "+r" (h), "+r" (blk1), "+r" (blk2)
: "r" ((x86_reg)stride)
);
}
static inline void sad8_4_mmx2(uint8_t *blk1, uint8_t *blk2, int stride, int h)
{
asm volatile(
"movq "MANGLE(bone)", %%mm5 \n\t"
"movq (%1), %%mm0 \n\t"
"pavgb 1(%1), %%mm0 \n\t"
"add %3, %1 \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%1), %%mm1 \n\t"
"movq (%1,%3), %%mm2 \n\t"
"pavgb 1(%1), %%mm1 \n\t"
"pavgb 1(%1,%3), %%mm2 \n\t"
"psubusb %%mm5, %%mm1 \n\t"
"pavgb %%mm1, %%mm0 \n\t"
"pavgb %%mm2, %%mm1 \n\t"
"psadbw (%2), %%mm0 \n\t"
"psadbw (%2,%3), %%mm1 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"paddw %%mm1, %%mm6 \n\t"
"movq %%mm2, %%mm0 \n\t"
"lea (%1,%3,2), %1 \n\t"
"lea (%2,%3,2), %2 \n\t"
"sub $2, %0 \n\t"
" jg 1b \n\t"
: "+r" (h), "+r" (blk1), "+r" (blk2)
: "r" ((x86_reg)stride)
);
}
static inline void sad8_2_mmx(uint8_t *blk1a, uint8_t *blk1b, uint8_t *blk2, int stride, int h)
{
x86_reg len= -(stride*h);
asm volatile(
ASMALIGN(4)
"1: \n\t"
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"movq (%2, %%"REG_a"), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm2 \n\t"
"movq (%2, %%"REG_a"), %%mm3 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpcklbw %%mm7, %%mm1 \n\t"
"punpckhbw %%mm7, %%mm2 \n\t"
"punpckhbw %%mm7, %%mm3 \n\t"
"paddw %%mm0, %%mm1 \n\t"
"paddw %%mm2, %%mm3 \n\t"
"movq (%3, %%"REG_a"), %%mm4 \n\t"
"movq (%3, %%"REG_a"), %%mm2 \n\t"
"paddw %%mm5, %%mm1 \n\t"
"paddw %%mm5, %%mm3 \n\t"
"psrlw $1, %%mm1 \n\t"
"psrlw $1, %%mm3 \n\t"
"packuswb %%mm3, %%mm1 \n\t"
"psubusb %%mm1, %%mm4 \n\t"
"psubusb %%mm2, %%mm1 \n\t"
"por %%mm4, %%mm1 \n\t"
"movq %%mm1, %%mm0 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpckhbw %%mm7, %%mm1 \n\t"
"paddw %%mm1, %%mm0 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"add %4, %%"REG_a" \n\t"
" js 1b \n\t"
: "+a" (len)
: "r" (blk1a - len), "r" (blk1b -len), "r" (blk2 - len), "r" ((x86_reg)stride)
);
}
static inline void sad8_4_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
{
x86_reg len= -(stride*h);
asm volatile(
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"movq 1(%1, %%"REG_a"), %%mm2 \n\t"
"movq %%mm0, %%mm1 \n\t"
"movq %%mm2, %%mm3 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpckhbw %%mm7, %%mm1 \n\t"
"punpcklbw %%mm7, %%mm2 \n\t"
"punpckhbw %%mm7, %%mm3 \n\t"
"paddw %%mm2, %%mm0 \n\t"
"paddw %%mm3, %%mm1 \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%2, %%"REG_a"), %%mm2 \n\t"
"movq 1(%2, %%"REG_a"), %%mm4 \n\t"
"movq %%mm2, %%mm3 \n\t"
"movq %%mm4, %%mm5 \n\t"
"punpcklbw %%mm7, %%mm2 \n\t"
"punpckhbw %%mm7, %%mm3 \n\t"
"punpcklbw %%mm7, %%mm4 \n\t"
"punpckhbw %%mm7, %%mm5 \n\t"
"paddw %%mm4, %%mm2 \n\t"
"paddw %%mm5, %%mm3 \n\t"
"movq 16+"MANGLE(round_tab)", %%mm5 \n\t"
"paddw %%mm2, %%mm0 \n\t"
"paddw %%mm3, %%mm1 \n\t"
"paddw %%mm5, %%mm0 \n\t"
"paddw %%mm5, %%mm1 \n\t"
"movq (%3, %%"REG_a"), %%mm4 \n\t"
"movq (%3, %%"REG_a"), %%mm5 \n\t"
"psrlw $2, %%mm0 \n\t"
"psrlw $2, %%mm1 \n\t"
"packuswb %%mm1, %%mm0 \n\t"
"psubusb %%mm0, %%mm4 \n\t"
"psubusb %%mm5, %%mm0 \n\t"
"por %%mm4, %%mm0 \n\t"
"movq %%mm0, %%mm4 \n\t"
"punpcklbw %%mm7, %%mm0 \n\t"
"punpckhbw %%mm7, %%mm4 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"paddw %%mm4, %%mm6 \n\t"
"movq %%mm2, %%mm0 \n\t"
"movq %%mm3, %%mm1 \n\t"
"add %4, %%"REG_a" \n\t"
" js 1b \n\t"
: "+a" (len)
: "r" (blk1 - len), "r" (blk1 -len + stride), "r" (blk2 - len), "r" ((x86_reg)stride)
);
}
static inline int sum_mmx(void)
{
int ret;
asm volatile(
"movq %%mm6, %%mm0 \n\t"
"psrlq $32, %%mm6 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"movq %%mm6, %%mm0 \n\t"
"psrlq $16, %%mm6 \n\t"
"paddw %%mm0, %%mm6 \n\t"
"movd %%mm6, %0 \n\t"
: "=r" (ret)
);
return ret&0xFFFF;
}
static inline int sum_mmx2(void)
{
int ret;
asm volatile(
"movd %%mm6, %0 \n\t"
: "=r" (ret)
);
return ret;
}
static inline void sad8_x2a_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
{
sad8_2_mmx(blk1, blk1+1, blk2, stride, h);
}
static inline void sad8_y2a_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
{
sad8_2_mmx(blk1, blk1+stride, blk2, stride, h);
}
#define PIX_SAD(suf)\
static int sad8_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
{\
assert(h==8);\
asm volatile("pxor %%mm7, %%mm7 \n\t"\
"pxor %%mm6, %%mm6 \n\t":);\
\
sad8_1_ ## suf(blk1, blk2, stride, 8);\
\
return sum_ ## suf();\
}\
static int sad8_x2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
{\
assert(h==8);\
asm volatile("pxor %%mm7, %%mm7 \n\t"\
"pxor %%mm6, %%mm6 \n\t"\
"movq %0, %%mm5 \n\t"\
:: "m"(round_tab[1]) \
);\
\
sad8_x2a_ ## suf(blk1, blk2, stride, 8);\
\
return sum_ ## suf();\
}\
\
static int sad8_y2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
{\
assert(h==8);\
asm volatile("pxor %%mm7, %%mm7 \n\t"\
"pxor %%mm6, %%mm6 \n\t"\
"movq %0, %%mm5 \n\t"\
:: "m"(round_tab[1]) \
);\
\
sad8_y2a_ ## suf(blk1, blk2, stride, 8);\
\
return sum_ ## suf();\
}\
\
static int sad8_xy2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
{\
assert(h==8);\
asm volatile("pxor %%mm7, %%mm7 \n\t"\
"pxor %%mm6, %%mm6 \n\t"\
::);\
\
sad8_4_ ## suf(blk1, blk2, stride, 8);\
\
return sum_ ## suf();\
}\
\
static int sad16_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
{\
asm volatile("pxor %%mm7, %%mm7 \n\t"\
"pxor %%mm6, %%mm6 \n\t":);\
\
sad8_1_ ## suf(blk1 , blk2 , stride, h);\
sad8_1_ ## suf(blk1+8, blk2+8, stride, h);\
\
return sum_ ## suf();\
}\
static int sad16_x2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
{\
asm volatile("pxor %%mm7, %%mm7 \n\t"\
"pxor %%mm6, %%mm6 \n\t"\
"movq %0, %%mm5 \n\t"\
:: "m"(round_tab[1]) \
);\
\
sad8_x2a_ ## suf(blk1 , blk2 , stride, h);\
sad8_x2a_ ## suf(blk1+8, blk2+8, stride, h);\
\
return sum_ ## suf();\
}\
static int sad16_y2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
{\
asm volatile("pxor %%mm7, %%mm7 \n\t"\
"pxor %%mm6, %%mm6 \n\t"\
"movq %0, %%mm5 \n\t"\
:: "m"(round_tab[1]) \
);\
\
sad8_y2a_ ## suf(blk1 , blk2 , stride, h);\
sad8_y2a_ ## suf(blk1+8, blk2+8, stride, h);\
\
return sum_ ## suf();\
}\
static int sad16_xy2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
{\
asm volatile("pxor %%mm7, %%mm7 \n\t"\
"pxor %%mm6, %%mm6 \n\t"\
::);\
\
sad8_4_ ## suf(blk1 , blk2 , stride, h);\
sad8_4_ ## suf(blk1+8, blk2+8, stride, h);\
\
return sum_ ## suf();\
}\
PIX_SAD(mmx)
PIX_SAD(mmx2)
void dsputil_init_pix_mmx(DSPContext* c, AVCodecContext *avctx)
{
if (mm_flags & MM_MMX) {
c->pix_abs[0][0] = sad16_mmx;
c->pix_abs[0][1] = sad16_x2_mmx;
c->pix_abs[0][2] = sad16_y2_mmx;
c->pix_abs[0][3] = sad16_xy2_mmx;
c->pix_abs[1][0] = sad8_mmx;
c->pix_abs[1][1] = sad8_x2_mmx;
c->pix_abs[1][2] = sad8_y2_mmx;
c->pix_abs[1][3] = sad8_xy2_mmx;
c->sad[0]= sad16_mmx;
c->sad[1]= sad8_mmx;
}
if (mm_flags & MM_MMXEXT) {
c->pix_abs[0][0] = sad16_mmx2;
c->pix_abs[1][0] = sad8_mmx2;
c->sad[0]= sad16_mmx2;
c->sad[1]= sad8_mmx2;
if(!(avctx->flags & CODEC_FLAG_BITEXACT)){
c->pix_abs[0][1] = sad16_x2_mmx2;
c->pix_abs[0][2] = sad16_y2_mmx2;
c->pix_abs[0][3] = sad16_xy2_mmx2;
c->pix_abs[1][1] = sad8_x2_mmx2;
c->pix_abs[1][2] = sad8_y2_mmx2;
c->pix_abs[1][3] = sad8_xy2_mmx2;
}
}
if ((mm_flags & MM_SSE2) && !(mm_flags & MM_3DNOW)) {
c->sad[0]= sad16_sse2;
}
}
@@ -0,0 +1,654 @@
/*
* The simplest mpeg encoder (well, it was the simplest!)
* Copyright (c) 2000,2001 Fabrice Bellard.
*
* Optimized for ia32 CPUs by Nick Kurshev <[email protected]>
* h263, mpeg1, mpeg2 dequantizer & draw_edges by Michael Niedermayer <[email protected]>
*
* 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/x86_cpu.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/dsputil.h"
#include "libavcodec/mpegvideo.h"
#include "dsputil_mmx.h"
extern uint16_t inv_zigzag_direct16[64];
static void dct_unquantize_h263_intra_mmx(MpegEncContext *s,
DCTELEM *block, int n, int qscale)
{
x86_reg level, qmul, qadd, nCoeffs;
qmul = qscale << 1;
assert(s->block_last_index[n]>=0 || s->h263_aic);
if (!s->h263_aic) {
if (n < 4)
level = block[0] * s->y_dc_scale;
else
level = block[0] * s->c_dc_scale;
qadd = (qscale - 1) | 1;
}else{
qadd = 0;
level= block[0];
}
if(s->ac_pred)
nCoeffs=63;
else
nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ];
//printf("%d %d ", qmul, qadd);
asm volatile(
"movd %1, %%mm6 \n\t" //qmul
"packssdw %%mm6, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"movd %2, %%mm5 \n\t" //qadd
"pxor %%mm7, %%mm7 \n\t"
"packssdw %%mm5, %%mm5 \n\t"
"packssdw %%mm5, %%mm5 \n\t"
"psubw %%mm5, %%mm7 \n\t"
"pxor %%mm4, %%mm4 \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%0, %3), %%mm0 \n\t"
"movq 8(%0, %3), %%mm1 \n\t"
"pmullw %%mm6, %%mm0 \n\t"
"pmullw %%mm6, %%mm1 \n\t"
"movq (%0, %3), %%mm2 \n\t"
"movq 8(%0, %3), %%mm3 \n\t"
"pcmpgtw %%mm4, %%mm2 \n\t" // block[i] < 0 ? -1 : 0
"pcmpgtw %%mm4, %%mm3 \n\t" // block[i] < 0 ? -1 : 0
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"paddw %%mm7, %%mm0 \n\t"
"paddw %%mm7, %%mm1 \n\t"
"pxor %%mm0, %%mm2 \n\t"
"pxor %%mm1, %%mm3 \n\t"
"pcmpeqw %%mm7, %%mm0 \n\t" // block[i] == 0 ? -1 : 0
"pcmpeqw %%mm7, %%mm1 \n\t" // block[i] == 0 ? -1 : 0
"pandn %%mm2, %%mm0 \n\t"
"pandn %%mm3, %%mm1 \n\t"
"movq %%mm0, (%0, %3) \n\t"
"movq %%mm1, 8(%0, %3) \n\t"
"add $16, %3 \n\t"
"jng 1b \n\t"
::"r" (block+nCoeffs), "rm"(qmul), "rm" (qadd), "r" (2*(-nCoeffs))
: "memory"
);
block[0]= level;
}
static void dct_unquantize_h263_inter_mmx(MpegEncContext *s,
DCTELEM *block, int n, int qscale)
{
x86_reg qmul, qadd, nCoeffs;
qmul = qscale << 1;
qadd = (qscale - 1) | 1;
assert(s->block_last_index[n]>=0 || s->h263_aic);
nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ];
//printf("%d %d ", qmul, qadd);
asm volatile(
"movd %1, %%mm6 \n\t" //qmul
"packssdw %%mm6, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"movd %2, %%mm5 \n\t" //qadd
"pxor %%mm7, %%mm7 \n\t"
"packssdw %%mm5, %%mm5 \n\t"
"packssdw %%mm5, %%mm5 \n\t"
"psubw %%mm5, %%mm7 \n\t"
"pxor %%mm4, %%mm4 \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%0, %3), %%mm0 \n\t"
"movq 8(%0, %3), %%mm1 \n\t"
"pmullw %%mm6, %%mm0 \n\t"
"pmullw %%mm6, %%mm1 \n\t"
"movq (%0, %3), %%mm2 \n\t"
"movq 8(%0, %3), %%mm3 \n\t"
"pcmpgtw %%mm4, %%mm2 \n\t" // block[i] < 0 ? -1 : 0
"pcmpgtw %%mm4, %%mm3 \n\t" // block[i] < 0 ? -1 : 0
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"paddw %%mm7, %%mm0 \n\t"
"paddw %%mm7, %%mm1 \n\t"
"pxor %%mm0, %%mm2 \n\t"
"pxor %%mm1, %%mm3 \n\t"
"pcmpeqw %%mm7, %%mm0 \n\t" // block[i] == 0 ? -1 : 0
"pcmpeqw %%mm7, %%mm1 \n\t" // block[i] == 0 ? -1 : 0
"pandn %%mm2, %%mm0 \n\t"
"pandn %%mm3, %%mm1 \n\t"
"movq %%mm0, (%0, %3) \n\t"
"movq %%mm1, 8(%0, %3) \n\t"
"add $16, %3 \n\t"
"jng 1b \n\t"
::"r" (block+nCoeffs), "rm"(qmul), "rm" (qadd), "r" (2*(-nCoeffs))
: "memory"
);
}
/*
NK:
Note: looking at PARANOID:
"enable all paranoid tests for rounding, overflows, etc..."
#ifdef PARANOID
if (level < -2048 || level > 2047)
fprintf(stderr, "unquant error %d %d\n", i, level);
#endif
We can suppose that result of two multiplications can't be greater than 0xFFFF
i.e. is 16-bit, so we use here only PMULLW instruction and can avoid
a complex multiplication.
=====================================================
Full formula for multiplication of 2 integer numbers
which are represent as high:low words:
input: value1 = high1:low1
value2 = high2:low2
output: value3 = value1*value2
value3=high3:low3 (on overflow: modulus 2^32 wrap-around)
this mean that for 0x123456 * 0x123456 correct result is 0x766cb0ce4
but this algorithm will compute only 0x66cb0ce4
this limited by 16-bit size of operands
---------------------------------
tlow1 = high1*low2
tlow2 = high2*low1
tlow1 = tlow1 + tlow2
high3:low3 = low1*low2
high3 += tlow1
*/
static void dct_unquantize_mpeg1_intra_mmx(MpegEncContext *s,
DCTELEM *block, int n, int qscale)
{
x86_reg nCoeffs;
const uint16_t *quant_matrix;
int block0;
assert(s->block_last_index[n]>=0);
nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1;
if (n < 4)
block0 = block[0] * s->y_dc_scale;
else
block0 = block[0] * s->c_dc_scale;
/* XXX: only mpeg1 */
quant_matrix = s->intra_matrix;
asm volatile(
"pcmpeqw %%mm7, %%mm7 \n\t"
"psrlw $15, %%mm7 \n\t"
"movd %2, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"mov %3, %%"REG_a" \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%0, %%"REG_a"), %%mm0 \n\t"
"movq 8(%0, %%"REG_a"), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm4 \n\t"
"movq 8(%1, %%"REG_a"), %%mm5 \n\t"
"pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i]
"pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i]
"pxor %%mm2, %%mm2 \n\t"
"pxor %%mm3, %%mm3 \n\t"
"pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0
"pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"psubw %%mm2, %%mm0 \n\t" // abs(block[i])
"psubw %%mm3, %%mm1 \n\t" // abs(block[i])
"pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*q
"pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*q
"pxor %%mm4, %%mm4 \n\t"
"pxor %%mm5, %%mm5 \n\t" // FIXME slow
"pcmpeqw (%0, %%"REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0
"pcmpeqw 8(%0, %%"REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0
"psraw $3, %%mm0 \n\t"
"psraw $3, %%mm1 \n\t"
"psubw %%mm7, %%mm0 \n\t"
"psubw %%mm7, %%mm1 \n\t"
"por %%mm7, %%mm0 \n\t"
"por %%mm7, %%mm1 \n\t"
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"psubw %%mm2, %%mm0 \n\t"
"psubw %%mm3, %%mm1 \n\t"
"pandn %%mm0, %%mm4 \n\t"
"pandn %%mm1, %%mm5 \n\t"
"movq %%mm4, (%0, %%"REG_a") \n\t"
"movq %%mm5, 8(%0, %%"REG_a") \n\t"
"add $16, %%"REG_a" \n\t"
"js 1b \n\t"
::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs)
: "%"REG_a, "memory"
);
block[0]= block0;
}
static void dct_unquantize_mpeg1_inter_mmx(MpegEncContext *s,
DCTELEM *block, int n, int qscale)
{
x86_reg nCoeffs;
const uint16_t *quant_matrix;
assert(s->block_last_index[n]>=0);
nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1;
quant_matrix = s->inter_matrix;
asm volatile(
"pcmpeqw %%mm7, %%mm7 \n\t"
"psrlw $15, %%mm7 \n\t"
"movd %2, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"mov %3, %%"REG_a" \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%0, %%"REG_a"), %%mm0 \n\t"
"movq 8(%0, %%"REG_a"), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm4 \n\t"
"movq 8(%1, %%"REG_a"), %%mm5 \n\t"
"pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i]
"pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i]
"pxor %%mm2, %%mm2 \n\t"
"pxor %%mm3, %%mm3 \n\t"
"pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0
"pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"psubw %%mm2, %%mm0 \n\t" // abs(block[i])
"psubw %%mm3, %%mm1 \n\t" // abs(block[i])
"paddw %%mm0, %%mm0 \n\t" // abs(block[i])*2
"paddw %%mm1, %%mm1 \n\t" // abs(block[i])*2
"paddw %%mm7, %%mm0 \n\t" // abs(block[i])*2 + 1
"paddw %%mm7, %%mm1 \n\t" // abs(block[i])*2 + 1
"pmullw %%mm4, %%mm0 \n\t" // (abs(block[i])*2 + 1)*q
"pmullw %%mm5, %%mm1 \n\t" // (abs(block[i])*2 + 1)*q
"pxor %%mm4, %%mm4 \n\t"
"pxor %%mm5, %%mm5 \n\t" // FIXME slow
"pcmpeqw (%0, %%"REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0
"pcmpeqw 8(%0, %%"REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0
"psraw $4, %%mm0 \n\t"
"psraw $4, %%mm1 \n\t"
"psubw %%mm7, %%mm0 \n\t"
"psubw %%mm7, %%mm1 \n\t"
"por %%mm7, %%mm0 \n\t"
"por %%mm7, %%mm1 \n\t"
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"psubw %%mm2, %%mm0 \n\t"
"psubw %%mm3, %%mm1 \n\t"
"pandn %%mm0, %%mm4 \n\t"
"pandn %%mm1, %%mm5 \n\t"
"movq %%mm4, (%0, %%"REG_a") \n\t"
"movq %%mm5, 8(%0, %%"REG_a") \n\t"
"add $16, %%"REG_a" \n\t"
"js 1b \n\t"
::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs)
: "%"REG_a, "memory"
);
}
static void dct_unquantize_mpeg2_intra_mmx(MpegEncContext *s,
DCTELEM *block, int n, int qscale)
{
x86_reg nCoeffs;
const uint16_t *quant_matrix;
int block0;
assert(s->block_last_index[n]>=0);
if(s->alternate_scan) nCoeffs= 63; //FIXME
else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ];
if (n < 4)
block0 = block[0] * s->y_dc_scale;
else
block0 = block[0] * s->c_dc_scale;
quant_matrix = s->intra_matrix;
asm volatile(
"pcmpeqw %%mm7, %%mm7 \n\t"
"psrlw $15, %%mm7 \n\t"
"movd %2, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"mov %3, %%"REG_a" \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%0, %%"REG_a"), %%mm0 \n\t"
"movq 8(%0, %%"REG_a"), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm4 \n\t"
"movq 8(%1, %%"REG_a"), %%mm5 \n\t"
"pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i]
"pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i]
"pxor %%mm2, %%mm2 \n\t"
"pxor %%mm3, %%mm3 \n\t"
"pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0
"pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"psubw %%mm2, %%mm0 \n\t" // abs(block[i])
"psubw %%mm3, %%mm1 \n\t" // abs(block[i])
"pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*q
"pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*q
"pxor %%mm4, %%mm4 \n\t"
"pxor %%mm5, %%mm5 \n\t" // FIXME slow
"pcmpeqw (%0, %%"REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0
"pcmpeqw 8(%0, %%"REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0
"psraw $3, %%mm0 \n\t"
"psraw $3, %%mm1 \n\t"
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"psubw %%mm2, %%mm0 \n\t"
"psubw %%mm3, %%mm1 \n\t"
"pandn %%mm0, %%mm4 \n\t"
"pandn %%mm1, %%mm5 \n\t"
"movq %%mm4, (%0, %%"REG_a") \n\t"
"movq %%mm5, 8(%0, %%"REG_a") \n\t"
"add $16, %%"REG_a" \n\t"
"jng 1b \n\t"
::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs)
: "%"REG_a, "memory"
);
block[0]= block0;
//Note, we do not do mismatch control for intra as errors cannot accumulate
}
static void dct_unquantize_mpeg2_inter_mmx(MpegEncContext *s,
DCTELEM *block, int n, int qscale)
{
x86_reg nCoeffs;
const uint16_t *quant_matrix;
assert(s->block_last_index[n]>=0);
if(s->alternate_scan) nCoeffs= 63; //FIXME
else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ];
quant_matrix = s->inter_matrix;
asm volatile(
"pcmpeqw %%mm7, %%mm7 \n\t"
"psrlq $48, %%mm7 \n\t"
"movd %2, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"packssdw %%mm6, %%mm6 \n\t"
"mov %3, %%"REG_a" \n\t"
ASMALIGN(4)
"1: \n\t"
"movq (%0, %%"REG_a"), %%mm0 \n\t"
"movq 8(%0, %%"REG_a"), %%mm1 \n\t"
"movq (%1, %%"REG_a"), %%mm4 \n\t"
"movq 8(%1, %%"REG_a"), %%mm5 \n\t"
"pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i]
"pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i]
"pxor %%mm2, %%mm2 \n\t"
"pxor %%mm3, %%mm3 \n\t"
"pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0
"pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"psubw %%mm2, %%mm0 \n\t" // abs(block[i])
"psubw %%mm3, %%mm1 \n\t" // abs(block[i])
"paddw %%mm0, %%mm0 \n\t" // abs(block[i])*2
"paddw %%mm1, %%mm1 \n\t" // abs(block[i])*2
"pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*2*q
"pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*2*q
"paddw %%mm4, %%mm0 \n\t" // (abs(block[i])*2 + 1)*q
"paddw %%mm5, %%mm1 \n\t" // (abs(block[i])*2 + 1)*q
"pxor %%mm4, %%mm4 \n\t"
"pxor %%mm5, %%mm5 \n\t" // FIXME slow
"pcmpeqw (%0, %%"REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0
"pcmpeqw 8(%0, %%"REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0
"psrlw $4, %%mm0 \n\t"
"psrlw $4, %%mm1 \n\t"
"pxor %%mm2, %%mm0 \n\t"
"pxor %%mm3, %%mm1 \n\t"
"psubw %%mm2, %%mm0 \n\t"
"psubw %%mm3, %%mm1 \n\t"
"pandn %%mm0, %%mm4 \n\t"
"pandn %%mm1, %%mm5 \n\t"
"pxor %%mm4, %%mm7 \n\t"
"pxor %%mm5, %%mm7 \n\t"
"movq %%mm4, (%0, %%"REG_a") \n\t"
"movq %%mm5, 8(%0, %%"REG_a") \n\t"
"add $16, %%"REG_a" \n\t"
"jng 1b \n\t"
"movd 124(%0, %3), %%mm0 \n\t"
"movq %%mm7, %%mm6 \n\t"
"psrlq $32, %%mm7 \n\t"
"pxor %%mm6, %%mm7 \n\t"
"movq %%mm7, %%mm6 \n\t"
"psrlq $16, %%mm7 \n\t"
"pxor %%mm6, %%mm7 \n\t"
"pslld $31, %%mm7 \n\t"
"psrlq $15, %%mm7 \n\t"
"pxor %%mm7, %%mm0 \n\t"
"movd %%mm0, 124(%0, %3) \n\t"
::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "r" (-2*nCoeffs)
: "%"REG_a, "memory"
);
}
static void denoise_dct_mmx(MpegEncContext *s, DCTELEM *block){
const int intra= s->mb_intra;
int *sum= s->dct_error_sum[intra];
uint16_t *offset= s->dct_offset[intra];
s->dct_count[intra]++;
asm volatile(
"pxor %%mm7, %%mm7 \n\t"
"1: \n\t"
"pxor %%mm0, %%mm0 \n\t"
"pxor %%mm1, %%mm1 \n\t"
"movq (%0), %%mm2 \n\t"
"movq 8(%0), %%mm3 \n\t"
"pcmpgtw %%mm2, %%mm0 \n\t"
"pcmpgtw %%mm3, %%mm1 \n\t"
"pxor %%mm0, %%mm2 \n\t"
"pxor %%mm1, %%mm3 \n\t"
"psubw %%mm0, %%mm2 \n\t"
"psubw %%mm1, %%mm3 \n\t"
"movq %%mm2, %%mm4 \n\t"
"movq %%mm3, %%mm5 \n\t"
"psubusw (%2), %%mm2 \n\t"
"psubusw 8(%2), %%mm3 \n\t"
"pxor %%mm0, %%mm2 \n\t"
"pxor %%mm1, %%mm3 \n\t"
"psubw %%mm0, %%mm2 \n\t"
"psubw %%mm1, %%mm3 \n\t"
"movq %%mm2, (%0) \n\t"
"movq %%mm3, 8(%0) \n\t"
"movq %%mm4, %%mm2 \n\t"
"movq %%mm5, %%mm3 \n\t"
"punpcklwd %%mm7, %%mm4 \n\t"
"punpckhwd %%mm7, %%mm2 \n\t"
"punpcklwd %%mm7, %%mm5 \n\t"
"punpckhwd %%mm7, %%mm3 \n\t"
"paddd (%1), %%mm4 \n\t"
"paddd 8(%1), %%mm2 \n\t"
"paddd 16(%1), %%mm5 \n\t"
"paddd 24(%1), %%mm3 \n\t"
"movq %%mm4, (%1) \n\t"
"movq %%mm2, 8(%1) \n\t"
"movq %%mm5, 16(%1) \n\t"
"movq %%mm3, 24(%1) \n\t"
"add $16, %0 \n\t"
"add $32, %1 \n\t"
"add $16, %2 \n\t"
"cmp %3, %0 \n\t"
" jb 1b \n\t"
: "+r" (block), "+r" (sum), "+r" (offset)
: "r"(block+64)
);
}
static void denoise_dct_sse2(MpegEncContext *s, DCTELEM *block){
const int intra= s->mb_intra;
int *sum= s->dct_error_sum[intra];
uint16_t *offset= s->dct_offset[intra];
s->dct_count[intra]++;
asm volatile(
"pxor %%xmm7, %%xmm7 \n\t"
"1: \n\t"
"pxor %%xmm0, %%xmm0 \n\t"
"pxor %%xmm1, %%xmm1 \n\t"
"movdqa (%0), %%xmm2 \n\t"
"movdqa 16(%0), %%xmm3 \n\t"
"pcmpgtw %%xmm2, %%xmm0 \n\t"
"pcmpgtw %%xmm3, %%xmm1 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pxor %%xmm1, %%xmm3 \n\t"
"psubw %%xmm0, %%xmm2 \n\t"
"psubw %%xmm1, %%xmm3 \n\t"
"movdqa %%xmm2, %%xmm4 \n\t"
"movdqa %%xmm3, %%xmm5 \n\t"
"psubusw (%2), %%xmm2 \n\t"
"psubusw 16(%2), %%xmm3 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pxor %%xmm1, %%xmm3 \n\t"
"psubw %%xmm0, %%xmm2 \n\t"
"psubw %%xmm1, %%xmm3 \n\t"
"movdqa %%xmm2, (%0) \n\t"
"movdqa %%xmm3, 16(%0) \n\t"
"movdqa %%xmm4, %%xmm6 \n\t"
"movdqa %%xmm5, %%xmm0 \n\t"
"punpcklwd %%xmm7, %%xmm4 \n\t"
"punpckhwd %%xmm7, %%xmm6 \n\t"
"punpcklwd %%xmm7, %%xmm5 \n\t"
"punpckhwd %%xmm7, %%xmm0 \n\t"
"paddd (%1), %%xmm4 \n\t"
"paddd 16(%1), %%xmm6 \n\t"
"paddd 32(%1), %%xmm5 \n\t"
"paddd 48(%1), %%xmm0 \n\t"
"movdqa %%xmm4, (%1) \n\t"
"movdqa %%xmm6, 16(%1) \n\t"
"movdqa %%xmm5, 32(%1) \n\t"
"movdqa %%xmm0, 48(%1) \n\t"
"add $32, %0 \n\t"
"add $64, %1 \n\t"
"add $32, %2 \n\t"
"cmp %3, %0 \n\t"
" jb 1b \n\t"
: "+r" (block), "+r" (sum), "+r" (offset)
: "r"(block+64)
);
}
#ifdef HAVE_SSSE3
#define HAVE_SSSE3_BAK
#endif
#undef HAVE_SSSE3
#undef HAVE_SSE2
#undef HAVE_MMX2
#define RENAME(a) a ## _MMX
#define RENAMEl(a) a ## _mmx
#include "mpegvideo_mmx_template.c"
#define HAVE_MMX2
#undef RENAME
#undef RENAMEl
#define RENAME(a) a ## _MMX2
#define RENAMEl(a) a ## _mmx2
#include "mpegvideo_mmx_template.c"
#define HAVE_SSE2
#undef RENAME
#undef RENAMEl
#define RENAME(a) a ## _SSE2
#define RENAMEl(a) a ## _sse2
#include "mpegvideo_mmx_template.c"
#ifdef HAVE_SSSE3_BAK
#define HAVE_SSSE3
#undef RENAME
#undef RENAMEl
#define RENAME(a) a ## _SSSE3
#define RENAMEl(a) a ## _sse2
#include "mpegvideo_mmx_template.c"
#endif
void MPV_common_init_mmx(MpegEncContext *s)
{
if (mm_flags & MM_MMX) {
const int dct_algo = s->avctx->dct_algo;
s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_mmx;
s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_mmx;
s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_mmx;
s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_mmx;
if(!(s->flags & CODEC_FLAG_BITEXACT))
s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_mmx;
s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_mmx;
if (mm_flags & MM_SSE2) {
s->denoise_dct= denoise_dct_sse2;
} else {
s->denoise_dct= denoise_dct_mmx;
}
if(dct_algo==FF_DCT_AUTO || dct_algo==FF_DCT_MMX){
#ifdef HAVE_SSSE3
if(mm_flags & MM_SSSE3){
s->dct_quantize= dct_quantize_SSSE3;
} else
#endif
if(mm_flags & MM_SSE2){
s->dct_quantize= dct_quantize_SSE2;
} else if(mm_flags & MM_MMXEXT){
s->dct_quantize= dct_quantize_MMX2;
} else {
s->dct_quantize= dct_quantize_MMX;
}
}
}
}
@@ -0,0 +1,376 @@
/*
* MPEG video MMX templates
*
* Copyright (c) 2002 Michael Niedermayer <[email protected]>
*
* 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
*/
#undef MMREG_WIDTH
#undef MM
#undef MOVQ
#undef SPREADW
#undef PMAXW
#undef PMAX
#undef SAVE_SIGN
#undef RESTORE_SIGN
#if defined(HAVE_SSE2)
#define MMREG_WIDTH "16"
#define MM "%%xmm"
#define MOVQ "movdqa"
#define SPREADW(a) \
"pshuflw $0, "a", "a" \n\t"\
"punpcklwd "a", "a" \n\t"
#define PMAXW(a,b) "pmaxsw "a", "b" \n\t"
#define PMAX(a,b) \
"movhlps "a", "b" \n\t"\
PMAXW(b, a)\
"pshuflw $0x0E, "a", "b" \n\t"\
PMAXW(b, a)\
"pshuflw $0x01, "a", "b" \n\t"\
PMAXW(b, a)
#else
#define MMREG_WIDTH "8"
#define MM "%%mm"
#define MOVQ "movq"
#if defined(HAVE_MMX2)
#define SPREADW(a) "pshufw $0, "a", "a" \n\t"
#define PMAXW(a,b) "pmaxsw "a", "b" \n\t"
#define PMAX(a,b) \
"pshufw $0x0E, "a", "b" \n\t"\
PMAXW(b, a)\
"pshufw $0x01, "a", "b" \n\t"\
PMAXW(b, a)
#else
#define SPREADW(a) \
"punpcklwd "a", "a" \n\t"\
"punpcklwd "a", "a" \n\t"
#define PMAXW(a,b) \
"psubusw "a", "b" \n\t"\
"paddw "a", "b" \n\t"
#define PMAX(a,b) \
"movq "a", "b" \n\t"\
"psrlq $32, "a" \n\t"\
PMAXW(b, a)\
"movq "a", "b" \n\t"\
"psrlq $16, "a" \n\t"\
PMAXW(b, a)
#endif
#endif
#ifdef HAVE_SSSE3
#define SAVE_SIGN(a,b) \
"movdqa "b", "a" \n\t"\
"pabsw "b", "b" \n\t"
#define RESTORE_SIGN(a,b) \
"psignw "a", "b" \n\t"
#else
#define SAVE_SIGN(a,b) \
"pxor "a", "a" \n\t"\
"pcmpgtw "b", "a" \n\t" /* block[i] <= 0 ? 0xFF : 0x00 */\
"pxor "a", "b" \n\t"\
"psubw "a", "b" \n\t" /* ABS(block[i]) */
#define RESTORE_SIGN(a,b) \
"pxor "a", "b" \n\t"\
"psubw "a", "b" \n\t" // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i])
#endif
static int RENAME(dct_quantize)(MpegEncContext *s,
DCTELEM *block, int n,
int qscale, int *overflow)
{
x86_reg last_non_zero_p1;
int level=0, q; //=0 is because gcc says uninitialized ...
const uint16_t *qmat, *bias;
DECLARE_ALIGNED_16(int16_t, temp_block[64]);
assert((7&(int)(&temp_block[0])) == 0); //did gcc align it correctly?
//s->fdct (block);
RENAMEl(ff_fdct) (block); //cannot be anything else ...
if(s->dct_error_sum)
s->denoise_dct(s, block);
if (s->mb_intra) {
int dummy;
if (n < 4)
q = s->y_dc_scale;
else
q = s->c_dc_scale;
/* note: block[0] is assumed to be positive */
if (!s->h263_aic) {
#if 1
asm volatile (
"mul %%ecx \n\t"
: "=d" (level), "=a"(dummy)
: "a" ((block[0]>>2) + q), "c" (ff_inverse[q<<1])
);
#else
asm volatile (
"xorl %%edx, %%edx \n\t"
"divw %%cx \n\t"
"movzwl %%ax, %%eax \n\t"
: "=a" (level)
: "a" ((block[0]>>2) + q), "c" (q<<1)
: "%edx"
);
#endif
} else
/* For AIC we skip quant/dequant of INTRADC */
level = (block[0] + 4)>>3;
block[0]=0; //avoid fake overflow
// temp_block[0] = (block[0] + (q >> 1)) / q;
last_non_zero_p1 = 1;
bias = s->q_intra_matrix16[qscale][1];
qmat = s->q_intra_matrix16[qscale][0];
} else {
last_non_zero_p1 = 0;
bias = s->q_inter_matrix16[qscale][1];
qmat = s->q_inter_matrix16[qscale][0];
}
if((s->out_format == FMT_H263 || s->out_format == FMT_H261) && s->mpeg_quant==0){
asm volatile(
"movd %%"REG_a", "MM"3 \n\t" // last_non_zero_p1
SPREADW(MM"3")
"pxor "MM"7, "MM"7 \n\t" // 0
"pxor "MM"4, "MM"4 \n\t" // 0
MOVQ" (%2), "MM"5 \n\t" // qmat[0]
"pxor "MM"6, "MM"6 \n\t"
"psubw (%3), "MM"6 \n\t" // -bias[0]
"mov $-128, %%"REG_a" \n\t"
ASMALIGN(4)
"1: \n\t"
MOVQ" (%1, %%"REG_a"), "MM"0 \n\t" // block[i]
SAVE_SIGN(MM"1", MM"0") // ABS(block[i])
"psubusw "MM"6, "MM"0 \n\t" // ABS(block[i]) + bias[0]
"pmulhw "MM"5, "MM"0 \n\t" // (ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16
"por "MM"0, "MM"4 \n\t"
RESTORE_SIGN(MM"1", MM"0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i])
MOVQ" "MM"0, (%5, %%"REG_a") \n\t"
"pcmpeqw "MM"7, "MM"0 \n\t" // out==0 ? 0xFF : 0x00
MOVQ" (%4, %%"REG_a"), "MM"1 \n\t"
MOVQ" "MM"7, (%1, %%"REG_a") \n\t" // 0
"pandn "MM"1, "MM"0 \n\t"
PMAXW(MM"0", MM"3")
"add $"MMREG_WIDTH", %%"REG_a" \n\t"
" js 1b \n\t"
PMAX(MM"3", MM"0")
"movd "MM"3, %%"REG_a" \n\t"
"movzb %%al, %%"REG_a" \n\t" // last_non_zero_p1
: "+a" (last_non_zero_p1)
: "r" (block+64), "r" (qmat), "r" (bias),
"r" (inv_zigzag_direct16+64), "r" (temp_block+64)
);
}else{ // FMT_H263
asm volatile(
"movd %%"REG_a", "MM"3 \n\t" // last_non_zero_p1
SPREADW(MM"3")
"pxor "MM"7, "MM"7 \n\t" // 0
"pxor "MM"4, "MM"4 \n\t" // 0
"mov $-128, %%"REG_a" \n\t"
ASMALIGN(4)
"1: \n\t"
MOVQ" (%1, %%"REG_a"), "MM"0 \n\t" // block[i]
SAVE_SIGN(MM"1", MM"0") // ABS(block[i])
MOVQ" (%3, %%"REG_a"), "MM"6 \n\t" // bias[0]
"paddusw "MM"6, "MM"0 \n\t" // ABS(block[i]) + bias[0]
MOVQ" (%2, %%"REG_a"), "MM"5 \n\t" // qmat[i]
"pmulhw "MM"5, "MM"0 \n\t" // (ABS(block[i])*qmat[0] + bias[0]*qmat[0])>>16
"por "MM"0, "MM"4 \n\t"
RESTORE_SIGN(MM"1", MM"0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i])
MOVQ" "MM"0, (%5, %%"REG_a") \n\t"
"pcmpeqw "MM"7, "MM"0 \n\t" // out==0 ? 0xFF : 0x00
MOVQ" (%4, %%"REG_a"), "MM"1 \n\t"
MOVQ" "MM"7, (%1, %%"REG_a") \n\t" // 0
"pandn "MM"1, "MM"0 \n\t"
PMAXW(MM"0", MM"3")
"add $"MMREG_WIDTH", %%"REG_a" \n\t"
" js 1b \n\t"
PMAX(MM"3", MM"0")
"movd "MM"3, %%"REG_a" \n\t"
"movzb %%al, %%"REG_a" \n\t" // last_non_zero_p1
: "+a" (last_non_zero_p1)
: "r" (block+64), "r" (qmat+64), "r" (bias+64),
"r" (inv_zigzag_direct16+64), "r" (temp_block+64)
);
}
asm volatile(
"movd %1, "MM"1 \n\t" // max_qcoeff
SPREADW(MM"1")
"psubusw "MM"1, "MM"4 \n\t"
"packuswb "MM"4, "MM"4 \n\t"
#ifdef HAVE_SSE2
"packuswb "MM"4, "MM"4 \n\t"
#endif
"movd "MM"4, %0 \n\t" // *overflow
: "=g" (*overflow)
: "g" (s->max_qcoeff)
);
if(s->mb_intra) block[0]= level;
else block[0]= temp_block[0];
if(s->dsp.idct_permutation_type == FF_SIMPLE_IDCT_PERM){
if(last_non_zero_p1 <= 1) goto end;
block[0x08] = temp_block[0x01]; block[0x10] = temp_block[0x08];
block[0x20] = temp_block[0x10];
if(last_non_zero_p1 <= 4) goto end;
block[0x18] = temp_block[0x09]; block[0x04] = temp_block[0x02];
block[0x09] = temp_block[0x03];
if(last_non_zero_p1 <= 7) goto end;
block[0x14] = temp_block[0x0A]; block[0x28] = temp_block[0x11];
block[0x12] = temp_block[0x18]; block[0x02] = temp_block[0x20];
if(last_non_zero_p1 <= 11) goto end;
block[0x1A] = temp_block[0x19]; block[0x24] = temp_block[0x12];
block[0x19] = temp_block[0x0B]; block[0x01] = temp_block[0x04];
block[0x0C] = temp_block[0x05];
if(last_non_zero_p1 <= 16) goto end;
block[0x11] = temp_block[0x0C]; block[0x29] = temp_block[0x13];
block[0x16] = temp_block[0x1A]; block[0x0A] = temp_block[0x21];
block[0x30] = temp_block[0x28]; block[0x22] = temp_block[0x30];
block[0x38] = temp_block[0x29]; block[0x06] = temp_block[0x22];
if(last_non_zero_p1 <= 24) goto end;
block[0x1B] = temp_block[0x1B]; block[0x21] = temp_block[0x14];
block[0x1C] = temp_block[0x0D]; block[0x05] = temp_block[0x06];
block[0x0D] = temp_block[0x07]; block[0x15] = temp_block[0x0E];
block[0x2C] = temp_block[0x15]; block[0x13] = temp_block[0x1C];
if(last_non_zero_p1 <= 32) goto end;
block[0x0B] = temp_block[0x23]; block[0x34] = temp_block[0x2A];
block[0x2A] = temp_block[0x31]; block[0x32] = temp_block[0x38];
block[0x3A] = temp_block[0x39]; block[0x26] = temp_block[0x32];
block[0x39] = temp_block[0x2B]; block[0x03] = temp_block[0x24];
if(last_non_zero_p1 <= 40) goto end;
block[0x1E] = temp_block[0x1D]; block[0x25] = temp_block[0x16];
block[0x1D] = temp_block[0x0F]; block[0x2D] = temp_block[0x17];
block[0x17] = temp_block[0x1E]; block[0x0E] = temp_block[0x25];
block[0x31] = temp_block[0x2C]; block[0x2B] = temp_block[0x33];
if(last_non_zero_p1 <= 48) goto end;
block[0x36] = temp_block[0x3A]; block[0x3B] = temp_block[0x3B];
block[0x23] = temp_block[0x34]; block[0x3C] = temp_block[0x2D];
block[0x07] = temp_block[0x26]; block[0x1F] = temp_block[0x1F];
block[0x0F] = temp_block[0x27]; block[0x35] = temp_block[0x2E];
if(last_non_zero_p1 <= 56) goto end;
block[0x2E] = temp_block[0x35]; block[0x33] = temp_block[0x3C];
block[0x3E] = temp_block[0x3D]; block[0x27] = temp_block[0x36];
block[0x3D] = temp_block[0x2F]; block[0x2F] = temp_block[0x37];
block[0x37] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F];
}else if(s->dsp.idct_permutation_type == FF_LIBMPEG2_IDCT_PERM){
if(last_non_zero_p1 <= 1) goto end;
block[0x04] = temp_block[0x01];
block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10];
if(last_non_zero_p1 <= 4) goto end;
block[0x0C] = temp_block[0x09]; block[0x01] = temp_block[0x02];
block[0x05] = temp_block[0x03];
if(last_non_zero_p1 <= 7) goto end;
block[0x09] = temp_block[0x0A]; block[0x14] = temp_block[0x11];
block[0x18] = temp_block[0x18]; block[0x20] = temp_block[0x20];
if(last_non_zero_p1 <= 11) goto end;
block[0x1C] = temp_block[0x19];
block[0x11] = temp_block[0x12]; block[0x0D] = temp_block[0x0B];
block[0x02] = temp_block[0x04]; block[0x06] = temp_block[0x05];
if(last_non_zero_p1 <= 16) goto end;
block[0x0A] = temp_block[0x0C]; block[0x15] = temp_block[0x13];
block[0x19] = temp_block[0x1A]; block[0x24] = temp_block[0x21];
block[0x28] = temp_block[0x28]; block[0x30] = temp_block[0x30];
block[0x2C] = temp_block[0x29]; block[0x21] = temp_block[0x22];
if(last_non_zero_p1 <= 24) goto end;
block[0x1D] = temp_block[0x1B]; block[0x12] = temp_block[0x14];
block[0x0E] = temp_block[0x0D]; block[0x03] = temp_block[0x06];
block[0x07] = temp_block[0x07]; block[0x0B] = temp_block[0x0E];
block[0x16] = temp_block[0x15]; block[0x1A] = temp_block[0x1C];
if(last_non_zero_p1 <= 32) goto end;
block[0x25] = temp_block[0x23]; block[0x29] = temp_block[0x2A];
block[0x34] = temp_block[0x31]; block[0x38] = temp_block[0x38];
block[0x3C] = temp_block[0x39]; block[0x31] = temp_block[0x32];
block[0x2D] = temp_block[0x2B]; block[0x22] = temp_block[0x24];
if(last_non_zero_p1 <= 40) goto end;
block[0x1E] = temp_block[0x1D]; block[0x13] = temp_block[0x16];
block[0x0F] = temp_block[0x0F]; block[0x17] = temp_block[0x17];
block[0x1B] = temp_block[0x1E]; block[0x26] = temp_block[0x25];
block[0x2A] = temp_block[0x2C]; block[0x35] = temp_block[0x33];
if(last_non_zero_p1 <= 48) goto end;
block[0x39] = temp_block[0x3A]; block[0x3D] = temp_block[0x3B];
block[0x32] = temp_block[0x34]; block[0x2E] = temp_block[0x2D];
block[0x23] = temp_block[0x26]; block[0x1F] = temp_block[0x1F];
block[0x27] = temp_block[0x27]; block[0x2B] = temp_block[0x2E];
if(last_non_zero_p1 <= 56) goto end;
block[0x36] = temp_block[0x35]; block[0x3A] = temp_block[0x3C];
block[0x3E] = temp_block[0x3D]; block[0x33] = temp_block[0x36];
block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37];
block[0x3B] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F];
}else{
if(last_non_zero_p1 <= 1) goto end;
block[0x01] = temp_block[0x01];
block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10];
if(last_non_zero_p1 <= 4) goto end;
block[0x09] = temp_block[0x09]; block[0x02] = temp_block[0x02];
block[0x03] = temp_block[0x03];
if(last_non_zero_p1 <= 7) goto end;
block[0x0A] = temp_block[0x0A]; block[0x11] = temp_block[0x11];
block[0x18] = temp_block[0x18]; block[0x20] = temp_block[0x20];
if(last_non_zero_p1 <= 11) goto end;
block[0x19] = temp_block[0x19];
block[0x12] = temp_block[0x12]; block[0x0B] = temp_block[0x0B];
block[0x04] = temp_block[0x04]; block[0x05] = temp_block[0x05];
if(last_non_zero_p1 <= 16) goto end;
block[0x0C] = temp_block[0x0C]; block[0x13] = temp_block[0x13];
block[0x1A] = temp_block[0x1A]; block[0x21] = temp_block[0x21];
block[0x28] = temp_block[0x28]; block[0x30] = temp_block[0x30];
block[0x29] = temp_block[0x29]; block[0x22] = temp_block[0x22];
if(last_non_zero_p1 <= 24) goto end;
block[0x1B] = temp_block[0x1B]; block[0x14] = temp_block[0x14];
block[0x0D] = temp_block[0x0D]; block[0x06] = temp_block[0x06];
block[0x07] = temp_block[0x07]; block[0x0E] = temp_block[0x0E];
block[0x15] = temp_block[0x15]; block[0x1C] = temp_block[0x1C];
if(last_non_zero_p1 <= 32) goto end;
block[0x23] = temp_block[0x23]; block[0x2A] = temp_block[0x2A];
block[0x31] = temp_block[0x31]; block[0x38] = temp_block[0x38];
block[0x39] = temp_block[0x39]; block[0x32] = temp_block[0x32];
block[0x2B] = temp_block[0x2B]; block[0x24] = temp_block[0x24];
if(last_non_zero_p1 <= 40) goto end;
block[0x1D] = temp_block[0x1D]; block[0x16] = temp_block[0x16];
block[0x0F] = temp_block[0x0F]; block[0x17] = temp_block[0x17];
block[0x1E] = temp_block[0x1E]; block[0x25] = temp_block[0x25];
block[0x2C] = temp_block[0x2C]; block[0x33] = temp_block[0x33];
if(last_non_zero_p1 <= 48) goto end;
block[0x3A] = temp_block[0x3A]; block[0x3B] = temp_block[0x3B];
block[0x34] = temp_block[0x34]; block[0x2D] = temp_block[0x2D];
block[0x26] = temp_block[0x26]; block[0x1F] = temp_block[0x1F];
block[0x27] = temp_block[0x27]; block[0x2E] = temp_block[0x2E];
if(last_non_zero_p1 <= 56) goto end;
block[0x35] = temp_block[0x35]; block[0x3C] = temp_block[0x3C];
block[0x3D] = temp_block[0x3D]; block[0x36] = temp_block[0x36];
block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37];
block[0x3E] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F];
}
end:
/*
for(i=0; i<last_non_zero_p1; i++)
{
int j= zigzag_direct_noperm[i];
block[block_permute_op(j)]= temp_block[j];
}
*/
return last_non_zero_p1 - 1;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,871 @@
/*
* MMX and SSE2 optimized snow DSP utils
* Copyright (c) 2005-2006 Robert Edele <[email protected]>
*
* 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/x86_cpu.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/snow.h"
void ff_snow_horizontal_compose97i_sse2(IDWTELEM *b, int width){
const int w2= (width+1)>>1;
DECLARE_ALIGNED_16(IDWTELEM, temp[width>>1]);
const int w_l= (width>>1);
const int w_r= w2 - 1;
int i;
{ // Lift 0
IDWTELEM * const ref = b + w2 - 1;
IDWTELEM b_0 = b[0]; //By allowing the first entry in b[0] to be calculated twice
// (the first time erroneously), we allow the SSE2 code to run an extra pass.
// The savings in code and time are well worth having to store this value and
// calculate b[0] correctly afterwards.
i = 0;
asm volatile(
"pcmpeqd %%xmm7, %%xmm7 \n\t"
"pcmpeqd %%xmm3, %%xmm3 \n\t"
"psllw $1, %%xmm3 \n\t"
"paddw %%xmm7, %%xmm3 \n\t"
"psllw $13, %%xmm3 \n\t"
::);
for(; i<w_l-15; i+=16){
asm volatile(
"movdqu (%1), %%xmm1 \n\t"
"movdqu 16(%1), %%xmm5 \n\t"
"movdqu 2(%1), %%xmm2 \n\t"
"movdqu 18(%1), %%xmm6 \n\t"
"paddw %%xmm1, %%xmm2 \n\t"
"paddw %%xmm5, %%xmm6 \n\t"
"paddw %%xmm7, %%xmm2 \n\t"
"paddw %%xmm7, %%xmm6 \n\t"
"pmulhw %%xmm3, %%xmm2 \n\t"
"pmulhw %%xmm3, %%xmm6 \n\t"
"paddw (%0), %%xmm2 \n\t"
"paddw 16(%0), %%xmm6 \n\t"
"movdqa %%xmm2, (%0) \n\t"
"movdqa %%xmm6, 16(%0) \n\t"
:: "r"(&b[i]), "r"(&ref[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, b, b, ref, width, w_l, 0, W_DM, W_DO, W_DS);
b[0] = b_0 - ((W_DM * 2 * ref[1]+W_DO)>>W_DS);
}
{ // Lift 1
IDWTELEM * const dst = b+w2;
i = 0;
for(; (((x86_reg)&dst[i]) & 0x1F) && i<w_r; i++){
dst[i] = dst[i] - (b[i] + b[i + 1]);
}
for(; i<w_r-15; i+=16){
asm volatile(
"movdqu (%1), %%xmm1 \n\t"
"movdqu 16(%1), %%xmm5 \n\t"
"movdqu 2(%1), %%xmm2 \n\t"
"movdqu 18(%1), %%xmm6 \n\t"
"paddw %%xmm1, %%xmm2 \n\t"
"paddw %%xmm5, %%xmm6 \n\t"
"movdqa (%0), %%xmm0 \n\t"
"movdqa 16(%0), %%xmm4 \n\t"
"psubw %%xmm2, %%xmm0 \n\t"
"psubw %%xmm6, %%xmm4 \n\t"
"movdqa %%xmm0, (%0) \n\t"
"movdqa %%xmm4, 16(%0) \n\t"
:: "r"(&dst[i]), "r"(&b[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, dst, dst, b, width, w_r, 1, W_CM, W_CO, W_CS);
}
{ // Lift 2
IDWTELEM * const ref = b+w2 - 1;
IDWTELEM b_0 = b[0];
i = 0;
asm volatile(
"psllw $15, %%xmm7 \n\t"
"pcmpeqw %%xmm6, %%xmm6 \n\t"
"psrlw $13, %%xmm6 \n\t"
"paddw %%xmm7, %%xmm6 \n\t"
::);
for(; i<w_l-15; i+=16){
asm volatile(
"movdqu (%1), %%xmm0 \n\t"
"movdqu 16(%1), %%xmm4 \n\t"
"movdqu 2(%1), %%xmm1 \n\t"
"movdqu 18(%1), %%xmm5 \n\t" //FIXME try aligned reads and shifts
"paddw %%xmm6, %%xmm0 \n\t"
"paddw %%xmm6, %%xmm4 \n\t"
"paddw %%xmm7, %%xmm1 \n\t"
"paddw %%xmm7, %%xmm5 \n\t"
"pavgw %%xmm1, %%xmm0 \n\t"
"pavgw %%xmm5, %%xmm4 \n\t"
"psubw %%xmm7, %%xmm0 \n\t"
"psubw %%xmm7, %%xmm4 \n\t"
"psraw $1, %%xmm0 \n\t"
"psraw $1, %%xmm4 \n\t"
"movdqa (%0), %%xmm1 \n\t"
"movdqa 16(%0), %%xmm5 \n\t"
"paddw %%xmm1, %%xmm0 \n\t"
"paddw %%xmm5, %%xmm4 \n\t"
"psraw $2, %%xmm0 \n\t"
"psraw $2, %%xmm4 \n\t"
"paddw %%xmm1, %%xmm0 \n\t"
"paddw %%xmm5, %%xmm4 \n\t"
"movdqa %%xmm0, (%0) \n\t"
"movdqa %%xmm4, 16(%0) \n\t"
:: "r"(&b[i]), "r"(&ref[i])
: "memory"
);
}
snow_horizontal_compose_liftS_lead_out(i, b, b, ref, width, w_l);
b[0] = b_0 + ((2 * ref[1] + W_BO-1 + 4 * b_0) >> W_BS);
}
{ // Lift 3
IDWTELEM * const src = b+w2;
i = 0;
for(; (((x86_reg)&temp[i]) & 0x1F) && i<w_r; i++){
temp[i] = src[i] - ((-W_AM*(b[i] + b[i+1]))>>W_AS);
}
for(; i<w_r-7; i+=8){
asm volatile(
"movdqu 2(%1), %%xmm2 \n\t"
"movdqu 18(%1), %%xmm6 \n\t"
"paddw (%1), %%xmm2 \n\t"
"paddw 16(%1), %%xmm6 \n\t"
"movdqu (%0), %%xmm0 \n\t"
"movdqu 16(%0), %%xmm4 \n\t"
"paddw %%xmm2, %%xmm0 \n\t"
"paddw %%xmm6, %%xmm4 \n\t"
"psraw $1, %%xmm2 \n\t"
"psraw $1, %%xmm6 \n\t"
"paddw %%xmm0, %%xmm2 \n\t"
"paddw %%xmm4, %%xmm6 \n\t"
"movdqa %%xmm2, (%2) \n\t"
"movdqa %%xmm6, 16(%2) \n\t"
:: "r"(&src[i]), "r"(&b[i]), "r"(&temp[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, temp, src, b, width, w_r, 1, -W_AM, W_AO+1, W_AS);
}
{
snow_interleave_line_header(&i, width, b, temp);
for (; (i & 0x3E) != 0x3E; i-=2){
b[i+1] = temp[i>>1];
b[i] = b[i>>1];
}
for (i-=62; i>=0; i-=64){
asm volatile(
"movdqa (%1), %%xmm0 \n\t"
"movdqa 16(%1), %%xmm2 \n\t"
"movdqa 32(%1), %%xmm4 \n\t"
"movdqa 48(%1), %%xmm6 \n\t"
"movdqa (%1), %%xmm1 \n\t"
"movdqa 16(%1), %%xmm3 \n\t"
"movdqa 32(%1), %%xmm5 \n\t"
"movdqa 48(%1), %%xmm7 \n\t"
"punpcklwd (%2), %%xmm0 \n\t"
"punpcklwd 16(%2), %%xmm2 \n\t"
"punpcklwd 32(%2), %%xmm4 \n\t"
"punpcklwd 48(%2), %%xmm6 \n\t"
"movdqa %%xmm0, (%0) \n\t"
"movdqa %%xmm2, 32(%0) \n\t"
"movdqa %%xmm4, 64(%0) \n\t"
"movdqa %%xmm6, 96(%0) \n\t"
"punpckhwd (%2), %%xmm1 \n\t"
"punpckhwd 16(%2), %%xmm3 \n\t"
"punpckhwd 32(%2), %%xmm5 \n\t"
"punpckhwd 48(%2), %%xmm7 \n\t"
"movdqa %%xmm1, 16(%0) \n\t"
"movdqa %%xmm3, 48(%0) \n\t"
"movdqa %%xmm5, 80(%0) \n\t"
"movdqa %%xmm7, 112(%0) \n\t"
:: "r"(&(b)[i]), "r"(&(b)[i>>1]), "r"(&(temp)[i>>1])
: "memory"
);
}
}
}
void ff_snow_horizontal_compose97i_mmx(IDWTELEM *b, int width){
const int w2= (width+1)>>1;
IDWTELEM temp[width >> 1];
const int w_l= (width>>1);
const int w_r= w2 - 1;
int i;
{ // Lift 0
IDWTELEM * const ref = b + w2 - 1;
i = 1;
b[0] = b[0] - ((W_DM * 2 * ref[1]+W_DO)>>W_DS);
asm volatile(
"pcmpeqw %%mm7, %%mm7 \n\t"
"pcmpeqw %%mm3, %%mm3 \n\t"
"psllw $1, %%mm3 \n\t"
"paddw %%mm7, %%mm3 \n\t"
"psllw $13, %%mm3 \n\t"
::);
for(; i<w_l-7; i+=8){
asm volatile(
"movq (%1), %%mm2 \n\t"
"movq 8(%1), %%mm6 \n\t"
"paddw 2(%1), %%mm2 \n\t"
"paddw 10(%1), %%mm6 \n\t"
"paddw %%mm7, %%mm2 \n\t"
"paddw %%mm7, %%mm6 \n\t"
"pmulhw %%mm3, %%mm2 \n\t"
"pmulhw %%mm3, %%mm6 \n\t"
"paddw (%0), %%mm2 \n\t"
"paddw 8(%0), %%mm6 \n\t"
"movq %%mm2, (%0) \n\t"
"movq %%mm6, 8(%0) \n\t"
:: "r"(&b[i]), "r"(&ref[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, b, b, ref, width, w_l, 0, W_DM, W_DO, W_DS);
}
{ // Lift 1
IDWTELEM * const dst = b+w2;
i = 0;
for(; i<w_r-7; i+=8){
asm volatile(
"movq (%1), %%mm2 \n\t"
"movq 8(%1), %%mm6 \n\t"
"paddw 2(%1), %%mm2 \n\t"
"paddw 10(%1), %%mm6 \n\t"
"movq (%0), %%mm0 \n\t"
"movq 8(%0), %%mm4 \n\t"
"psubw %%mm2, %%mm0 \n\t"
"psubw %%mm6, %%mm4 \n\t"
"movq %%mm0, (%0) \n\t"
"movq %%mm4, 8(%0) \n\t"
:: "r"(&dst[i]), "r"(&b[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, dst, dst, b, width, w_r, 1, W_CM, W_CO, W_CS);
}
{ // Lift 2
IDWTELEM * const ref = b+w2 - 1;
i = 1;
b[0] = b[0] + (((2 * ref[1] + W_BO) + 4 * b[0]) >> W_BS);
asm volatile(
"psllw $15, %%mm7 \n\t"
"pcmpeqw %%mm6, %%mm6 \n\t"
"psrlw $13, %%mm6 \n\t"
"paddw %%mm7, %%mm6 \n\t"
::);
for(; i<w_l-7; i+=8){
asm volatile(
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm4 \n\t"
"movq 2(%1), %%mm1 \n\t"
"movq 10(%1), %%mm5 \n\t"
"paddw %%mm6, %%mm0 \n\t"
"paddw %%mm6, %%mm4 \n\t"
"paddw %%mm7, %%mm1 \n\t"
"paddw %%mm7, %%mm5 \n\t"
"pavgw %%mm1, %%mm0 \n\t"
"pavgw %%mm5, %%mm4 \n\t"
"psubw %%mm7, %%mm0 \n\t"
"psubw %%mm7, %%mm4 \n\t"
"psraw $1, %%mm0 \n\t"
"psraw $1, %%mm4 \n\t"
"movq (%0), %%mm1 \n\t"
"movq 8(%0), %%mm5 \n\t"
"paddw %%mm1, %%mm0 \n\t"
"paddw %%mm5, %%mm4 \n\t"
"psraw $2, %%mm0 \n\t"
"psraw $2, %%mm4 \n\t"
"paddw %%mm1, %%mm0 \n\t"
"paddw %%mm5, %%mm4 \n\t"
"movq %%mm0, (%0) \n\t"
"movq %%mm4, 8(%0) \n\t"
:: "r"(&b[i]), "r"(&ref[i])
: "memory"
);
}
snow_horizontal_compose_liftS_lead_out(i, b, b, ref, width, w_l);
}
{ // Lift 3
IDWTELEM * const src = b+w2;
i = 0;
for(; i<w_r-7; i+=8){
asm volatile(
"movq 2(%1), %%mm2 \n\t"
"movq 10(%1), %%mm6 \n\t"
"paddw (%1), %%mm2 \n\t"
"paddw 8(%1), %%mm6 \n\t"
"movq (%0), %%mm0 \n\t"
"movq 8(%0), %%mm4 \n\t"
"paddw %%mm2, %%mm0 \n\t"
"paddw %%mm6, %%mm4 \n\t"
"psraw $1, %%mm2 \n\t"
"psraw $1, %%mm6 \n\t"
"paddw %%mm0, %%mm2 \n\t"
"paddw %%mm4, %%mm6 \n\t"
"movq %%mm2, (%2) \n\t"
"movq %%mm6, 8(%2) \n\t"
:: "r"(&src[i]), "r"(&b[i]), "r"(&temp[i])
: "memory"
);
}
snow_horizontal_compose_lift_lead_out(i, temp, src, b, width, w_r, 1, -W_AM, W_AO+1, W_AS);
}
{
snow_interleave_line_header(&i, width, b, temp);
for (; (i & 0x1E) != 0x1E; i-=2){
b[i+1] = temp[i>>1];
b[i] = b[i>>1];
}
for (i-=30; i>=0; i-=32){
asm volatile(
"movq (%1), %%mm0 \n\t"
"movq 8(%1), %%mm2 \n\t"
"movq 16(%1), %%mm4 \n\t"
"movq 24(%1), %%mm6 \n\t"
"movq (%1), %%mm1 \n\t"
"movq 8(%1), %%mm3 \n\t"
"movq 16(%1), %%mm5 \n\t"
"movq 24(%1), %%mm7 \n\t"
"punpcklwd (%2), %%mm0 \n\t"
"punpcklwd 8(%2), %%mm2 \n\t"
"punpcklwd 16(%2), %%mm4 \n\t"
"punpcklwd 24(%2), %%mm6 \n\t"
"movq %%mm0, (%0) \n\t"
"movq %%mm2, 16(%0) \n\t"
"movq %%mm4, 32(%0) \n\t"
"movq %%mm6, 48(%0) \n\t"
"punpckhwd (%2), %%mm1 \n\t"
"punpckhwd 8(%2), %%mm3 \n\t"
"punpckhwd 16(%2), %%mm5 \n\t"
"punpckhwd 24(%2), %%mm7 \n\t"
"movq %%mm1, 8(%0) \n\t"
"movq %%mm3, 24(%0) \n\t"
"movq %%mm5, 40(%0) \n\t"
"movq %%mm7, 56(%0) \n\t"
:: "r"(&b[i]), "r"(&b[i>>1]), "r"(&temp[i>>1])
: "memory"
);
}
}
}
#ifdef HAVE_7REGS
#define snow_vertical_compose_sse2_load_add(op,r,t0,t1,t2,t3)\
""op" ("r",%%"REG_d"), %%"t0" \n\t"\
""op" 16("r",%%"REG_d"), %%"t1" \n\t"\
""op" 32("r",%%"REG_d"), %%"t2" \n\t"\
""op" 48("r",%%"REG_d"), %%"t3" \n\t"
#define snow_vertical_compose_sse2_load(r,t0,t1,t2,t3)\
snow_vertical_compose_sse2_load_add("movdqa",r,t0,t1,t2,t3)
#define snow_vertical_compose_sse2_add(r,t0,t1,t2,t3)\
snow_vertical_compose_sse2_load_add("paddw",r,t0,t1,t2,t3)
#define snow_vertical_compose_r2r_sub(s0,s1,s2,s3,t0,t1,t2,t3)\
"psubw %%"s0", %%"t0" \n\t"\
"psubw %%"s1", %%"t1" \n\t"\
"psubw %%"s2", %%"t2" \n\t"\
"psubw %%"s3", %%"t3" \n\t"
#define snow_vertical_compose_sse2_store(w,s0,s1,s2,s3)\
"movdqa %%"s0", ("w",%%"REG_d") \n\t"\
"movdqa %%"s1", 16("w",%%"REG_d") \n\t"\
"movdqa %%"s2", 32("w",%%"REG_d") \n\t"\
"movdqa %%"s3", 48("w",%%"REG_d") \n\t"
#define snow_vertical_compose_sra(n,t0,t1,t2,t3)\
"psraw $"n", %%"t0" \n\t"\
"psraw $"n", %%"t1" \n\t"\
"psraw $"n", %%"t2" \n\t"\
"psraw $"n", %%"t3" \n\t"
#define snow_vertical_compose_r2r_add(s0,s1,s2,s3,t0,t1,t2,t3)\
"paddw %%"s0", %%"t0" \n\t"\
"paddw %%"s1", %%"t1" \n\t"\
"paddw %%"s2", %%"t2" \n\t"\
"paddw %%"s3", %%"t3" \n\t"
#define snow_vertical_compose_r2r_pmulhw(s0,s1,s2,s3,t0,t1,t2,t3)\
"pmulhw %%"s0", %%"t0" \n\t"\
"pmulhw %%"s1", %%"t1" \n\t"\
"pmulhw %%"s2", %%"t2" \n\t"\
"pmulhw %%"s3", %%"t3" \n\t"
#define snow_vertical_compose_sse2_move(s0,s1,s2,s3,t0,t1,t2,t3)\
"movdqa %%"s0", %%"t0" \n\t"\
"movdqa %%"s1", %%"t1" \n\t"\
"movdqa %%"s2", %%"t2" \n\t"\
"movdqa %%"s3", %%"t3" \n\t"
void ff_snow_vertical_compose97i_sse2(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width){
x86_reg i = width;
while(i & 0x1F)
{
i--;
b4[i] -= (W_DM*(b3[i] + b5[i])+W_DO)>>W_DS;
b3[i] -= (W_CM*(b2[i] + b4[i])+W_CO)>>W_CS;
b2[i] += (W_BM*(b1[i] + b3[i])+4*b2[i]+W_BO)>>W_BS;
b1[i] += (W_AM*(b0[i] + b2[i])+W_AO)>>W_AS;
}
i+=i;
asm volatile (
"jmp 2f \n\t"
"1: \n\t"
snow_vertical_compose_sse2_load("%4","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%6","xmm0","xmm2","xmm4","xmm6")
"pcmpeqw %%xmm0, %%xmm0 \n\t"
"pcmpeqw %%xmm2, %%xmm2 \n\t"
"paddw %%xmm2, %%xmm2 \n\t"
"paddw %%xmm0, %%xmm2 \n\t"
"psllw $13, %%xmm2 \n\t"
snow_vertical_compose_r2r_add("xmm0","xmm0","xmm0","xmm0","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_r2r_pmulhw("xmm2","xmm2","xmm2","xmm2","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_sse2_add("%5","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_sse2_store("%5","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_sse2_load("%4","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%3","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_r2r_sub("xmm1","xmm3","xmm5","xmm7","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_store("%4","xmm0","xmm2","xmm4","xmm6")
"pcmpeqw %%xmm7, %%xmm7 \n\t"
"pcmpeqw %%xmm5, %%xmm5 \n\t"
"psllw $15, %%xmm7 \n\t"
"psrlw $13, %%xmm5 \n\t"
"paddw %%xmm7, %%xmm5 \n\t"
snow_vertical_compose_r2r_add("xmm5","xmm5","xmm5","xmm5","xmm0","xmm2","xmm4","xmm6")
"movq (%2,%%"REG_d"), %%xmm1 \n\t"
"movq 8(%2,%%"REG_d"), %%xmm3 \n\t"
"paddw %%xmm7, %%xmm1 \n\t"
"paddw %%xmm7, %%xmm3 \n\t"
"pavgw %%xmm1, %%xmm0 \n\t"
"pavgw %%xmm3, %%xmm2 \n\t"
"movq 16(%2,%%"REG_d"), %%xmm1 \n\t"
"movq 24(%2,%%"REG_d"), %%xmm3 \n\t"
"paddw %%xmm7, %%xmm1 \n\t"
"paddw %%xmm7, %%xmm3 \n\t"
"pavgw %%xmm1, %%xmm4 \n\t"
"pavgw %%xmm3, %%xmm6 \n\t"
snow_vertical_compose_r2r_sub("xmm7","xmm7","xmm7","xmm7","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sra("1","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%3","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sra("2","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%3","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_store("%3","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%1","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_move("xmm0","xmm2","xmm4","xmm6","xmm1","xmm3","xmm5","xmm7")
snow_vertical_compose_sra("1","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_r2r_add("xmm1","xmm3","xmm5","xmm7","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_add("%2","xmm0","xmm2","xmm4","xmm6")
snow_vertical_compose_sse2_store("%2","xmm0","xmm2","xmm4","xmm6")
"2: \n\t"
"sub $64, %%"REG_d" \n\t"
"jge 1b \n\t"
:"+d"(i)
:"r"(b0),"r"(b1),"r"(b2),"r"(b3),"r"(b4),"r"(b5));
}
#define snow_vertical_compose_mmx_load_add(op,r,t0,t1,t2,t3)\
""op" ("r",%%"REG_d"), %%"t0" \n\t"\
""op" 8("r",%%"REG_d"), %%"t1" \n\t"\
""op" 16("r",%%"REG_d"), %%"t2" \n\t"\
""op" 24("r",%%"REG_d"), %%"t3" \n\t"
#define snow_vertical_compose_mmx_load(r,t0,t1,t2,t3)\
snow_vertical_compose_mmx_load_add("movq",r,t0,t1,t2,t3)
#define snow_vertical_compose_mmx_add(r,t0,t1,t2,t3)\
snow_vertical_compose_mmx_load_add("paddw",r,t0,t1,t2,t3)
#define snow_vertical_compose_mmx_store(w,s0,s1,s2,s3)\
"movq %%"s0", ("w",%%"REG_d") \n\t"\
"movq %%"s1", 8("w",%%"REG_d") \n\t"\
"movq %%"s2", 16("w",%%"REG_d") \n\t"\
"movq %%"s3", 24("w",%%"REG_d") \n\t"
#define snow_vertical_compose_mmx_move(s0,s1,s2,s3,t0,t1,t2,t3)\
"movq %%"s0", %%"t0" \n\t"\
"movq %%"s1", %%"t1" \n\t"\
"movq %%"s2", %%"t2" \n\t"\
"movq %%"s3", %%"t3" \n\t"
void ff_snow_vertical_compose97i_mmx(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width){
x86_reg i = width;
while(i & 15)
{
i--;
b4[i] -= (W_DM*(b3[i] + b5[i])+W_DO)>>W_DS;
b3[i] -= (W_CM*(b2[i] + b4[i])+W_CO)>>W_CS;
b2[i] += (W_BM*(b1[i] + b3[i])+4*b2[i]+W_BO)>>W_BS;
b1[i] += (W_AM*(b0[i] + b2[i])+W_AO)>>W_AS;
}
i+=i;
asm volatile(
"jmp 2f \n\t"
"1: \n\t"
snow_vertical_compose_mmx_load("%4","mm1","mm3","mm5","mm7")
snow_vertical_compose_mmx_add("%6","mm1","mm3","mm5","mm7")
"pcmpeqw %%mm0, %%mm0 \n\t"
"pcmpeqw %%mm2, %%mm2 \n\t"
"paddw %%mm2, %%mm2 \n\t"
"paddw %%mm0, %%mm2 \n\t"
"psllw $13, %%mm2 \n\t"
snow_vertical_compose_r2r_add("mm0","mm0","mm0","mm0","mm1","mm3","mm5","mm7")
snow_vertical_compose_r2r_pmulhw("mm2","mm2","mm2","mm2","mm1","mm3","mm5","mm7")
snow_vertical_compose_mmx_add("%5","mm1","mm3","mm5","mm7")
snow_vertical_compose_mmx_store("%5","mm1","mm3","mm5","mm7")
snow_vertical_compose_mmx_load("%4","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%3","mm1","mm3","mm5","mm7")
snow_vertical_compose_r2r_sub("mm1","mm3","mm5","mm7","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_store("%4","mm0","mm2","mm4","mm6")
"pcmpeqw %%mm7, %%mm7 \n\t"
"pcmpeqw %%mm5, %%mm5 \n\t"
"psllw $15, %%mm7 \n\t"
"psrlw $13, %%mm5 \n\t"
"paddw %%mm7, %%mm5 \n\t"
snow_vertical_compose_r2r_add("mm5","mm5","mm5","mm5","mm0","mm2","mm4","mm6")
"movq (%2,%%"REG_d"), %%mm1 \n\t"
"movq 8(%2,%%"REG_d"), %%mm3 \n\t"
"paddw %%mm7, %%mm1 \n\t"
"paddw %%mm7, %%mm3 \n\t"
"pavgw %%mm1, %%mm0 \n\t"
"pavgw %%mm3, %%mm2 \n\t"
"movq 16(%2,%%"REG_d"), %%mm1 \n\t"
"movq 24(%2,%%"REG_d"), %%mm3 \n\t"
"paddw %%mm7, %%mm1 \n\t"
"paddw %%mm7, %%mm3 \n\t"
"pavgw %%mm1, %%mm4 \n\t"
"pavgw %%mm3, %%mm6 \n\t"
snow_vertical_compose_r2r_sub("mm7","mm7","mm7","mm7","mm0","mm2","mm4","mm6")
snow_vertical_compose_sra("1","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%3","mm0","mm2","mm4","mm6")
snow_vertical_compose_sra("2","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%3","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_store("%3","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%1","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_move("mm0","mm2","mm4","mm6","mm1","mm3","mm5","mm7")
snow_vertical_compose_sra("1","mm0","mm2","mm4","mm6")
snow_vertical_compose_r2r_add("mm1","mm3","mm5","mm7","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_add("%2","mm0","mm2","mm4","mm6")
snow_vertical_compose_mmx_store("%2","mm0","mm2","mm4","mm6")
"2: \n\t"
"sub $32, %%"REG_d" \n\t"
"jge 1b \n\t"
:"+d"(i)
:"r"(b0),"r"(b1),"r"(b2),"r"(b3),"r"(b4),"r"(b5));
}
#endif //HAVE_7REGS
#define snow_inner_add_yblock_sse2_header \
IDWTELEM * * dst_array = sb->line + src_y;\
x86_reg tmp;\
asm volatile(\
"mov %7, %%"REG_c" \n\t"\
"mov %6, %2 \n\t"\
"mov %4, %%"REG_S" \n\t"\
"pxor %%xmm7, %%xmm7 \n\t" /* 0 */\
"pcmpeqd %%xmm3, %%xmm3 \n\t"\
"psllw $15, %%xmm3 \n\t"\
"psrlw $12, %%xmm3 \n\t" /* FRAC_BITS >> 1 */\
"1: \n\t"\
"mov %1, %%"REG_D" \n\t"\
"mov (%%"REG_D"), %%"REG_D" \n\t"\
"add %3, %%"REG_D" \n\t"
#define snow_inner_add_yblock_sse2_start_8(out_reg1, out_reg2, ptr_offset, s_offset)\
"mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
"movq (%%"REG_d"), %%"out_reg1" \n\t"\
"movq (%%"REG_d", %%"REG_c"), %%"out_reg2" \n\t"\
"punpcklbw %%xmm7, %%"out_reg1" \n\t"\
"punpcklbw %%xmm7, %%"out_reg2" \n\t"\
"movq "s_offset"(%%"REG_S"), %%xmm0 \n\t"\
"movq "s_offset"+16(%%"REG_S"), %%xmm4 \n\t"\
"punpcklbw %%xmm7, %%xmm0 \n\t"\
"punpcklbw %%xmm7, %%xmm4 \n\t"\
"pmullw %%xmm0, %%"out_reg1" \n\t"\
"pmullw %%xmm4, %%"out_reg2" \n\t"
#define snow_inner_add_yblock_sse2_start_16(out_reg1, out_reg2, ptr_offset, s_offset)\
"mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
"movq (%%"REG_d"), %%"out_reg1" \n\t"\
"movq 8(%%"REG_d"), %%"out_reg2" \n\t"\
"punpcklbw %%xmm7, %%"out_reg1" \n\t"\
"punpcklbw %%xmm7, %%"out_reg2" \n\t"\
"movq "s_offset"(%%"REG_S"), %%xmm0 \n\t"\
"movq "s_offset"+8(%%"REG_S"), %%xmm4 \n\t"\
"punpcklbw %%xmm7, %%xmm0 \n\t"\
"punpcklbw %%xmm7, %%xmm4 \n\t"\
"pmullw %%xmm0, %%"out_reg1" \n\t"\
"pmullw %%xmm4, %%"out_reg2" \n\t"
#define snow_inner_add_yblock_sse2_accum_8(ptr_offset, s_offset) \
snow_inner_add_yblock_sse2_start_8("xmm2", "xmm6", ptr_offset, s_offset)\
"paddusw %%xmm2, %%xmm1 \n\t"\
"paddusw %%xmm6, %%xmm5 \n\t"
#define snow_inner_add_yblock_sse2_accum_16(ptr_offset, s_offset) \
snow_inner_add_yblock_sse2_start_16("xmm2", "xmm6", ptr_offset, s_offset)\
"paddusw %%xmm2, %%xmm1 \n\t"\
"paddusw %%xmm6, %%xmm5 \n\t"
#define snow_inner_add_yblock_sse2_end_common1\
"add $32, %%"REG_S" \n\t"\
"add %%"REG_c", %0 \n\t"\
"add %%"REG_c", "PTR_SIZE"*3(%%"REG_a");\n\t"\
"add %%"REG_c", "PTR_SIZE"*2(%%"REG_a");\n\t"\
"add %%"REG_c", "PTR_SIZE"*1(%%"REG_a");\n\t"\
"add %%"REG_c", (%%"REG_a") \n\t"
#define snow_inner_add_yblock_sse2_end_common2\
"jnz 1b \n\t"\
:"+m"(dst8),"+m"(dst_array),"=&r"(tmp)\
:\
"rm"((x86_reg)(src_x<<1)),"m"(obmc),"a"(block),"m"((x86_reg)b_h),"m"((x86_reg)src_stride):\
"%"REG_c"","%"REG_S"","%"REG_D"","%"REG_d"");
#define snow_inner_add_yblock_sse2_end_8\
"sal $1, %%"REG_c" \n\t"\
"add $"PTR_SIZE"*2, %1 \n\t"\
snow_inner_add_yblock_sse2_end_common1\
"sar $1, %%"REG_c" \n\t"\
"sub $2, %2 \n\t"\
snow_inner_add_yblock_sse2_end_common2
#define snow_inner_add_yblock_sse2_end_16\
"add $"PTR_SIZE"*1, %1 \n\t"\
snow_inner_add_yblock_sse2_end_common1\
"dec %2 \n\t"\
snow_inner_add_yblock_sse2_end_common2
static void inner_add_yblock_bw_8_obmc_16_bh_even_sse2(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
snow_inner_add_yblock_sse2_header
snow_inner_add_yblock_sse2_start_8("xmm1", "xmm5", "3", "0")
snow_inner_add_yblock_sse2_accum_8("2", "8")
snow_inner_add_yblock_sse2_accum_8("1", "128")
snow_inner_add_yblock_sse2_accum_8("0", "136")
"mov %0, %%"REG_d" \n\t"
"movdqa (%%"REG_D"), %%xmm0 \n\t"
"movdqa %%xmm1, %%xmm2 \n\t"
"punpckhwd %%xmm7, %%xmm1 \n\t"
"punpcklwd %%xmm7, %%xmm2 \n\t"
"paddd %%xmm2, %%xmm0 \n\t"
"movdqa 16(%%"REG_D"), %%xmm2 \n\t"
"paddd %%xmm1, %%xmm2 \n\t"
"paddd %%xmm3, %%xmm0 \n\t"
"paddd %%xmm3, %%xmm2 \n\t"
"mov %1, %%"REG_D" \n\t"
"mov "PTR_SIZE"(%%"REG_D"), %%"REG_D";\n\t"
"add %3, %%"REG_D" \n\t"
"movdqa (%%"REG_D"), %%xmm4 \n\t"
"movdqa %%xmm5, %%xmm6 \n\t"
"punpckhwd %%xmm7, %%xmm5 \n\t"
"punpcklwd %%xmm7, %%xmm6 \n\t"
"paddd %%xmm6, %%xmm4 \n\t"
"movdqa 16(%%"REG_D"), %%xmm6 \n\t"
"paddd %%xmm5, %%xmm6 \n\t"
"paddd %%xmm3, %%xmm4 \n\t"
"paddd %%xmm3, %%xmm6 \n\t"
"psrad $8, %%xmm0 \n\t" /* FRAC_BITS. */
"psrad $8, %%xmm2 \n\t" /* FRAC_BITS. */
"packssdw %%xmm2, %%xmm0 \n\t"
"packuswb %%xmm7, %%xmm0 \n\t"
"movq %%xmm0, (%%"REG_d") \n\t"
"psrad $8, %%xmm4 \n\t" /* FRAC_BITS. */
"psrad $8, %%xmm6 \n\t" /* FRAC_BITS. */
"packssdw %%xmm6, %%xmm4 \n\t"
"packuswb %%xmm7, %%xmm4 \n\t"
"movq %%xmm4, (%%"REG_d",%%"REG_c");\n\t"
snow_inner_add_yblock_sse2_end_8
}
static void inner_add_yblock_bw_16_obmc_32_sse2(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
snow_inner_add_yblock_sse2_header
snow_inner_add_yblock_sse2_start_16("xmm1", "xmm5", "3", "0")
snow_inner_add_yblock_sse2_accum_16("2", "16")
snow_inner_add_yblock_sse2_accum_16("1", "512")
snow_inner_add_yblock_sse2_accum_16("0", "528")
"mov %0, %%"REG_d" \n\t"
"psrlw $4, %%xmm1 \n\t"
"psrlw $4, %%xmm5 \n\t"
"paddw (%%"REG_D"), %%xmm1 \n\t"
"paddw 16(%%"REG_D"), %%xmm5 \n\t"
"paddw %%xmm3, %%xmm1 \n\t"
"paddw %%xmm3, %%xmm5 \n\t"
"psraw $4, %%xmm1 \n\t" /* FRAC_BITS. */
"psraw $4, %%xmm5 \n\t" /* FRAC_BITS. */
"packuswb %%xmm5, %%xmm1 \n\t"
"movdqu %%xmm1, (%%"REG_d") \n\t"
snow_inner_add_yblock_sse2_end_16
}
#define snow_inner_add_yblock_mmx_header \
IDWTELEM * * dst_array = sb->line + src_y;\
x86_reg tmp;\
asm volatile(\
"mov %7, %%"REG_c" \n\t"\
"mov %6, %2 \n\t"\
"mov %4, %%"REG_S" \n\t"\
"pxor %%mm7, %%mm7 \n\t" /* 0 */\
"pcmpeqd %%mm3, %%mm3 \n\t"\
"psllw $15, %%mm3 \n\t"\
"psrlw $12, %%mm3 \n\t" /* FRAC_BITS >> 1 */\
"1: \n\t"\
"mov %1, %%"REG_D" \n\t"\
"mov (%%"REG_D"), %%"REG_D" \n\t"\
"add %3, %%"REG_D" \n\t"
#define snow_inner_add_yblock_mmx_start(out_reg1, out_reg2, ptr_offset, s_offset, d_offset)\
"mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
"movd "d_offset"(%%"REG_d"), %%"out_reg1" \n\t"\
"movd "d_offset"+4(%%"REG_d"), %%"out_reg2" \n\t"\
"punpcklbw %%mm7, %%"out_reg1" \n\t"\
"punpcklbw %%mm7, %%"out_reg2" \n\t"\
"movd "s_offset"(%%"REG_S"), %%mm0 \n\t"\
"movd "s_offset"+4(%%"REG_S"), %%mm4 \n\t"\
"punpcklbw %%mm7, %%mm0 \n\t"\
"punpcklbw %%mm7, %%mm4 \n\t"\
"pmullw %%mm0, %%"out_reg1" \n\t"\
"pmullw %%mm4, %%"out_reg2" \n\t"
#define snow_inner_add_yblock_mmx_accum(ptr_offset, s_offset, d_offset) \
snow_inner_add_yblock_mmx_start("mm2", "mm6", ptr_offset, s_offset, d_offset)\
"paddusw %%mm2, %%mm1 \n\t"\
"paddusw %%mm6, %%mm5 \n\t"
#define snow_inner_add_yblock_mmx_mix(read_offset, write_offset)\
"mov %0, %%"REG_d" \n\t"\
"psrlw $4, %%mm1 \n\t"\
"psrlw $4, %%mm5 \n\t"\
"paddw "read_offset"(%%"REG_D"), %%mm1 \n\t"\
"paddw "read_offset"+8(%%"REG_D"), %%mm5 \n\t"\
"paddw %%mm3, %%mm1 \n\t"\
"paddw %%mm3, %%mm5 \n\t"\
"psraw $4, %%mm1 \n\t"\
"psraw $4, %%mm5 \n\t"\
"packuswb %%mm5, %%mm1 \n\t"\
"movq %%mm1, "write_offset"(%%"REG_d") \n\t"
#define snow_inner_add_yblock_mmx_end(s_step)\
"add $"s_step", %%"REG_S" \n\t"\
"add %%"REG_c", "PTR_SIZE"*3(%%"REG_a");\n\t"\
"add %%"REG_c", "PTR_SIZE"*2(%%"REG_a");\n\t"\
"add %%"REG_c", "PTR_SIZE"*1(%%"REG_a");\n\t"\
"add %%"REG_c", (%%"REG_a") \n\t"\
"add $"PTR_SIZE"*1, %1 \n\t"\
"add %%"REG_c", %0 \n\t"\
"dec %2 \n\t"\
"jnz 1b \n\t"\
:"+m"(dst8),"+m"(dst_array),"=&r"(tmp)\
:\
"rm"((x86_reg)(src_x<<1)),"m"(obmc),"a"(block),"m"((x86_reg)b_h),"m"((x86_reg)src_stride):\
"%"REG_c"","%"REG_S"","%"REG_D"","%"REG_d"");
static void inner_add_yblock_bw_8_obmc_16_mmx(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
snow_inner_add_yblock_mmx_header
snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "0", "0")
snow_inner_add_yblock_mmx_accum("2", "8", "0")
snow_inner_add_yblock_mmx_accum("1", "128", "0")
snow_inner_add_yblock_mmx_accum("0", "136", "0")
snow_inner_add_yblock_mmx_mix("0", "0")
snow_inner_add_yblock_mmx_end("16")
}
static void inner_add_yblock_bw_16_obmc_32_mmx(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
snow_inner_add_yblock_mmx_header
snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "0", "0")
snow_inner_add_yblock_mmx_accum("2", "16", "0")
snow_inner_add_yblock_mmx_accum("1", "512", "0")
snow_inner_add_yblock_mmx_accum("0", "528", "0")
snow_inner_add_yblock_mmx_mix("0", "0")
snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "8", "8")
snow_inner_add_yblock_mmx_accum("2", "24", "8")
snow_inner_add_yblock_mmx_accum("1", "520", "8")
snow_inner_add_yblock_mmx_accum("0", "536", "8")
snow_inner_add_yblock_mmx_mix("16", "8")
snow_inner_add_yblock_mmx_end("32")
}
void ff_snow_inner_add_yblock_sse2(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h,
int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){
if (b_w == 16)
inner_add_yblock_bw_16_obmc_32_sse2(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
else if (b_w == 8 && obmc_stride == 16) {
if (!(b_h & 1))
inner_add_yblock_bw_8_obmc_16_bh_even_sse2(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
else
inner_add_yblock_bw_8_obmc_16_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
} else
ff_snow_inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
}
void ff_snow_inner_add_yblock_mmx(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h,
int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){
if (b_w == 16)
inner_add_yblock_bw_16_obmc_32_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
else if (b_w == 8 && obmc_stride == 16)
inner_add_yblock_bw_8_obmc_16_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
else
ff_snow_inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
}
@@ -0,0 +1,490 @@
/*
* VC-1 and WMV3 - DSP functions MMX-optimized
* Copyright (c) 2007 Christophe GISQUET <[email protected]>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libavutil/x86_cpu.h"
#include "libavcodec/dsputil.h"
#include "dsputil_mmx.h"
/** Add rounder from mm7 to mm3 and pack result at destination */
#define NORMALIZE_MMX(SHIFT) \
"paddw %%mm7, %%mm3 \n\t" /* +bias-r */ \
"paddw %%mm7, %%mm4 \n\t" /* +bias-r */ \
"psraw "SHIFT", %%mm3 \n\t" \
"psraw "SHIFT", %%mm4 \n\t"
#define TRANSFER_DO_PACK \
"packuswb %%mm4, %%mm3 \n\t" \
"movq %%mm3, (%2) \n\t"
#define TRANSFER_DONT_PACK \
"movq %%mm3, 0(%2) \n\t" \
"movq %%mm4, 8(%2) \n\t"
/** @see MSPEL_FILTER13_CORE for use as UNPACK macro */
#define DO_UNPACK(reg) "punpcklbw %%mm0, " reg "\n\t"
#define DONT_UNPACK(reg)
/** Compute the rounder 32-r or 8-r and unpacks it to mm7 */
#define LOAD_ROUNDER_MMX(ROUND) \
"movd "ROUND", %%mm7 \n\t" \
"punpcklwd %%mm7, %%mm7 \n\t" \
"punpckldq %%mm7, %%mm7 \n\t"
#define SHIFT2_LINE(OFF, R0,R1,R2,R3) \
"paddw %%mm"#R2", %%mm"#R1" \n\t" \
"movd (%0,%3), %%mm"#R0" \n\t" \
"pmullw %%mm6, %%mm"#R1" \n\t" \
"punpcklbw %%mm0, %%mm"#R0" \n\t" \
"movd (%0,%2), %%mm"#R3" \n\t" \
"psubw %%mm"#R0", %%mm"#R1" \n\t" \
"punpcklbw %%mm0, %%mm"#R3" \n\t" \
"paddw %%mm7, %%mm"#R1" \n\t" \
"psubw %%mm"#R3", %%mm"#R1" \n\t" \
"psraw %4, %%mm"#R1" \n\t" \
"movq %%mm"#R1", "#OFF"(%1) \n\t" \
"add %2, %0 \n\t"
DECLARE_ALIGNED_16(const uint64_t, ff_pw_9) = 0x0009000900090009ULL;
/** Sacrifying mm6 allows to pipeline loads from src */
static void vc1_put_ver_16b_shift2_mmx(int16_t *dst,
const uint8_t *src, x86_reg stride,
int rnd, int64_t shift)
{
asm volatile(
"mov $3, %%"REG_c" \n\t"
LOAD_ROUNDER_MMX("%5")
"movq "MANGLE(ff_pw_9)", %%mm6 \n\t"
"1: \n\t"
"movd (%0), %%mm2 \n\t"
"add %2, %0 \n\t"
"movd (%0), %%mm3 \n\t"
"punpcklbw %%mm0, %%mm2 \n\t"
"punpcklbw %%mm0, %%mm3 \n\t"
SHIFT2_LINE( 0, 1, 2, 3, 4)
SHIFT2_LINE( 24, 2, 3, 4, 1)
SHIFT2_LINE( 48, 3, 4, 1, 2)
SHIFT2_LINE( 72, 4, 1, 2, 3)
SHIFT2_LINE( 96, 1, 2, 3, 4)
SHIFT2_LINE(120, 2, 3, 4, 1)
SHIFT2_LINE(144, 3, 4, 1, 2)
SHIFT2_LINE(168, 4, 1, 2, 3)
"sub %6, %0 \n\t"
"add $8, %1 \n\t"
"dec %%"REG_c" \n\t"
"jnz 1b \n\t"
: "+r"(src), "+r"(dst)
: "r"(stride), "r"(-2*stride),
"m"(shift), "m"(rnd), "r"(9*stride-4)
: "%"REG_c, "memory"
);
}
/**
* Data is already unpacked, so some operations can directly be made from
* memory.
*/
static void vc1_put_hor_16b_shift2_mmx(uint8_t *dst, x86_reg stride,
const int16_t *src, int rnd)
{
int h = 8;
src -= 1;
rnd -= (-1+9+9-1)*1024; /* Add -1024 bias */
asm volatile(
LOAD_ROUNDER_MMX("%4")
"movq "MANGLE(ff_pw_128)", %%mm6\n\t"
"movq "MANGLE(ff_pw_9)", %%mm5 \n\t"
"1: \n\t"
"movq 2*0+0(%1), %%mm1 \n\t"
"movq 2*0+8(%1), %%mm2 \n\t"
"movq 2*1+0(%1), %%mm3 \n\t"
"movq 2*1+8(%1), %%mm4 \n\t"
"paddw 2*3+0(%1), %%mm1 \n\t"
"paddw 2*3+8(%1), %%mm2 \n\t"
"paddw 2*2+0(%1), %%mm3 \n\t"
"paddw 2*2+8(%1), %%mm4 \n\t"
"pmullw %%mm5, %%mm3 \n\t"
"pmullw %%mm5, %%mm4 \n\t"
"psubw %%mm1, %%mm3 \n\t"
"psubw %%mm2, %%mm4 \n\t"
NORMALIZE_MMX("$7")
/* Remove bias */
"paddw %%mm6, %%mm3 \n\t"
"paddw %%mm6, %%mm4 \n\t"
TRANSFER_DO_PACK
"add $24, %1 \n\t"
"add %3, %2 \n\t"
"decl %0 \n\t"
"jnz 1b \n\t"
: "+r"(h), "+r" (src), "+r" (dst)
: "r"(stride), "m"(rnd)
: "memory"
);
}
/**
* Purely vertical or horizontal 1/2 shift interpolation.
* Sacrify mm6 for *9 factor.
*/
static void vc1_put_shift2_mmx(uint8_t *dst, const uint8_t *src,
x86_reg stride, int rnd, x86_reg offset)
{
rnd = 8-rnd;
asm volatile(
"mov $8, %%"REG_c" \n\t"
LOAD_ROUNDER_MMX("%5")
"movq "MANGLE(ff_pw_9)", %%mm6\n\t"
"1: \n\t"
"movd 0(%0 ), %%mm3 \n\t"
"movd 4(%0 ), %%mm4 \n\t"
"movd 0(%0,%2), %%mm1 \n\t"
"movd 4(%0,%2), %%mm2 \n\t"
"add %2, %0 \n\t"
"punpcklbw %%mm0, %%mm3 \n\t"
"punpcklbw %%mm0, %%mm4 \n\t"
"punpcklbw %%mm0, %%mm1 \n\t"
"punpcklbw %%mm0, %%mm2 \n\t"
"paddw %%mm1, %%mm3 \n\t"
"paddw %%mm2, %%mm4 \n\t"
"movd 0(%0,%3), %%mm1 \n\t"
"movd 4(%0,%3), %%mm2 \n\t"
"pmullw %%mm6, %%mm3 \n\t" /* 0,9,9,0*/
"pmullw %%mm6, %%mm4 \n\t" /* 0,9,9,0*/
"punpcklbw %%mm0, %%mm1 \n\t"
"punpcklbw %%mm0, %%mm2 \n\t"
"psubw %%mm1, %%mm3 \n\t" /*-1,9,9,0*/
"psubw %%mm2, %%mm4 \n\t" /*-1,9,9,0*/
"movd 0(%0,%2), %%mm1 \n\t"
"movd 4(%0,%2), %%mm2 \n\t"
"punpcklbw %%mm0, %%mm1 \n\t"
"punpcklbw %%mm0, %%mm2 \n\t"
"psubw %%mm1, %%mm3 \n\t" /*-1,9,9,-1*/
"psubw %%mm2, %%mm4 \n\t" /*-1,9,9,-1*/
NORMALIZE_MMX("$4")
"packuswb %%mm4, %%mm3 \n\t"
"movq %%mm3, (%1) \n\t"
"add %6, %0 \n\t"
"add %4, %1 \n\t"
"dec %%"REG_c" \n\t"
"jnz 1b \n\t"
: "+r"(src), "+r"(dst)
: "r"(offset), "r"(-2*offset), "g"(stride), "m"(rnd),
"g"(stride-offset)
: "%"REG_c, "memory"
);
}
/**
* Filter coefficients made global to allow access by all 1 or 3 quarter shift
* interpolation functions.
*/
DECLARE_ALIGNED_16(const uint64_t, ff_pw_53) = 0x0035003500350035ULL;
DECLARE_ALIGNED_16(const uint64_t, ff_pw_18) = 0x0012001200120012ULL;
/**
* Core of the 1/4 and 3/4 shift bicubic interpolation.
*
* @param UNPACK Macro unpacking arguments from 8 to 16bits (can be empty).
* @param MOVQ "movd 1" or "movq 2", if data read is already unpacked.
* @param A1 Address of 1st tap (beware of unpacked/packed).
* @param A2 Address of 2nd tap
* @param A3 Address of 3rd tap
* @param A4 Address of 4th tap
*/
#define MSPEL_FILTER13_CORE(UNPACK, MOVQ, A1, A2, A3, A4) \
MOVQ "*0+"A1", %%mm1 \n\t" \
MOVQ "*4+"A1", %%mm2 \n\t" \
UNPACK("%%mm1") \
UNPACK("%%mm2") \
"pmullw "MANGLE(ff_pw_3)", %%mm1\n\t" \
"pmullw "MANGLE(ff_pw_3)", %%mm2\n\t" \
MOVQ "*0+"A2", %%mm3 \n\t" \
MOVQ "*4+"A2", %%mm4 \n\t" \
UNPACK("%%mm3") \
UNPACK("%%mm4") \
"pmullw %%mm6, %%mm3 \n\t" /* *18 */ \
"pmullw %%mm6, %%mm4 \n\t" /* *18 */ \
"psubw %%mm1, %%mm3 \n\t" /* 18,-3 */ \
"psubw %%mm2, %%mm4 \n\t" /* 18,-3 */ \
MOVQ "*0+"A4", %%mm1 \n\t" \
MOVQ "*4+"A4", %%mm2 \n\t" \
UNPACK("%%mm1") \
UNPACK("%%mm2") \
"psllw $2, %%mm1 \n\t" /* 4* */ \
"psllw $2, %%mm2 \n\t" /* 4* */ \
"psubw %%mm1, %%mm3 \n\t" /* -4,18,-3 */ \
"psubw %%mm2, %%mm4 \n\t" /* -4,18,-3 */ \
MOVQ "*0+"A3", %%mm1 \n\t" \
MOVQ "*4+"A3", %%mm2 \n\t" \
UNPACK("%%mm1") \
UNPACK("%%mm2") \
"pmullw %%mm5, %%mm1 \n\t" /* *53 */ \
"pmullw %%mm5, %%mm2 \n\t" /* *53 */ \
"paddw %%mm1, %%mm3 \n\t" /* 4,53,18,-3 */ \
"paddw %%mm2, %%mm4 \n\t" /* 4,53,18,-3 */
/**
* Macro to build the vertical 16bits version of vc1_put_shift[13].
* Here, offset=src_stride. Parameters passed A1 to A4 must use
* %3 (src_stride) and %4 (3*src_stride).
*
* @param NAME Either 1 or 3
* @see MSPEL_FILTER13_CORE for information on A1->A4
*/
#define MSPEL_FILTER13_VER_16B(NAME, A1, A2, A3, A4) \
static void \
vc1_put_ver_16b_ ## NAME ## _mmx(int16_t *dst, const uint8_t *src, \
x86_reg src_stride, \
int rnd, int64_t shift) \
{ \
int h = 8; \
src -= src_stride; \
asm volatile( \
LOAD_ROUNDER_MMX("%5") \
"movq "MANGLE(ff_pw_53)", %%mm5\n\t" \
"movq "MANGLE(ff_pw_18)", %%mm6\n\t" \
ASMALIGN(3) \
"1: \n\t" \
MSPEL_FILTER13_CORE(DO_UNPACK, "movd 1", A1, A2, A3, A4) \
NORMALIZE_MMX("%6") \
TRANSFER_DONT_PACK \
/* Last 3 (in fact 4) bytes on the line */ \
"movd 8+"A1", %%mm1 \n\t" \
DO_UNPACK("%%mm1") \
"movq %%mm1, %%mm3 \n\t" \
"paddw %%mm1, %%mm1 \n\t" \
"paddw %%mm3, %%mm1 \n\t" /* 3* */ \
"movd 8+"A2", %%mm3 \n\t" \
DO_UNPACK("%%mm3") \
"pmullw %%mm6, %%mm3 \n\t" /* *18 */ \
"psubw %%mm1, %%mm3 \n\t" /*18,-3 */ \
"movd 8+"A3", %%mm1 \n\t" \
DO_UNPACK("%%mm1") \
"pmullw %%mm5, %%mm1 \n\t" /* *53 */ \
"paddw %%mm1, %%mm3 \n\t" /*53,18,-3 */ \
"movd 8+"A4", %%mm1 \n\t" \
DO_UNPACK("%%mm1") \
"psllw $2, %%mm1 \n\t" /* 4* */ \
"psubw %%mm1, %%mm3 \n\t" \
"paddw %%mm7, %%mm3 \n\t" \
"psraw %6, %%mm3 \n\t" \
"movq %%mm3, 16(%2) \n\t" \
"add %3, %1 \n\t" \
"add $24, %2 \n\t" \
"decl %0 \n\t" \
"jnz 1b \n\t" \
: "+r"(h), "+r" (src), "+r" (dst) \
: "r"(src_stride), "r"(3*src_stride), \
"m"(rnd), "m"(shift) \
: "memory" \
); \
}
/**
* Macro to build the horizontal 16bits version of vc1_put_shift[13].
* Here, offset=16bits, so parameters passed A1 to A4 should be simple.
*
* @param NAME Either 1 or 3
* @see MSPEL_FILTER13_CORE for information on A1->A4
*/
#define MSPEL_FILTER13_HOR_16B(NAME, A1, A2, A3, A4) \
static void \
vc1_put_hor_16b_ ## NAME ## _mmx(uint8_t *dst, x86_reg stride, \
const int16_t *src, int rnd) \
{ \
int h = 8; \
src -= 1; \
rnd -= (-4+58+13-3)*256; /* Add -256 bias */ \
asm volatile( \
LOAD_ROUNDER_MMX("%4") \
"movq "MANGLE(ff_pw_18)", %%mm6 \n\t" \
"movq "MANGLE(ff_pw_53)", %%mm5 \n\t" \
ASMALIGN(3) \
"1: \n\t" \
MSPEL_FILTER13_CORE(DONT_UNPACK, "movq 2", A1, A2, A3, A4) \
NORMALIZE_MMX("$7") \
/* Remove bias */ \
"paddw "MANGLE(ff_pw_128)", %%mm3 \n\t" \
"paddw "MANGLE(ff_pw_128)", %%mm4 \n\t" \
TRANSFER_DO_PACK \
"add $24, %1 \n\t" \
"add %3, %2 \n\t" \
"decl %0 \n\t" \
"jnz 1b \n\t" \
: "+r"(h), "+r" (src), "+r" (dst) \
: "r"(stride), "m"(rnd) \
: "memory" \
); \
}
/**
* Macro to build the 8bits, any direction, version of vc1_put_shift[13].
* Here, offset=src_stride. Parameters passed A1 to A4 must use
* %3 (offset) and %4 (3*offset).
*
* @param NAME Either 1 or 3
* @see MSPEL_FILTER13_CORE for information on A1->A4
*/
#define MSPEL_FILTER13_8B(NAME, A1, A2, A3, A4) \
static void \
vc1_put_## NAME ## _mmx(uint8_t *dst, const uint8_t *src, \
x86_reg stride, int rnd, x86_reg offset) \
{ \
int h = 8; \
src -= offset; \
rnd = 32-rnd; \
asm volatile ( \
LOAD_ROUNDER_MMX("%6") \
"movq "MANGLE(ff_pw_53)", %%mm5 \n\t" \
"movq "MANGLE(ff_pw_18)", %%mm6 \n\t" \
ASMALIGN(3) \
"1: \n\t" \
MSPEL_FILTER13_CORE(DO_UNPACK, "movd 1", A1, A2, A3, A4) \
NORMALIZE_MMX("$6") \
TRANSFER_DO_PACK \
"add %5, %1 \n\t" \
"add %5, %2 \n\t" \
"decl %0 \n\t" \
"jnz 1b \n\t" \
: "+r"(h), "+r" (src), "+r" (dst) \
: "r"(offset), "r"(3*offset), "g"(stride), "m"(rnd) \
: "memory" \
); \
}
/** 1/4 shift bicubic interpolation */
MSPEL_FILTER13_8B (shift1, "0(%1,%4 )", "0(%1,%3,2)", "0(%1,%3 )", "0(%1 )")
MSPEL_FILTER13_VER_16B(shift1, "0(%1,%4 )", "0(%1,%3,2)", "0(%1,%3 )", "0(%1 )")
MSPEL_FILTER13_HOR_16B(shift1, "2*3(%1)", "2*2(%1)", "2*1(%1)", "2*0(%1)")
/** 3/4 shift bicubic interpolation */
MSPEL_FILTER13_8B (shift3, "0(%1 )", "0(%1,%3 )", "0(%1,%3,2)", "0(%1,%4 )")
MSPEL_FILTER13_VER_16B(shift3, "0(%1 )", "0(%1,%3 )", "0(%1,%3,2)", "0(%1,%4 )")
MSPEL_FILTER13_HOR_16B(shift3, "2*0(%1)", "2*1(%1)", "2*2(%1)", "2*3(%1)")
typedef void (*vc1_mspel_mc_filter_ver_16bits)(int16_t *dst, const uint8_t *src, x86_reg src_stride, int rnd, int64_t shift);
typedef void (*vc1_mspel_mc_filter_hor_16bits)(uint8_t *dst, x86_reg dst_stride, const int16_t *src, int rnd);
typedef void (*vc1_mspel_mc_filter_8bits)(uint8_t *dst, const uint8_t *src, x86_reg stride, int rnd, x86_reg offset);
/**
* Interpolates fractional pel values by applying proper vertical then
* horizontal filter.
*
* @param dst Destination buffer for interpolated pels.
* @param src Source buffer.
* @param stride Stride for both src and dst buffers.
* @param hmode Horizontal filter (expressed in quarter pixels shift).
* @param hmode Vertical filter.
* @param rnd Rounding bias.
*/
static void vc1_mspel_mc(uint8_t *dst, const uint8_t *src, int stride,
int hmode, int vmode, int rnd)
{
static const vc1_mspel_mc_filter_ver_16bits vc1_put_shift_ver_16bits[] =
{ NULL, vc1_put_ver_16b_shift1_mmx, vc1_put_ver_16b_shift2_mmx, vc1_put_ver_16b_shift3_mmx };
static const vc1_mspel_mc_filter_hor_16bits vc1_put_shift_hor_16bits[] =
{ NULL, vc1_put_hor_16b_shift1_mmx, vc1_put_hor_16b_shift2_mmx, vc1_put_hor_16b_shift3_mmx };
static const vc1_mspel_mc_filter_8bits vc1_put_shift_8bits[] =
{ NULL, vc1_put_shift1_mmx, vc1_put_shift2_mmx, vc1_put_shift3_mmx };
asm volatile(
"pxor %%mm0, %%mm0 \n\t"
::: "memory"
);
if (vmode) { /* Vertical filter to apply */
if (hmode) { /* Horizontal filter to apply, output to tmp */
static const int shift_value[] = { 0, 5, 1, 5 };
int shift = (shift_value[hmode]+shift_value[vmode])>>1;
int r;
DECLARE_ALIGNED_16(int16_t, tmp[12*8]);
r = (1<<(shift-1)) + rnd-1;
vc1_put_shift_ver_16bits[vmode](tmp, src-1, stride, r, shift);
vc1_put_shift_hor_16bits[hmode](dst, stride, tmp+1, 64-rnd);
return;
}
else { /* No horizontal filter, output 8 lines to dst */
vc1_put_shift_8bits[vmode](dst, src, stride, 1-rnd, stride);
return;
}
}
/* Horizontal mode with no vertical mode */
vc1_put_shift_8bits[hmode](dst, src, stride, rnd, 1);
}
void ff_put_vc1_mspel_mc00_mmx(uint8_t *dst, const uint8_t *src, int stride, int rnd);
/** Macro to ease bicubic filter interpolation functions declarations */
#define DECLARE_FUNCTION(a, b) \
static void put_vc1_mspel_mc ## a ## b ## _mmx(uint8_t *dst, const uint8_t *src, int stride, int rnd) { \
vc1_mspel_mc(dst, src, stride, a, b, rnd); \
}
DECLARE_FUNCTION(0, 1)
DECLARE_FUNCTION(0, 2)
DECLARE_FUNCTION(0, 3)
DECLARE_FUNCTION(1, 0)
DECLARE_FUNCTION(1, 1)
DECLARE_FUNCTION(1, 2)
DECLARE_FUNCTION(1, 3)
DECLARE_FUNCTION(2, 0)
DECLARE_FUNCTION(2, 1)
DECLARE_FUNCTION(2, 2)
DECLARE_FUNCTION(2, 3)
DECLARE_FUNCTION(3, 0)
DECLARE_FUNCTION(3, 1)
DECLARE_FUNCTION(3, 2)
DECLARE_FUNCTION(3, 3)
void ff_vc1dsp_init_mmx(DSPContext* dsp, AVCodecContext *avctx) {
dsp->put_vc1_mspel_pixels_tab[ 0] = ff_put_vc1_mspel_mc00_mmx;
dsp->put_vc1_mspel_pixels_tab[ 4] = put_vc1_mspel_mc01_mmx;
dsp->put_vc1_mspel_pixels_tab[ 8] = put_vc1_mspel_mc02_mmx;
dsp->put_vc1_mspel_pixels_tab[12] = put_vc1_mspel_mc03_mmx;
dsp->put_vc1_mspel_pixels_tab[ 1] = put_vc1_mspel_mc10_mmx;
dsp->put_vc1_mspel_pixels_tab[ 5] = put_vc1_mspel_mc11_mmx;
dsp->put_vc1_mspel_pixels_tab[ 9] = put_vc1_mspel_mc12_mmx;
dsp->put_vc1_mspel_pixels_tab[13] = put_vc1_mspel_mc13_mmx;
dsp->put_vc1_mspel_pixels_tab[ 2] = put_vc1_mspel_mc20_mmx;
dsp->put_vc1_mspel_pixels_tab[ 6] = put_vc1_mspel_mc21_mmx;
dsp->put_vc1_mspel_pixels_tab[10] = put_vc1_mspel_mc22_mmx;
dsp->put_vc1_mspel_pixels_tab[14] = put_vc1_mspel_mc23_mmx;
dsp->put_vc1_mspel_pixels_tab[ 3] = put_vc1_mspel_mc30_mmx;
dsp->put_vc1_mspel_pixels_tab[ 7] = put_vc1_mspel_mc31_mmx;
dsp->put_vc1_mspel_pixels_tab[11] = put_vc1_mspel_mc32_mmx;
dsp->put_vc1_mspel_pixels_tab[15] = put_vc1_mspel_mc33_mmx;
}
@@ -0,0 +1,336 @@
/*
* Copyright (C) 2004 the ffmpeg project
*
* 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
*/
/**
* @file vp3dsp_mmx.c
* MMX-optimized functions cribbed from the original VP3 source code.
*/
#include "libavcodec/dsputil.h"
#include "mmx.h"
#define IdctAdjustBeforeShift 8
/* (12 * 4) 2-byte memory locations ( = 96 bytes total)
* idct_constants[0..15] = Mask table (M(I))
* idct_constants[16..43] = Cosine table (C(I))
* idct_constants[44..47] = 8
*/
static uint16_t idct_constants[(4 + 7 + 1) * 4];
static const uint16_t idct_cosine_table[7] = {
64277, 60547, 54491, 46341, 36410, 25080, 12785
};
#define r0 mm0
#define r1 mm1
#define r2 mm2
#define r3 mm3
#define r4 mm4
#define r5 mm5
#define r6 mm6
#define r7 mm7
/* from original comments: The Macro does IDct on 4 1-D Dcts */
#define BeginIDCT() { \
movq_m2r(*I(3), r2); \
movq_m2r(*C(3), r6); \
movq_r2r(r2, r4); \
movq_m2r(*J(5), r7); \
pmulhw_r2r(r6, r4); /* r4 = c3*i3 - i3 */ \
movq_m2r(*C(5), r1); \
pmulhw_r2r(r7, r6); /* r6 = c3*i5 - i5 */ \
movq_r2r(r1, r5); \
pmulhw_r2r(r2, r1); /* r1 = c5*i3 - i3 */ \
movq_m2r(*I(1), r3); \
pmulhw_r2r(r7, r5); /* r5 = c5*i5 - i5 */ \
movq_m2r(*C(1), r0); /* (all registers are in use) */ \
paddw_r2r(r2, r4); /* r4 = c3*i3 */ \
paddw_r2r(r7, r6); /* r6 = c3*i5 */ \
paddw_r2r(r1, r2); /* r2 = c5*i3 */ \
movq_m2r(*J(7), r1); \
paddw_r2r(r5, r7); /* r7 = c5*i5 */ \
movq_r2r(r0, r5); /* r5 = c1 */ \
pmulhw_r2r(r3, r0); /* r0 = c1*i1 - i1 */ \
paddsw_r2r(r7, r4); /* r4 = C = c3*i3 + c5*i5 */ \
pmulhw_r2r(r1, r5); /* r5 = c1*i7 - i7 */ \
movq_m2r(*C(7), r7); \
psubsw_r2r(r2, r6); /* r6 = D = c3*i5 - c5*i3 */ \
paddw_r2r(r3, r0); /* r0 = c1*i1 */ \
pmulhw_r2r(r7, r3); /* r3 = c7*i1 */ \
movq_m2r(*I(2), r2); \
pmulhw_r2r(r1, r7); /* r7 = c7*i7 */ \
paddw_r2r(r1, r5); /* r5 = c1*i7 */ \
movq_r2r(r2, r1); /* r1 = i2 */ \
pmulhw_m2r(*C(2), r2); /* r2 = c2*i2 - i2 */ \
psubsw_r2r(r5, r3); /* r3 = B = c7*i1 - c1*i7 */ \
movq_m2r(*J(6), r5); \
paddsw_r2r(r7, r0); /* r0 = A = c1*i1 + c7*i7 */ \
movq_r2r(r5, r7); /* r7 = i6 */ \
psubsw_r2r(r4, r0); /* r0 = A - C */ \
pmulhw_m2r(*C(2), r5); /* r5 = c2*i6 - i6 */ \
paddw_r2r(r1, r2); /* r2 = c2*i2 */ \
pmulhw_m2r(*C(6), r1); /* r1 = c6*i2 */ \
paddsw_r2r(r4, r4); /* r4 = C + C */ \
paddsw_r2r(r0, r4); /* r4 = C. = A + C */ \
psubsw_r2r(r6, r3); /* r3 = B - D */ \
paddw_r2r(r7, r5); /* r5 = c2*i6 */ \
paddsw_r2r(r6, r6); /* r6 = D + D */ \
pmulhw_m2r(*C(6), r7); /* r7 = c6*i6 */ \
paddsw_r2r(r3, r6); /* r6 = D. = B + D */ \
movq_r2m(r4, *I(1)); /* save C. at I(1) */ \
psubsw_r2r(r5, r1); /* r1 = H = c6*i2 - c2*i6 */ \
movq_m2r(*C(4), r4); \
movq_r2r(r3, r5); /* r5 = B - D */ \
pmulhw_r2r(r4, r3); /* r3 = (c4 - 1) * (B - D) */ \
paddsw_r2r(r2, r7); /* r7 = G = c6*i6 + c2*i2 */ \
movq_r2m(r6, *I(2)); /* save D. at I(2) */ \
movq_r2r(r0, r2); /* r2 = A - C */ \
movq_m2r(*I(0), r6); \
pmulhw_r2r(r4, r0); /* r0 = (c4 - 1) * (A - C) */ \
paddw_r2r(r3, r5); /* r5 = B. = c4 * (B - D) */ \
movq_m2r(*J(4), r3); \
psubsw_r2r(r1, r5); /* r5 = B.. = B. - H */ \
paddw_r2r(r0, r2); /* r0 = A. = c4 * (A - C) */ \
psubsw_r2r(r3, r6); /* r6 = i0 - i4 */ \
movq_r2r(r6, r0); \
pmulhw_r2r(r4, r6); /* r6 = (c4 - 1) * (i0 - i4) */ \
paddsw_r2r(r3, r3); /* r3 = i4 + i4 */ \
paddsw_r2r(r1, r1); /* r1 = H + H */ \
paddsw_r2r(r0, r3); /* r3 = i0 + i4 */ \
paddsw_r2r(r5, r1); /* r1 = H. = B + H */ \
pmulhw_r2r(r3, r4); /* r4 = (c4 - 1) * (i0 + i4) */ \
paddsw_r2r(r0, r6); /* r6 = F = c4 * (i0 - i4) */ \
psubsw_r2r(r2, r6); /* r6 = F. = F - A. */ \
paddsw_r2r(r2, r2); /* r2 = A. + A. */ \
movq_m2r(*I(1), r0); /* r0 = C. */ \
paddsw_r2r(r6, r2); /* r2 = A.. = F + A. */ \
paddw_r2r(r3, r4); /* r4 = E = c4 * (i0 + i4) */ \
psubsw_r2r(r1, r2); /* r2 = R2 = A.. - H. */ \
}
/* RowIDCT gets ready to transpose */
#define RowIDCT() { \
\
BeginIDCT(); \
\
movq_m2r(*I(2), r3); /* r3 = D. */ \
psubsw_r2r(r7, r4); /* r4 = E. = E - G */ \
paddsw_r2r(r1, r1); /* r1 = H. + H. */ \
paddsw_r2r(r7, r7); /* r7 = G + G */ \
paddsw_r2r(r2, r1); /* r1 = R1 = A.. + H. */ \
paddsw_r2r(r4, r7); /* r7 = G. = E + G */ \
psubsw_r2r(r3, r4); /* r4 = R4 = E. - D. */ \
paddsw_r2r(r3, r3); \
psubsw_r2r(r5, r6); /* r6 = R6 = F. - B.. */ \
paddsw_r2r(r5, r5); \
paddsw_r2r(r4, r3); /* r3 = R3 = E. + D. */ \
paddsw_r2r(r6, r5); /* r5 = R5 = F. + B.. */ \
psubsw_r2r(r0, r7); /* r7 = R7 = G. - C. */ \
paddsw_r2r(r0, r0); \
movq_r2m(r1, *I(1)); /* save R1 */ \
paddsw_r2r(r7, r0); /* r0 = R0 = G. + C. */ \
}
/* Column IDCT normalizes and stores final results */
#define ColumnIDCT() { \
\
BeginIDCT(); \
\
paddsw_m2r(*Eight, r2); /* adjust R2 (and R1) for shift */ \
paddsw_r2r(r1, r1); /* r1 = H. + H. */ \
paddsw_r2r(r2, r1); /* r1 = R1 = A.. + H. */ \
psraw_i2r(4, r2); /* r2 = NR2 */ \
psubsw_r2r(r7, r4); /* r4 = E. = E - G */ \
psraw_i2r(4, r1); /* r1 = NR1 */ \
movq_m2r(*I(2), r3); /* r3 = D. */ \
paddsw_r2r(r7, r7); /* r7 = G + G */ \
movq_r2m(r2, *I(2)); /* store NR2 at I2 */ \
paddsw_r2r(r4, r7); /* r7 = G. = E + G */ \
movq_r2m(r1, *I(1)); /* store NR1 at I1 */ \
psubsw_r2r(r3, r4); /* r4 = R4 = E. - D. */ \
paddsw_m2r(*Eight, r4); /* adjust R4 (and R3) for shift */ \
paddsw_r2r(r3, r3); /* r3 = D. + D. */ \
paddsw_r2r(r4, r3); /* r3 = R3 = E. + D. */ \
psraw_i2r(4, r4); /* r4 = NR4 */ \
psubsw_r2r(r5, r6); /* r6 = R6 = F. - B.. */ \
psraw_i2r(4, r3); /* r3 = NR3 */ \
paddsw_m2r(*Eight, r6); /* adjust R6 (and R5) for shift */ \
paddsw_r2r(r5, r5); /* r5 = B.. + B.. */ \
paddsw_r2r(r6, r5); /* r5 = R5 = F. + B.. */ \
psraw_i2r(4, r6); /* r6 = NR6 */ \
movq_r2m(r4, *J(4)); /* store NR4 at J4 */ \
psraw_i2r(4, r5); /* r5 = NR5 */ \
movq_r2m(r3, *I(3)); /* store NR3 at I3 */ \
psubsw_r2r(r0, r7); /* r7 = R7 = G. - C. */ \
paddsw_m2r(*Eight, r7); /* adjust R7 (and R0) for shift */ \
paddsw_r2r(r0, r0); /* r0 = C. + C. */ \
paddsw_r2r(r7, r0); /* r0 = R0 = G. + C. */ \
psraw_i2r(4, r7); /* r7 = NR7 */ \
movq_r2m(r6, *J(6)); /* store NR6 at J6 */ \
psraw_i2r(4, r0); /* r0 = NR0 */ \
movq_r2m(r5, *J(5)); /* store NR5 at J5 */ \
movq_r2m(r7, *J(7)); /* store NR7 at J7 */ \
movq_r2m(r0, *I(0)); /* store NR0 at I0 */ \
}
/* Following macro does two 4x4 transposes in place.
At entry (we assume):
r0 = a3 a2 a1 a0
I(1) = b3 b2 b1 b0
r2 = c3 c2 c1 c0
r3 = d3 d2 d1 d0
r4 = e3 e2 e1 e0
r5 = f3 f2 f1 f0
r6 = g3 g2 g1 g0
r7 = h3 h2 h1 h0
At exit, we have:
I(0) = d0 c0 b0 a0
I(1) = d1 c1 b1 a1
I(2) = d2 c2 b2 a2
I(3) = d3 c3 b3 a3
J(4) = h0 g0 f0 e0
J(5) = h1 g1 f1 e1
J(6) = h2 g2 f2 e2
J(7) = h3 g3 f3 e3
I(0) I(1) I(2) I(3) is the transpose of r0 I(1) r2 r3.
J(4) J(5) J(6) J(7) is the transpose of r4 r5 r6 r7.
Since r1 is free at entry, we calculate the Js first. */
#define Transpose() { \
movq_r2r(r4, r1); /* r1 = e3 e2 e1 e0 */ \
punpcklwd_r2r(r5, r4); /* r4 = f1 e1 f0 e0 */ \
movq_r2m(r0, *I(0)); /* save a3 a2 a1 a0 */ \
punpckhwd_r2r(r5, r1); /* r1 = f3 e3 f2 e2 */ \
movq_r2r(r6, r0); /* r0 = g3 g2 g1 g0 */ \
punpcklwd_r2r(r7, r6); /* r6 = h1 g1 h0 g0 */ \
movq_r2r(r4, r5); /* r5 = f1 e1 f0 e0 */ \
punpckldq_r2r(r6, r4); /* r4 = h0 g0 f0 e0 = R4 */ \
punpckhdq_r2r(r6, r5); /* r5 = h1 g1 f1 e1 = R5 */ \
movq_r2r(r1, r6); /* r6 = f3 e3 f2 e2 */ \
movq_r2m(r4, *J(4)); \
punpckhwd_r2r(r7, r0); /* r0 = h3 g3 h2 g2 */ \
movq_r2m(r5, *J(5)); \
punpckhdq_r2r(r0, r6); /* r6 = h3 g3 f3 e3 = R7 */ \
movq_m2r(*I(0), r4); /* r4 = a3 a2 a1 a0 */ \
punpckldq_r2r(r0, r1); /* r1 = h2 g2 f2 e2 = R6 */ \
movq_m2r(*I(1), r5); /* r5 = b3 b2 b1 b0 */ \
movq_r2r(r4, r0); /* r0 = a3 a2 a1 a0 */ \
movq_r2m(r6, *J(7)); \
punpcklwd_r2r(r5, r0); /* r0 = b1 a1 b0 a0 */ \
movq_r2m(r1, *J(6)); \
punpckhwd_r2r(r5, r4); /* r4 = b3 a3 b2 a2 */ \
movq_r2r(r2, r5); /* r5 = c3 c2 c1 c0 */ \
punpcklwd_r2r(r3, r2); /* r2 = d1 c1 d0 c0 */ \
movq_r2r(r0, r1); /* r1 = b1 a1 b0 a0 */ \
punpckldq_r2r(r2, r0); /* r0 = d0 c0 b0 a0 = R0 */ \
punpckhdq_r2r(r2, r1); /* r1 = d1 c1 b1 a1 = R1 */ \
movq_r2r(r4, r2); /* r2 = b3 a3 b2 a2 */ \
movq_r2m(r0, *I(0)); \
punpckhwd_r2r(r3, r5); /* r5 = d3 c3 d2 c2 */ \
movq_r2m(r1, *I(1)); \
punpckhdq_r2r(r5, r4); /* r4 = d3 c3 b3 a3 = R3 */ \
punpckldq_r2r(r5, r2); /* r2 = d2 c2 b2 a2 = R2 */ \
movq_r2m(r4, *I(3)); \
movq_r2m(r2, *I(2)); \
}
void ff_vp3_dsp_init_mmx(void)
{
int j = 16;
uint16_t *p;
j = 1;
do {
p = idct_constants + ((j + 3) << 2);
p[0] = p[1] = p[2] = p[3] = idct_cosine_table[j - 1];
} while (++j <= 7);
idct_constants[44] = idct_constants[45] =
idct_constants[46] = idct_constants[47] = IdctAdjustBeforeShift;
}
void ff_vp3_idct_mmx(int16_t *output_data)
{
/* eax = quantized input
* ebx = dequantizer matrix
* ecx = IDCT constants
* M(I) = ecx + MaskOffset(0) + I * 8
* C(I) = ecx + CosineOffset(32) + (I-1) * 8
* edx = output
* r0..r7 = mm0..mm7
*/
#define C(x) (idct_constants + 16 + (x - 1) * 4)
#define Eight (idct_constants + 44)
/* at this point, function has completed dequantization + dezigzag +
* partial transposition; now do the idct itself */
#define I(K) (output_data + K * 8)
#define J(K) (output_data + ((K - 4) * 8) + 4)
RowIDCT();
Transpose();
#undef I
#undef J
#define I(K) (output_data + (K * 8) + 32)
#define J(K) (output_data + ((K - 4) * 8) + 36)
RowIDCT();
Transpose();
#undef I
#undef J
#define I(K) (output_data + K * 8)
#define J(K) (output_data + K * 8)
ColumnIDCT();
#undef I
#undef J
#define I(K) (output_data + (K * 8) + 4)
#define J(K) (output_data + (K * 8) + 4)
ColumnIDCT();
#undef I
#undef J
}
void ff_vp3_idct_put_mmx(uint8_t *dest, int line_size, DCTELEM *block)
{
ff_vp3_idct_mmx(block);
put_signed_pixels_clamped_mmx(block, dest, line_size);
}
void ff_vp3_idct_add_mmx(uint8_t *dest, int line_size, DCTELEM *block)
{
ff_vp3_idct_mmx(block);
add_pixels_clamped_mmx(block, dest, line_size);
}
@@ -0,0 +1,33 @@
/*
* vp3dsp MMX function declarations
* Copyright (c) 2007 Aurelien Jacobs <[email protected]>
*
* 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
*/
#ifndef FFMPEG_VP3DSP_MMX_H
#define FFMPEG_VP3DSP_MMX_H
#include <stdint.h>
#include "libavcodec/dsputil.h"
void ff_vp3_idct_mmx(int16_t *data);
void ff_vp3_idct_put_mmx(uint8_t *dest, int line_size, DCTELEM *block);
void ff_vp3_idct_add_mmx(uint8_t *dest, int line_size, DCTELEM *block);
void ff_vp3_dsp_init_mmx(void);
#endif /* FFMPEG_VP3DSP_MMX_H */
@@ -0,0 +1,839 @@
/*
* Copyright (C) 2004 the ffmpeg project
*
* 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
*/
/**
* @file vp3dsp_sse2.c
* SSE2-optimized functions cribbed from the original VP3 source code.
*/
#include "libavcodec/dsputil.h"
#include "mmx.h"
static DECLARE_ALIGNED_16(const unsigned short, SSE2_dequant_const[]) =
{
0,65535,65535,0,0,0,0,0, // 0x0000 0000 0000 0000 0000 FFFF FFFF 0000
0,0,0,0,65535,65535,0,0, // 0x0000 0000 FFFF FFFF 0000 0000 0000 0000
65535,65535,65535,0,0,0,0,0,// 0x0000 0000 0000 0000 0000 FFFF FFFF FFFF
0,0,0,65535,0,0,0,0, // 0x0000 0000 0000 0000 FFFF 0000 0000 0000
0,0,0,65535,65535,0,0,0, // 0x0000 0000 0000 FFFF FFFF 0000 0000 0000
65535,0,0,0,0,65535,0,0, // 0x0000 0000 FFFF 0000 0000 0000 0000 FFFF
0,0,65535,65535, 0,0,0,0 // 0x0000 0000 0000 0000 FFFF FFFF 0000 0000
};
static DECLARE_ALIGNED_16(const unsigned int, eight_data[]) =
{
0x00080008,
0x00080008,
0x00080008,
0x00080008
};
static DECLARE_ALIGNED_16(const unsigned short, SSE2_idct_data[7 * 8]) =
{
64277,64277,64277,64277,64277,64277,64277,64277,
60547,60547,60547,60547,60547,60547,60547,60547,
54491,54491,54491,54491,54491,54491,54491,54491,
46341,46341,46341,46341,46341,46341,46341,46341,
36410,36410,36410,36410,36410,36410,36410,36410,
25080,25080,25080,25080,25080,25080,25080,25080,
12785,12785,12785,12785,12785,12785,12785,12785
};
#define SSE2_Column_IDCT() { \
\
movdqa_m2r(*I(3), xmm2); /* xmm2 = i3 */ \
movdqa_m2r(*C(3), xmm6); /* xmm6 = c3 */ \
\
movdqa_r2r(xmm2, xmm4); /* xmm4 = i3 */ \
movdqa_m2r(*I(5), xmm7); /* xmm7 = i5 */ \
\
pmulhw_r2r(xmm6, xmm4); /* xmm4 = c3 * i3 - i3 */ \
movdqa_m2r(*C(5), xmm1); /* xmm1 = c5 */ \
\
pmulhw_r2r(xmm7, xmm6); /* xmm6 = c3 * i5 - i5 */ \
movdqa_r2r(xmm1, xmm5); /* xmm5 = c5 */ \
\
pmulhw_r2r(xmm2, xmm1); /* xmm1 = c5 * i3 - i3 */ \
movdqa_m2r(*I(1), xmm3); /* xmm3 = i1 */ \
\
pmulhw_r2r(xmm7, xmm5); /* xmm5 = c5 * i5 - i5 */ \
movdqa_m2r(*C(1), xmm0); /* xmm0 = c1 */ \
\
/* all registers are in use */ \
\
paddw_r2r(xmm2, xmm4); /* xmm4 = c3 * i3 */ \
paddw_r2r(xmm7, xmm6); /* xmm6 = c3 * i5 */ \
\
paddw_r2r(xmm1, xmm2); /* xmm2 = c5 * i3 */ \
movdqa_m2r(*I(7), xmm1); /* xmm1 = i7 */ \
\
paddw_r2r(xmm5, xmm7); /* xmm7 = c5 * i5 */ \
movdqa_r2r(xmm0, xmm5); /* xmm5 = c1 */ \
\
pmulhw_r2r(xmm3, xmm0); /* xmm0 = c1 * i1 - i1 */ \
paddsw_r2r(xmm7, xmm4); /* xmm4 = c3 * i3 + c5 * i5 = C */ \
\
pmulhw_r2r(xmm1, xmm5); /* xmm5 = c1 * i7 - i7 */ \
movdqa_m2r(*C(7), xmm7); /* xmm7 = c7 */ \
\
psubsw_r2r(xmm2, xmm6); /* xmm6 = c3 * i5 - c5 * i3 = D */ \
paddw_r2r(xmm3, xmm0); /* xmm0 = c1 * i1 */ \
\
pmulhw_r2r(xmm7, xmm3); /* xmm3 = c7 * i1 */ \
movdqa_m2r(*I(2), xmm2); /* xmm2 = i2 */ \
\
pmulhw_r2r(xmm1, xmm7); /* xmm7 = c7 * i7 */ \
paddw_r2r(xmm1, xmm5); /* xmm5 = c1 * i7 */ \
\
movdqa_r2r(xmm2, xmm1); /* xmm1 = i2 */ \
pmulhw_m2r(*C(2), xmm2); /* xmm2 = i2 * c2 -i2 */ \
\
psubsw_r2r(xmm5, xmm3); /* xmm3 = c7 * i1 - c1 * i7 = B */ \
movdqa_m2r(*I(6), xmm5); /* xmm5 = i6 */ \
\
paddsw_r2r(xmm7, xmm0); /* xmm0 = c1 * i1 + c7 * i7 = A */ \
movdqa_r2r(xmm5, xmm7); /* xmm7 = i6 */ \
\
psubsw_r2r(xmm4, xmm0); /* xmm0 = A - C */ \
pmulhw_m2r(*C(2), xmm5); /* xmm5 = c2 * i6 - i6 */ \
\
paddw_r2r(xmm1, xmm2); /* xmm2 = i2 * c2 */ \
pmulhw_m2r(*C(6), xmm1); /* xmm1 = c6 * i2 */ \
\
paddsw_r2r(xmm4, xmm4); /* xmm4 = C + C */ \
paddsw_r2r(xmm0, xmm4); /* xmm4 = A + C = C. */ \
\
psubsw_r2r(xmm6, xmm3); /* xmm3 = B - D */ \
paddw_r2r(xmm7, xmm5); /* xmm5 = c2 * i6 */ \
\
paddsw_r2r(xmm6, xmm6); /* xmm6 = D + D */ \
pmulhw_m2r(*C(6), xmm7); /* xmm7 = c6 * i6 */ \
\
paddsw_r2r(xmm3, xmm6); /* xmm6 = B + D = D. */ \
movdqa_r2m(xmm4, *I(1)); /* Save C. at I(1) */ \
\
psubsw_r2r(xmm5, xmm1); /* xmm1 = c6 * i2 - c2 * i6 = H */ \
movdqa_m2r(*C(4), xmm4); /* xmm4 = c4 */ \
\
movdqa_r2r(xmm3, xmm5); /* xmm5 = B - D */ \
pmulhw_r2r(xmm4, xmm3); /* xmm3 = ( c4 -1 ) * ( B - D ) */ \
\
paddsw_r2r(xmm2, xmm7); /* xmm7 = c2 * i2 + c6 * i6 = G */ \
movdqa_r2m(xmm6, *I(2)); /* Save D. at I(2) */ \
\
movdqa_r2r(xmm0, xmm2); /* xmm2 = A - C */ \
movdqa_m2r(*I(0), xmm6); /* xmm6 = i0 */ \
\
pmulhw_r2r(xmm4, xmm0); /* xmm0 = ( c4 - 1 ) * ( A - C ) = A. */ \
paddw_r2r(xmm3, xmm5); /* xmm5 = c4 * ( B - D ) = B. */ \
\
movdqa_m2r(*I(4), xmm3); /* xmm3 = i4 */ \
psubsw_r2r(xmm1, xmm5); /* xmm5 = B. - H = B.. */ \
\
paddw_r2r(xmm0, xmm2); /* xmm2 = c4 * ( A - C) = A. */ \
psubsw_r2r(xmm3, xmm6); /* xmm6 = i0 - i4 */ \
\
movdqa_r2r(xmm6, xmm0); /* xmm0 = i0 - i4 */ \
pmulhw_r2r(xmm4, xmm6); /* xmm6 = (c4 - 1) * (i0 - i4) = F */ \
\
paddsw_r2r(xmm3, xmm3); /* xmm3 = i4 + i4 */ \
paddsw_r2r(xmm1, xmm1); /* xmm1 = H + H */ \
\
paddsw_r2r(xmm0, xmm3); /* xmm3 = i0 + i4 */ \
paddsw_r2r(xmm5, xmm1); /* xmm1 = B. + H = H. */ \
\
pmulhw_r2r(xmm3, xmm4); /* xmm4 = ( c4 - 1 ) * ( i0 + i4 ) */ \
paddw_r2r(xmm0, xmm6); /* xmm6 = c4 * ( i0 - i4 ) */ \
\
psubsw_r2r(xmm2, xmm6); /* xmm6 = F - A. = F. */ \
paddsw_r2r(xmm2, xmm2); /* xmm2 = A. + A. */ \
\
movdqa_m2r(*I(1), xmm0); /* Load C. from I(1) */ \
paddsw_r2r(xmm6, xmm2); /* xmm2 = F + A. = A.. */ \
\
paddw_r2r(xmm3, xmm4); /* xmm4 = c4 * ( i0 + i4 ) = 3 */ \
psubsw_r2r(xmm1, xmm2); /* xmm2 = A.. - H. = R2 */ \
\
paddsw_m2r(*Eight, xmm2); /* Adjust R2 and R1 before shifting */ \
paddsw_r2r(xmm1, xmm1); /* xmm1 = H. + H. */ \
\
paddsw_r2r(xmm2, xmm1); /* xmm1 = A.. + H. = R1 */ \
psraw_i2r(4, xmm2); /* xmm2 = op2 */ \
\
psubsw_r2r(xmm7, xmm4); /* xmm4 = E - G = E. */ \
psraw_i2r(4, xmm1); /* xmm1 = op1 */ \
\
movdqa_m2r(*I(2), xmm3); /* Load D. from I(2) */ \
paddsw_r2r(xmm7, xmm7); /* xmm7 = G + G */ \
\
movdqa_r2m(xmm2, *O(2)); /* Write out op2 */ \
paddsw_r2r(xmm4, xmm7); /* xmm7 = E + G = G. */ \
\
movdqa_r2m(xmm1, *O(1)); /* Write out op1 */ \
psubsw_r2r(xmm3, xmm4); /* xmm4 = E. - D. = R4 */ \
\
paddsw_m2r(*Eight, xmm4); /* Adjust R4 and R3 before shifting */ \
paddsw_r2r(xmm3, xmm3); /* xmm3 = D. + D. */ \
\
paddsw_r2r(xmm4, xmm3); /* xmm3 = E. + D. = R3 */ \
psraw_i2r(4, xmm4); /* xmm4 = op4 */ \
\
psubsw_r2r(xmm5, xmm6); /* xmm6 = F. - B..= R6 */ \
psraw_i2r(4, xmm3); /* xmm3 = op3 */ \
\
paddsw_m2r(*Eight, xmm6); /* Adjust R6 and R5 before shifting */ \
paddsw_r2r(xmm5, xmm5); /* xmm5 = B.. + B.. */ \
\
paddsw_r2r(xmm6, xmm5); /* xmm5 = F. + B.. = R5 */ \
psraw_i2r(4, xmm6); /* xmm6 = op6 */ \
\
movdqa_r2m(xmm4, *O(4)); /* Write out op4 */ \
psraw_i2r(4, xmm5); /* xmm5 = op5 */ \
\
movdqa_r2m(xmm3, *O(3)); /* Write out op3 */ \
psubsw_r2r(xmm0, xmm7); /* xmm7 = G. - C. = R7 */ \
\
paddsw_m2r(*Eight, xmm7); /* Adjust R7 and R0 before shifting */ \
paddsw_r2r(xmm0, xmm0); /* xmm0 = C. + C. */ \
\
paddsw_r2r(xmm7, xmm0); /* xmm0 = G. + C. */ \
psraw_i2r(4, xmm7); /* xmm7 = op7 */ \
\
movdqa_r2m(xmm6, *O(6)); /* Write out op6 */ \
psraw_i2r(4, xmm0); /* xmm0 = op0 */ \
\
movdqa_r2m(xmm5, *O(5)); /* Write out op5 */ \
movdqa_r2m(xmm7, *O(7)); /* Write out op7 */ \
\
movdqa_r2m(xmm0, *O(0)); /* Write out op0 */ \
\
} /* End of SSE2_Column_IDCT macro */
#define SSE2_Row_IDCT() { \
\
movdqa_m2r(*I(3), xmm2); /* xmm2 = i3 */ \
movdqa_m2r(*C(3), xmm6); /* xmm6 = c3 */ \
\
movdqa_r2r(xmm2, xmm4); /* xmm4 = i3 */ \
movdqa_m2r(*I(5), xmm7); /* xmm7 = i5 */ \
\
pmulhw_r2r(xmm6, xmm4); /* xmm4 = c3 * i3 - i3 */ \
movdqa_m2r(*C(5), xmm1); /* xmm1 = c5 */ \
\
pmulhw_r2r(xmm7, xmm6); /* xmm6 = c3 * i5 - i5 */ \
movdqa_r2r(xmm1, xmm5); /* xmm5 = c5 */ \
\
pmulhw_r2r(xmm2, xmm1); /* xmm1 = c5 * i3 - i3 */ \
movdqa_m2r(*I(1), xmm3); /* xmm3 = i1 */ \
\
pmulhw_r2r(xmm7, xmm5); /* xmm5 = c5 * i5 - i5 */ \
movdqa_m2r(*C(1), xmm0); /* xmm0 = c1 */ \
\
/* all registers are in use */ \
\
paddw_r2r(xmm2, xmm4); /* xmm4 = c3 * i3 */ \
paddw_r2r(xmm7, xmm6); /* xmm6 = c3 * i5 */ \
\
paddw_r2r(xmm1, xmm2); /* xmm2 = c5 * i3 */ \
movdqa_m2r(*I(7), xmm1); /* xmm1 = i7 */ \
\
paddw_r2r(xmm5, xmm7); /* xmm7 = c5 * i5 */ \
movdqa_r2r(xmm0, xmm5); /* xmm5 = c1 */ \
\
pmulhw_r2r(xmm3, xmm0); /* xmm0 = c1 * i1 - i1 */ \
paddsw_r2r(xmm7, xmm4); /* xmm4 = c3 * i3 + c5 * i5 = C */ \
\
pmulhw_r2r(xmm1, xmm5); /* xmm5 = c1 * i7 - i7 */ \
movdqa_m2r(*C(7), xmm7); /* xmm7 = c7 */ \
\
psubsw_r2r(xmm2, xmm6); /* xmm6 = c3 * i5 - c5 * i3 = D */ \
paddw_r2r(xmm3, xmm0); /* xmm0 = c1 * i1 */ \
\
pmulhw_r2r(xmm7, xmm3); /* xmm3 = c7 * i1 */ \
movdqa_m2r(*I(2), xmm2); /* xmm2 = i2 */ \
\
pmulhw_r2r(xmm1, xmm7); /* xmm7 = c7 * i7 */ \
paddw_r2r(xmm1, xmm5); /* xmm5 = c1 * i7 */ \
\
movdqa_r2r(xmm2, xmm1); /* xmm1 = i2 */ \
pmulhw_m2r(*C(2), xmm2); /* xmm2 = i2 * c2 -i2 */ \
\
psubsw_r2r(xmm5, xmm3); /* xmm3 = c7 * i1 - c1 * i7 = B */ \
movdqa_m2r(*I(6), xmm5); /* xmm5 = i6 */ \
\
paddsw_r2r(xmm7, xmm0); /* xmm0 = c1 * i1 + c7 * i7 = A */ \
movdqa_r2r(xmm5, xmm7); /* xmm7 = i6 */ \
\
psubsw_r2r(xmm4, xmm0); /* xmm0 = A - C */ \
pmulhw_m2r(*C(2), xmm5); /* xmm5 = c2 * i6 - i6 */ \
\
paddw_r2r(xmm1, xmm2); /* xmm2 = i2 * c2 */ \
pmulhw_m2r(*C(6), xmm1); /* xmm1 = c6 * i2 */ \
\
paddsw_r2r(xmm4, xmm4); /* xmm4 = C + C */ \
paddsw_r2r(xmm0, xmm4); /* xmm4 = A + C = C. */ \
\
psubsw_r2r(xmm6, xmm3); /* xmm3 = B - D */ \
paddw_r2r(xmm7, xmm5); /* xmm5 = c2 * i6 */ \
\
paddsw_r2r(xmm6, xmm6); /* xmm6 = D + D */ \
pmulhw_m2r(*C(6), xmm7); /* xmm7 = c6 * i6 */ \
\
paddsw_r2r(xmm3, xmm6); /* xmm6 = B + D = D. */ \
movdqa_r2m(xmm4, *I(1)); /* Save C. at I(1) */ \
\
psubsw_r2r(xmm5, xmm1); /* xmm1 = c6 * i2 - c2 * i6 = H */ \
movdqa_m2r(*C(4), xmm4); /* xmm4 = c4 */ \
\
movdqa_r2r(xmm3, xmm5); /* xmm5 = B - D */ \
pmulhw_r2r(xmm4, xmm3); /* xmm3 = ( c4 -1 ) * ( B - D ) */ \
\
paddsw_r2r(xmm2, xmm7); /* xmm7 = c2 * i2 + c6 * i6 = G */ \
movdqa_r2m(xmm6, *I(2)); /* Save D. at I(2) */ \
\
movdqa_r2r(xmm0, xmm2); /* xmm2 = A - C */ \
movdqa_m2r(*I(0), xmm6); /* xmm6 = i0 */ \
\
pmulhw_r2r(xmm4, xmm0); /* xmm0 = ( c4 - 1 ) * ( A - C ) = A. */ \
paddw_r2r(xmm3, xmm5); /* xmm5 = c4 * ( B - D ) = B. */ \
\
movdqa_m2r(*I(4), xmm3); /* xmm3 = i4 */ \
psubsw_r2r(xmm1, xmm5); /* xmm5 = B. - H = B.. */ \
\
paddw_r2r(xmm0, xmm2); /* xmm2 = c4 * ( A - C) = A. */ \
psubsw_r2r(xmm3, xmm6); /* xmm6 = i0 - i4 */ \
\
movdqa_r2r(xmm6, xmm0); /* xmm0 = i0 - i4 */ \
pmulhw_r2r(xmm4, xmm6); /* xmm6 = ( c4 - 1 ) * ( i0 - i4 ) = F */ \
\
paddsw_r2r(xmm3, xmm3); /* xmm3 = i4 + i4 */ \
paddsw_r2r(xmm1, xmm1); /* xmm1 = H + H */ \
\
paddsw_r2r(xmm0, xmm3); /* xmm3 = i0 + i4 */ \
paddsw_r2r(xmm5, xmm1); /* xmm1 = B. + H = H. */ \
\
pmulhw_r2r(xmm3, xmm4); /* xmm4 = ( c4 - 1 ) * ( i0 + i4 ) */ \
paddw_r2r(xmm0, xmm6); /* xmm6 = c4 * ( i0 - i4 ) */ \
\
psubsw_r2r(xmm2, xmm6); /* xmm6 = F - A. = F. */ \
paddsw_r2r(xmm2, xmm2); /* xmm2 = A. + A. */ \
\
movdqa_m2r(*I(1), xmm0); /* Load C. from I(1) */ \
paddsw_r2r(xmm6, xmm2); /* xmm2 = F + A. = A.. */ \
\
paddw_r2r(xmm3, xmm4); /* xmm4 = c4 * ( i0 + i4 ) = 3 */ \
psubsw_r2r(xmm1, xmm2); /* xmm2 = A.. - H. = R2 */ \
\
paddsw_r2r(xmm1, xmm1); /* xmm1 = H. + H. */ \
paddsw_r2r(xmm2, xmm1); /* xmm1 = A.. + H. = R1 */ \
\
psubsw_r2r(xmm7, xmm4); /* xmm4 = E - G = E. */ \
\
movdqa_m2r(*I(2), xmm3); /* Load D. from I(2) */ \
paddsw_r2r(xmm7, xmm7); /* xmm7 = G + G */ \
\
movdqa_r2m(xmm2, *I(2)); /* Write out op2 */ \
paddsw_r2r(xmm4, xmm7); /* xmm7 = E + G = G. */ \
\
movdqa_r2m(xmm1, *I(1)); /* Write out op1 */ \
psubsw_r2r(xmm3, xmm4); /* xmm4 = E. - D. = R4 */ \
\
paddsw_r2r(xmm3, xmm3); /* xmm3 = D. + D. */ \
\
paddsw_r2r(xmm4, xmm3); /* xmm3 = E. + D. = R3 */ \
\
psubsw_r2r(xmm5, xmm6); /* xmm6 = F. - B..= R6 */ \
\
paddsw_r2r(xmm5, xmm5); /* xmm5 = B.. + B.. */ \
\
paddsw_r2r(xmm6, xmm5); /* xmm5 = F. + B.. = R5 */ \
\
movdqa_r2m(xmm4, *I(4)); /* Write out op4 */ \
\
movdqa_r2m(xmm3, *I(3)); /* Write out op3 */ \
psubsw_r2r(xmm0, xmm7); /* xmm7 = G. - C. = R7 */ \
\
paddsw_r2r(xmm0, xmm0); /* xmm0 = C. + C. */ \
\
paddsw_r2r(xmm7, xmm0); /* xmm0 = G. + C. */ \
\
movdqa_r2m(xmm6, *I(6)); /* Write out op6 */ \
\
movdqa_r2m(xmm5, *I(5)); /* Write out op5 */ \
movdqa_r2m(xmm7, *I(7)); /* Write out op7 */ \
\
movdqa_r2m(xmm0, *I(0)); /* Write out op0 */ \
\
} /* End of SSE2_Row_IDCT macro */
#define SSE2_Transpose() { \
\
movdqa_m2r(*I(4), xmm4); /* xmm4=e7e6e5e4e3e2e1e0 */ \
movdqa_m2r(*I(5), xmm0); /* xmm4=f7f6f5f4f3f2f1f0 */ \
\
movdqa_r2r(xmm4, xmm5); /* make a copy */ \
punpcklwd_r2r(xmm0, xmm4); /* xmm4=f3e3f2e2f1e1f0e0 */ \
\
punpckhwd_r2r(xmm0, xmm5); /* xmm5=f7e7f6e6f5e5f4e4 */ \
movdqa_m2r(*I(6), xmm6); /* xmm6=g7g6g5g4g3g2g1g0 */ \
\
movdqa_m2r(*I(7), xmm0); /* xmm0=h7h6h5h4h3h2h1h0 */ \
movdqa_r2r(xmm6, xmm7); /* make a copy */ \
\
punpcklwd_r2r(xmm0, xmm6); /* xmm6=h3g3h3g2h1g1h0g0 */ \
punpckhwd_r2r(xmm0, xmm7); /* xmm7=h7g7h6g6h5g5h4g4 */ \
\
movdqa_r2r(xmm4, xmm3); /* make a copy */ \
punpckldq_r2r(xmm6, xmm4); /* xmm4=h1g1f1e1h0g0f0e0 */ \
\
punpckhdq_r2r(xmm6, xmm3); /* xmm3=h3g3g3e3h2g2f2e2 */ \
movdqa_r2m(xmm3, *I(6)); /* save h3g3g3e3h2g2f2e2 */ \
/* Free xmm6 */ \
movdqa_r2r(xmm5, xmm6); /* make a copy */ \
punpckldq_r2r(xmm7, xmm5); /* xmm5=h5g5f5e5h4g4f4e4 */ \
\
punpckhdq_r2r(xmm7, xmm6); /* xmm6=h7g7f7e7h6g6f6e6 */ \
movdqa_m2r(*I(0), xmm0); /* xmm0=a7a6a5a4a3a2a1a0 */ \
/* Free xmm7 */ \
movdqa_m2r(*I(1), xmm1); /* xmm1=b7b6b5b4b3b2b1b0 */ \
movdqa_r2r(xmm0, xmm7); /* make a copy */ \
\
punpcklwd_r2r(xmm1, xmm0); /* xmm0=b3a3b2a2b1a1b0a0 */ \
punpckhwd_r2r(xmm1, xmm7); /* xmm7=b7a7b6a6b5a5b4a4 */ \
/* Free xmm1 */ \
movdqa_m2r(*I(2), xmm2); /* xmm2=c7c6c5c4c3c2c1c0 */ \
movdqa_m2r(*I(3), xmm3); /* xmm3=d7d6d5d4d3d2d1d0 */ \
\
movdqa_r2r(xmm2, xmm1); /* make a copy */ \
punpcklwd_r2r(xmm3, xmm2); /* xmm2=d3c3d2c2d1c1d0c0 */ \
\
punpckhwd_r2r(xmm3, xmm1); /* xmm1=d7c7d6c6d5c5d4c4 */ \
movdqa_r2r(xmm0, xmm3); /* make a copy */ \
\
punpckldq_r2r(xmm2, xmm0); /* xmm0=d1c1b1a1d0c0b0a0 */ \
punpckhdq_r2r(xmm2, xmm3); /* xmm3=d3c3b3a3d2c2b2a2 */ \
/* Free xmm2 */ \
movdqa_r2r(xmm7, xmm2); /* make a copy */ \
punpckldq_r2r(xmm1, xmm2); /* xmm2=d5c5b5a5d4c4b4a4 */ \
\
punpckhdq_r2r(xmm1, xmm7); /* xmm7=d7c7b7a7d6c6b6a6 */ \
movdqa_r2r(xmm0, xmm1); /* make a copy */ \
\
punpcklqdq_r2r(xmm4, xmm0); /* xmm0=h0g0f0e0d0c0b0a0 */ \
punpckhqdq_r2r(xmm4, xmm1); /* xmm1=h1g1g1e1d1c1b1a1 */ \
\
movdqa_r2m(xmm0, *I(0)); /* save I(0) */ \
movdqa_r2m(xmm1, *I(1)); /* save I(1) */ \
\
movdqa_m2r(*I(6), xmm0); /* load h3g3g3e3h2g2f2e2 */ \
movdqa_r2r(xmm3, xmm1); /* make a copy */ \
\
punpcklqdq_r2r(xmm0, xmm1); /* xmm1=h2g2f2e2d2c2b2a2 */ \
punpckhqdq_r2r(xmm0, xmm3); /* xmm3=h3g3f3e3d3c3b3a3 */ \
\
movdqa_r2r(xmm2, xmm4); /* make a copy */ \
punpcklqdq_r2r(xmm5, xmm4); /* xmm4=h4g4f4e4d4c4b4a4 */ \
\
punpckhqdq_r2r(xmm5, xmm2); /* xmm2=h5g5f5e5d5c5b5a5 */ \
movdqa_r2m(xmm1, *I(2)); /* save I(2) */ \
\
movdqa_r2m(xmm3, *I(3)); /* save I(3) */ \
movdqa_r2m(xmm4, *I(4)); /* save I(4) */ \
\
movdqa_r2m(xmm2, *I(5)); /* save I(5) */ \
movdqa_r2r(xmm7, xmm5); /* make a copy */ \
\
punpcklqdq_r2r(xmm6, xmm5); /* xmm5=h6g6f6e6d6c6b6a6 */ \
punpckhqdq_r2r(xmm6, xmm7); /* xmm7=h7g7f7e7d7c7b7a7 */ \
\
movdqa_r2m(xmm5, *I(6)); /* save I(6) */ \
movdqa_r2m(xmm7, *I(7)); /* save I(7) */ \
\
} /* End of Transpose Macro */
#define SSE2_Dequantize() { \
movdqa_m2r(*(eax), xmm0); \
\
pmullw_m2r(*(ebx), xmm0); /* xmm0 = 07 06 05 04 03 02 01 00 */ \
movdqa_m2r(*(eax + 16), xmm1); \
\
pmullw_m2r(*(ebx + 16), xmm1); /* xmm1 = 17 16 15 14 13 12 11 10 */ \
pshuflw_r2r(xmm0, xmm3, 0x078); /* xmm3 = 07 06 05 04 01 03 02 00 */ \
\
movdqa_r2r(xmm1, xmm2); /* xmm2 = 17 16 15 14 13 12 11 10 */ \
movdqa_m2r(*(ecx), xmm7); /* xmm7 = -- -- -- -- -- FF FF -- */ \
\
movdqa_m2r(*(eax + 32), xmm4); \
movdqa_m2r(*(eax + 64), xmm5); \
\
pmullw_m2r(*(ebx + 32), xmm4); /* xmm4 = 27 26 25 24 23 22 21 20 */ \
pmullw_m2r(*(ebx + 64), xmm5); /* xmm5 = 47 46 45 44 43 42 41 40 */ \
\
movdqa_m2r(*(ecx + 16), xmm6); /* xmm6 = -- -- FF FF -- -- -- -- */ \
pand_r2r(xmm2, xmm7); /* xmm7 = -- -- -- -- -- 12 11 -- */ \
\
pand_r2r(xmm4, xmm6); /* xmm6 = -- -- 25 24 -- -- -- -- */ \
pxor_r2r(xmm7, xmm2); /* xmm2 = 17 16 15 14 13 -- -- 10 */ \
\
pxor_r2r(xmm6, xmm4); /* xmm4 = 27 26 -- -- 23 22 21 20 */ \
pslldq_i2r(4, xmm7); /* xmm7 = -- -- -- 12 11 -- -- -- */ \
\
pslldq_i2r(2, xmm6); /* xmm6 = -- 25 24 -- -- -- -- -- */ \
por_r2r(xmm6, xmm7); /* xmm7 = -- 25 24 12 11 -- -- -- */ \
\
movdqa_m2r(*(ecx + 32), xmm0); /* xmm0 = -- -- -- -- -- FF FF FF */ \
movdqa_m2r(*(ecx + 48), xmm6); /* xmm6 = -- -- -- -- FF -- -- -- */ \
\
pand_r2r(xmm3, xmm0); /* xmm0 = -- -- -- -- -- 03 02 00 */ \
pand_r2r(xmm5, xmm6); /* xmm6 = -- -- -- -- 43 -- -- -- */ \
\
pxor_r2r(xmm0, xmm3); /* xmm3 = 07 06 05 04 01 -- -- -- */ \
pxor_r2r(xmm6, xmm5); /* xmm5 = 47 46 45 44 -- 42 41 40 */ \
\
por_r2r(xmm7, xmm0); /* xmm0 = -- 25 24 12 11 03 02 00 */ \
pslldq_i2r(8, xmm6); /* xmm6 = 43 -- -- -- -- -- -- -- */ \
\
por_r2r(xmm6, xmm0); /* xmm0 = 43 25 24 12 11 03 02 00 */ \
/* 02345 in use */ \
\
movdqa_m2r(*(ecx + 64 ), xmm1); /* xmm1 = -- -- -- FF FF -- -- -- */ \
pshuflw_r2r(xmm5, xmm5, 0x0B4); /* xmm5 = 47 46 45 44 42 -- 41 40 */ \
\
movdqa_r2r(xmm1, xmm7); /* xmm7 = -- -- -- FF FF -- -- -- */ \
movdqa_r2r(xmm1, xmm6); /* xmm6 = -- -- -- FF FF -- -- -- */ \
\
movdqa_r2m(xmm0, *(eax)); /* write 43 25 24 12 11 03 02 00 */ \
pshufhw_r2r(xmm4, xmm4, 0x0C2); /* xmm4 = 27 -- -- 26 23 22 21 20 */ \
\
pand_r2r(xmm4, xmm7); /* xmm7 = -- -- -- 26 23 -- -- -- */ \
pand_r2r(xmm5, xmm1); /* xmm1 = -- -- -- 44 42 -- -- -- */ \
\
pxor_r2r(xmm7, xmm4); /* xmm4 = 27 -- -- -- -- 22 21 20 */ \
pxor_r2r(xmm1, xmm5); /* xmm5 = 47 46 45 -- -- -- 41 40 */ \
\
pshuflw_r2r(xmm2, xmm2, 0x0C6); /* xmm2 = 17 16 15 14 13 10 -- -- */ \
movdqa_r2r(xmm6, xmm0); /* xmm0 = -- -- -- FF FF -- -- -- */ \
\
pslldq_i2r(2, xmm7); /* xmm7 = -- -- 26 23 -- -- -- -- */ \
pslldq_i2r(6, xmm1); /* xmm1 = 44 42 -- -- -- -- -- -- */ \
\
psrldq_i2r(2, xmm0); /* xmm0 = -- -- -- -- FF FF -- -- */ \
pand_r2r(xmm3, xmm6); /* xmm6 = -- -- -- 04 01 -- -- -- */ \
\
pand_r2r(xmm2, xmm0); /* xmm0 = -- -- -- -- 13 10 -- -- */ \
pxor_r2r(xmm6, xmm3); /* xmm3 = 07 06 05 -- -- -- -- -- */ \
\
pxor_r2r(xmm0, xmm2); /* xmm2 = 17 16 15 14 -- -- -- -- */ \
psrldq_i2r(6, xmm6); /* xmm0 = -- -- -- -- -- -- 04 01 */ \
\
por_r2r(xmm7, xmm1); /* xmm1 = 44 42 26 23 -- -- -- -- */ \
por_r2r(xmm6, xmm0); /* xmm1 = -- -- -- -- 13 10 04 01 */ \
/* 12345 in use */ \
por_r2r(xmm0, xmm1); /* xmm1 = 44 42 26 23 13 10 04 01 */ \
pshuflw_r2r(xmm4, xmm4, 0x093); /* xmm4 = 27 -- -- -- 22 21 20 -- */ \
\
pshufhw_r2r(xmm4, xmm4, 0x093); /* xmm4 = -- -- -- 27 22 21 20 -- */ \
movdqa_r2m(xmm1, *(eax + 16)); /* write 44 42 26 23 13 10 04 01 */ \
\
pshufhw_r2r(xmm3, xmm3, 0x0D2); /* xmm3 = 07 05 -- 06 -- -- -- -- */ \
movdqa_m2r(*(ecx + 64), xmm0); /* xmm0 = -- -- -- FF FF -- -- -- */ \
\
pand_r2r(xmm3, xmm0); /* xmm0 = -- -- -- 06 -- -- -- -- */ \
psrldq_i2r(12, xmm3); /* xmm3 = -- -- -- -- -- -- 07 05 */ \
\
psrldq_i2r(8, xmm0); /* xmm0 = -- -- -- -- -- -- -- 06 */ \
\
movdqa_m2r(*(ecx + 64), xmm6); /* xmm6 = -- -- -- FF FF -- -- -- */ \
movdqa_m2r(*(ecx + 96), xmm7); /* xmm7 = -- -- -- -- FF FF -- -- */ \
\
pand_r2r(xmm4, xmm6); /* xmm6 = -- -- -- 27 22 -- -- -- */ \
pxor_r2r(xmm6, xmm4); /* xmm4 = -- -- -- -- -- 21 20 -- */ \
\
por_r2r(xmm6, xmm3); /* xmm3 = -- -- -- 27 22 -- 07 05 */ \
pand_r2r(xmm4, xmm7); /* xmm7 = -- -- -- -- -- 21 -- -- */ \
\
por_r2r(xmm7, xmm0); /* xmm0 = -- -- -- -- -- 21 -- 06 */ \
pxor_r2r(xmm7, xmm4); /* xmm4 = -- -- -- -- -- -- 20 -- */ \
\
movdqa_m2r(*(ecx + 16 ), xmm6); /* xmm6 = -- -- FF FF -- -- -- -- */ \
movdqa_m2r(*(ecx + 64 ), xmm1); /* xmm1 = -- -- -- FF FF -- -- -- */ \
\
pand_r2r(xmm2, xmm6); /* xmm6 = -- -- 15 14 -- -- -- -- */ \
pand_r2r(xmm6, xmm1); /* xmm1 = -- -- -- 14 -- -- -- -- */ \
\
pxor_r2r(xmm6, xmm2); /* xmm2 = 17 16 -- -- -- -- -- -- */ \
pxor_r2r(xmm1, xmm6); /* xmm6 = -- -- 15 -- -- -- -- -- */ \
\
psrldq_i2r(4, xmm1); /* xmm1 = -- -- -- -- -- 14 -- -- */ \
\
psrldq_i2r(8, xmm6); /* xmm6 = -- -- -- -- -- -- 15 -- */ \
por_r2r(xmm1, xmm3); /* xmm3 = -- -- -- 27 22 14 07 05 */ \
\
por_r2r(xmm6, xmm0); /* xmm0 = -- -- -- -- -- 21 15 06 */ \
pshufhw_r2r(xmm5, xmm5, 0x0E1); /* xmm5 = 47 46 -- 45 -- -- 41 40 */ \
\
movdqa_m2r(*(ecx + 64), xmm1); /* xmm1 = -- -- -- FF FF -- -- -- */ \
pshuflw_r2r(xmm5, xmm5, 0x072); /* xmm5 = 47 46 -- 45 41 -- 40 -- */ \
\
movdqa_r2r(xmm1, xmm6); /* xmm6 = -- -- -- FF FF -- -- -- */ \
pand_r2r(xmm5, xmm1); /* xmm1 = -- -- -- 45 41 -- -- -- */ \
\
pxor_r2r(xmm1, xmm5); /* xmm5 = 47 46 -- -- -- -- 40 -- */ \
pslldq_i2r(4, xmm1); /* xmm1 = -- 45 41 -- -- -- -- -- */ \
\
pshufd_r2r(xmm5, xmm5, 0x09C); /* xmm5 = -- -- -- -- 47 46 40 -- */ \
por_r2r(xmm1, xmm3); /* xmm3 = -- 45 41 27 22 14 07 05 */ \
\
movdqa_m2r(*(eax + 96), xmm1); /* xmm1 = 67 66 65 64 63 62 61 60 */ \
pmullw_m2r(*(ebx + 96), xmm1); \
\
movdqa_m2r(*(ecx), xmm7); /* xmm7 = -- -- -- -- -- FF FF -- */ \
\
psrldq_i2r(8, xmm6); /* xmm6 = -- -- -- -- -- -- -- FF */ \
pand_r2r(xmm5, xmm7); /* xmm7 = -- -- -- -- -- 46 40 -- */ \
\
pand_r2r(xmm1, xmm6); /* xmm6 = -- -- -- -- -- -- -- 60 */ \
pxor_r2r(xmm7, xmm5); /* xmm5 = -- -- -- -- 47 -- -- -- */ \
\
pxor_r2r(xmm6, xmm1); /* xmm1 = 67 66 65 64 63 62 61 -- */ \
pslldq_i2r(2, xmm5); /* xmm5 = -- -- -- 47 -- -- -- -- */ \
\
pslldq_i2r(14, xmm6); /* xmm6 = 60 -- -- -- -- -- -- -- */ \
por_r2r(xmm5, xmm4); /* xmm4 = -- -- -- 47 -- -- 20 -- */ \
\
por_r2r(xmm6, xmm3); /* xmm3 = 60 45 41 27 22 14 07 05 */ \
pslldq_i2r(6, xmm7); /* xmm7 = -- -- 46 40 -- -- -- -- */ \
\
movdqa_r2m(xmm3, *(eax+32)); /* write 60 45 41 27 22 14 07 05 */ \
por_r2r(xmm7, xmm0); /* xmm0 = -- -- 46 40 -- 21 15 06 */ \
/* 0, 1, 2, 4 in use */ \
movdqa_m2r(*(eax + 48), xmm3); /* xmm3 = 37 36 35 34 33 32 31 30 */ \
movdqa_m2r(*(eax + 80), xmm5); /* xmm5 = 57 56 55 54 53 52 51 50 */ \
\
pmullw_m2r(*(ebx + 48), xmm3); \
pmullw_m2r(*(ebx + 80), xmm5); \
\
movdqa_m2r(*(ecx + 64), xmm6); /* xmm6 = -- -- -- FF FF -- -- -- */ \
movdqa_m2r(*(ecx + 64), xmm7); /* xmm7 = -- -- -- FF FF -- -- -- */ \
\
psrldq_i2r(8, xmm6); /* xmm6 = -- -- -- -- -- -- -- FF */ \
pslldq_i2r(8, xmm7); /* xmm7 = FF -- -- -- -- -- -- -- */ \
\
pand_r2r(xmm3, xmm6); /* xmm6 = -- -- -- -- -- -- -- 30 */ \
pand_r2r(xmm5, xmm7); /* xmm7 = 57 -- -- -- -- -- -- -- */ \
\
pxor_r2r(xmm6, xmm3); /* xmm3 = 37 36 35 34 33 32 31 -- */ \
pxor_r2r(xmm7, xmm5); /* xmm5 = __ 56 55 54 53 52 51 50 */ \
\
pslldq_i2r(6, xmm6); /* xmm6 = -- -- -- -- 30 -- -- -- */ \
psrldq_i2r(2, xmm7); /* xmm7 = -- 57 -- -- -- -- -- -- */ \
\
por_r2r(xmm7, xmm6); /* xmm6 = -- 57 -- -- 30 -- -- -- */ \
movdqa_m2r(*(ecx), xmm7); /* xmm7 = -- -- -- -- -- FF FF -- */ \
\
por_r2r(xmm6, xmm0); /* xmm0 = -- 57 46 40 30 21 15 06 */ \
psrldq_i2r(2, xmm7); /* xmm7 = -- -- -- -- -- -- FF FF */ \
\
movdqa_r2r(xmm2, xmm6); /* xmm6 = 17 16 -- -- -- -- -- -- */ \
pand_r2r(xmm1, xmm7); /* xmm7 = -- -- -- -- -- -- 61 -- */ \
\
pslldq_i2r(2, xmm6); /* xmm6 = 16 -- -- -- -- -- -- -- */ \
psrldq_i2r(14, xmm2); /* xmm2 = -- -- -- -- -- -- -- 17 */ \
\
pxor_r2r(xmm7, xmm1); /* xmm1 = 67 66 65 64 63 62 -- -- */ \
pslldq_i2r(12, xmm7); /* xmm7 = 61 -- -- -- -- -- -- -- */ \
\
psrldq_i2r(14, xmm6); /* xmm6 = -- -- -- -- -- -- -- 16 */ \
por_r2r(xmm6, xmm4); /* xmm4 = -- -- -- 47 -- -- 20 16 */ \
\
por_r2r(xmm7, xmm0); /* xmm0 = 61 57 46 40 30 21 15 06 */ \
movdqa_m2r(*(ecx), xmm6); /* xmm6 = -- -- -- -- -- FF FF -- */ \
\
psrldq_i2r(2, xmm6); /* xmm6 = -- -- -- -- -- -- FF FF */ \
movdqa_r2m(xmm0, *(eax+48)); /* write 61 57 46 40 30 21 15 06 */ \
/* 1, 2, 3, 4, 5 in use */\
movdqa_m2r(*(ecx), xmm0); /* xmm0 = -- -- -- -- -- FF FF -- */ \
pand_r2r(xmm3, xmm6); /* xmm6 = -- -- -- -- -- -- 31 -- */ \
\
movdqa_r2r(xmm3, xmm7); /* xmm7 = 37 36 35 34 33 32 31 -- */ \
pxor_r2r(xmm6, xmm3); /* xmm3 = 37 36 35 34 33 32 -- -- */ \
\
pslldq_i2r(2, xmm3); /* xmm3 = 36 35 34 33 32 -- -- -- */ \
pand_r2r(xmm1, xmm0); /* xmm0 = -- -- -- -- -- 62 -- -- */ \
\
psrldq_i2r(14, xmm7); /* xmm7 = -- -- -- -- -- -- -- 37 */ \
pxor_r2r(xmm0, xmm1); /* xmm1 = 67 66 65 64 63 -- -- -- */ \
\
por_r2r(xmm7, xmm6); /* xmm6 = -- -- -- -- -- -- 31 37 */ \
movdqa_m2r(*(ecx + 64), xmm7); /* xmm7 = -- -- -- FF FF -- -- -- */ \
\
pshuflw_r2r(xmm6, xmm6, 0x01E); /* xmm6 = -- -- -- -- 37 31 -- -- */ \
pslldq_i2r(6, xmm7); /* xmm7 = FF FF -- -- -- -- -- -- */ \
\
por_r2r(xmm6, xmm4); /* xmm4 = -- -- -- 47 37 31 20 16 */ \
pand_r2r(xmm5, xmm7); /* xmm7 = -- 56 -- -- -- -- -- -- */ \
\
pslldq_i2r(8, xmm0); /* xmm0 = -- 62 -- -- -- -- -- -- */ \
pxor_r2r(xmm7, xmm5); /* xmm5 = -- -- 55 54 53 52 51 50 */ \
\
psrldq_i2r(2, xmm7); /* xmm7 = -- -- 56 -- -- -- -- -- */ \
\
pshufhw_r2r(xmm3, xmm3, 0x087); /* xmm3 = 35 33 34 36 32 -- -- -- */ \
por_r2r(xmm7, xmm0); /* xmm0 = -- 62 56 -- -- -- -- -- */ \
\
movdqa_m2r(*(eax + 112), xmm7); /* xmm7 = 77 76 75 74 73 72 71 70 */ \
pmullw_m2r(*(ebx + 112), xmm7); \
\
movdqa_m2r(*(ecx + 64), xmm6); /* xmm6 = -- -- -- FF FF -- -- -- */ \
por_r2r(xmm0, xmm4); /* xmm4 = -- 62 56 47 37 31 20 16 */ \
\
pshuflw_r2r(xmm7, xmm7, 0x0E1); /* xmm7 = 77 76 75 74 73 72 70 71 */ \
psrldq_i2r(8, xmm6); /* xmm6 = -- -- -- -- -- -- -- FF */ \
\
movdqa_m2r(*(ecx + 64), xmm0); /* xmm0 = -- -- -- FF FF -- -- -- */ \
pand_r2r(xmm7, xmm6); /* xmm6 = -- -- -- -- -- -- -- 71 */ \
\
pand_r2r(xmm3, xmm0); /* xmm0 = -- -- -- 36 32 -- -- -- */ \
pxor_r2r(xmm6, xmm7); /* xmm7 = 77 76 75 74 73 72 70 -- */ \
\
pxor_r2r(xmm0, xmm3); /* xmm3 = 35 33 34 -- -- -- -- -- */ \
pslldq_i2r(14, xmm6); /* xmm6 = 71 -- -- -- -- -- -- -- */ \
\
psrldq_i2r(4, xmm0); /* xmm0 = -- -- -- -- -- 36 32 -- */ \
por_r2r(xmm6, xmm4); /* xmm4 = 71 62 56 47 37 31 20 16 */ \
\
por_r2r(xmm0, xmm2); /* xmm2 = -- -- -- -- -- 36 32 17 */ \
movdqa_r2m(xmm4, *(eax + 64)); /* write 71 62 56 47 37 31 20 16 */ \
/* 1, 2, 3, 5, 7 in use */ \
movdqa_m2r(*(ecx + 80), xmm6); /* xmm6 = -- -- FF -- -- -- -- FF */ \
pshufhw_r2r(xmm7, xmm7, 0x0D2); /* xmm7 = 77 75 74 76 73 72 70 __ */ \
\
movdqa_m2r(*(ecx), xmm4); /* xmm4 = -- -- -- -- -- FF FF -- */ \
movdqa_m2r(*(ecx+48), xmm0); /* xmm0 = -- -- -- -- FF -- -- -- */ \
\
pand_r2r(xmm5, xmm6); /* xmm6 = -- -- 55 -- -- -- -- 50 */ \
pand_r2r(xmm7, xmm4); /* xmm4 = -- -- -- -- -- 72 70 -- */ \
\
pand_r2r(xmm1, xmm0); /* xmm0 = -- -- -- -- 63 -- -- -- */ \
pxor_r2r(xmm6, xmm5); /* xmm5 = -- -- -- 54 53 52 51 -- */ \
\
pxor_r2r(xmm4, xmm7); /* xmm7 = 77 75 74 76 73 -- -- -- */ \
pxor_r2r(xmm0, xmm1); /* xmm1 = 67 66 65 64 -- -- -- -- */ \
\
pshuflw_r2r(xmm6, xmm6, 0x02B); /* xmm6 = -- -- 55 -- 50 -- -- -- */ \
pslldq_i2r(10, xmm4); /* xmm4 = 72 20 -- -- -- -- -- -- */ \
\
pshufhw_r2r(xmm6, xmm6, 0x0B1); /* xmm6 = -- -- -- 55 50 -- -- -- */ \
pslldq_i2r(4, xmm0); /* xmm0 = -- -- 63 -- -- -- -- -- */ \
\
por_r2r(xmm4, xmm6); /* xmm6 = 72 70 -- 55 50 -- -- -- */ \
por_r2r(xmm0, xmm2); /* xmm2 = -- -- 63 -- -- 36 32 17 */ \
\
por_r2r(xmm6, xmm2); /* xmm2 = 72 70 64 55 50 36 32 17 */ \
pshufhw_r2r(xmm1, xmm1, 0x0C9); /* xmm1 = 67 64 66 65 -- -- -- -- */ \
\
movdqa_r2r(xmm3, xmm6); /* xmm6 = 35 33 34 -- -- -- -- -- */ \
movdqa_r2m(xmm2, *(eax+80)); /* write 72 70 64 55 50 36 32 17 */ \
\
psrldq_i2r(12, xmm6); /* xmm6 = -- -- -- -- -- -- 35 33 */ \
pslldq_i2r(4, xmm3); /* xmm3 = 34 -- -- -- -- -- -- -- */ \
\
pshuflw_r2r(xmm5, xmm5, 0x04E); /* xmm5 = -- -- -- 54 51 -- 53 52 */ \
movdqa_r2r(xmm7, xmm4); /* xmm4 = 77 75 74 76 73 -- -- -- */ \
\
movdqa_r2r(xmm5, xmm2); /* xmm2 = -- -- -- 54 51 -- 53 52 */ \
psrldq_i2r(10, xmm7); /* xmm7 = -- -- -- -- -- 77 75 74 */ \
\
pslldq_i2r(6, xmm4); /* xmm4 = 76 73 -- -- -- -- -- -- */ \
pslldq_i2r(12, xmm2); /* xmm2 = 53 52 -- -- -- -- -- -- */ \
\
movdqa_r2r(xmm1, xmm0); /* xmm0 = 67 64 66 65 -- -- -- -- */ \
psrldq_i2r(12, xmm1); /* xmm1 = -- -- -- -- -- -- 67 64 */ \
\
psrldq_i2r(6, xmm5); /* xmm5 = -- -- -- -- -- -- 54 51 */ \
psrldq_i2r(14, xmm3); /* xmm3 = -- -- -- -- -- -- -- 34 */ \
\
pslldq_i2r(10, xmm7); /* xmm7 = 77 75 74 -- -- -- -- -- */ \
por_r2r(xmm6, xmm4); /* xmm4 = 76 73 -- -- -- -- 35 33 */ \
\
psrldq_i2r(10, xmm2); /* xmm2 = -- -- -- -- -- 53 52 -- */ \
pslldq_i2r(4, xmm0); /* xmm0 = 66 65 -- -- -- -- -- -- */ \
\
pslldq_i2r(8, xmm1); /* xmm1 = -- -- 67 64 -- -- -- -- */ \
por_r2r(xmm7, xmm3); /* xmm3 = 77 75 74 -- -- -- -- 34 */ \
\
psrldq_i2r(6, xmm0); /* xmm0 = -- -- -- 66 65 -- -- -- */ \
pslldq_i2r(4, xmm5); /* xmm5 = -- -- -- -- 54 51 -- -- */ \
\
por_r2r(xmm1, xmm4); /* xmm4 = 76 73 67 64 -- -- 35 33 */ \
por_r2r(xmm2, xmm3); /* xmm3 = 77 75 74 -- -- 53 52 34 */ \
\
por_r2r(xmm5, xmm4); /* xmm4 = 76 73 67 64 54 51 35 33 */ \
por_r2r(xmm0, xmm3); /* xmm3 = 77 75 74 66 65 53 52 34 */ \
\
movdqa_r2m(xmm4, *(eax+96)); /* write 76 73 67 64 54 51 35 33 */ \
movdqa_r2m(xmm3, *(eax+112)); /* write 77 75 74 66 65 53 52 34 */ \
\
} /* end of SSE2_Dequantize Macro */
void ff_vp3_idct_sse2(int16_t *input_data)
{
unsigned char *input_bytes = (unsigned char *)input_data;
unsigned char *output_data_bytes = (unsigned char *)input_data;
const unsigned char *idct_data_bytes = (const unsigned char *)SSE2_idct_data;
const unsigned char *Eight = (const unsigned char *)eight_data;
#define eax input_bytes
//#define ebx dequant_matrix_bytes
#define ecx dequant_const_bytes
#define edx idct_data_bytes
#define I(i) (eax + 16 * i)
#define O(i) (ebx + 16 * i)
#define C(i) (edx + 16 * (i-1))
// SSE2_Dequantize();
#undef ebx
#define ebx output_data_bytes
SSE2_Row_IDCT();
SSE2_Transpose();
SSE2_Column_IDCT();
}
void ff_vp3_idct_put_sse2(uint8_t *dest, int line_size, DCTELEM *block)
{
ff_vp3_idct_sse2(block);
put_signed_pixels_clamped_mmx(block, dest, line_size);
}
void ff_vp3_idct_add_sse2(uint8_t *dest, int line_size, DCTELEM *block)
{
ff_vp3_idct_sse2(block);
add_pixels_clamped_mmx(block, dest, line_size);
}
@@ -0,0 +1,31 @@
/*
* vp3dsp SSE2 function declarations
* Copyright (c) 2007 Aurelien Jacobs <[email protected]>
*
* 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
*/
#ifndef FFMPEG_VP3DSP_SSE2_H
#define FFMPEG_VP3DSP_SSE2_H
#include "libavcodec/dsputil.h"
void ff_vp3_idct_sse2(int16_t *input_data);
void ff_vp3_idct_put_sse2(uint8_t *dest, int line_size, DCTELEM *block);
void ff_vp3_idct_add_sse2(uint8_t *dest, int line_size, DCTELEM *block);
#endif /* FFMPEG_VP3DSP_SSE2_H */
@@ -0,0 +1,546 @@
;*****************************************************************************
;* x86inc.asm
;*****************************************************************************
;* Copyright (C) 2005-2008 Loren Merritt <[email protected]>
;*
;* 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
;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;*****************************************************************************
; FIXME: All of the 64bit asm functions that take a stride as an argument
; via register, assume that the high dword of that register is filled with 0.
; This is true in practice (since we never do any 64bit arithmetic on strides,
; and x264's strides are all positive), but is not guaranteed by the ABI.
; Name of the .rodata section.
; Kludge: Something on OS X fails to align .rodata even given an align attribute,
; so use a different read-only section.
%macro SECTION_RODATA 0
%ifidn __OUTPUT_FORMAT__,macho64
SECTION .text align=16
%elifidn __OUTPUT_FORMAT__,macho
SECTION .text align=16
fakegot:
%else
SECTION .rodata align=16
%endif
%endmacro
; PIC support macros. All these macros are totally harmless when PIC is
; not defined but can ruin everything if misused in PIC mode. On x86_32, shared
; objects cannot directly access global variables by address, they need to
; go through the GOT (global offset table). Most OSes do not care about it
; and let you load non-shared .so objects (Linux, Win32...). However, OS X
; requires PIC code in its .dylib objects.
;
; - GLOBAL should be used as a suffix for global addressing, eg.
; picgetgot ebx
; mov eax, [foo GLOBAL]
; instead of
; mov eax, [foo]
;
; - picgetgot computes the GOT address into the given register in PIC
; mode, otherwise does nothing. You need to do this before using GLOBAL.
; Before in both execution order and compiled code order (so GLOBAL knows
; which register the GOT is in).
%ifndef PIC
%define GLOBAL
%macro picgetgot 1
%endmacro
%elifdef ARCH_X86_64
%define PIC64
%define GLOBAL wrt rip
%macro picgetgot 1
%endmacro
%else
%define PIC32
%ifidn __OUTPUT_FORMAT__,macho
; There is no real global offset table on OS X, but we still
; need to reference our variables by offset.
%macro picgetgot 1
call %%getgot
%%getgot:
pop %1
add %1, $$ - %%getgot
%undef GLOBAL
%define GLOBAL + %1 - fakegot
%endmacro
%else ; elf
extern _GLOBAL_OFFSET_TABLE_
%macro picgetgot 1
call %%getgot
%%getgot:
pop %1
add %1, _GLOBAL_OFFSET_TABLE_ + $$ - %%getgot wrt ..gotpc
%undef GLOBAL
%define GLOBAL + %1 wrt ..gotoff
%endmacro
%endif
%endif
; Macros to eliminate most code duplication between x86_32 and x86_64:
; Currently this works only for leaf functions which load all their arguments
; into registers at the start, and make no other use of the stack. Luckily that
; covers most of x264's asm.
; PROLOGUE:
; %1 = number of arguments. loads them from stack if needed.
; %2 = number of registers used, not including PIC. pushes callee-saved regs if needed.
; %3 = whether global constants are used in this function. inits x86_32 PIC if needed.
; %4 = list of names to define to registers
; PROLOGUE can also be invoked by adding the same options to cglobal
; e.g.
; cglobal foo, 2,3,0, dst, src, tmp
; declares a function (foo), taking two args (dst and src), one local variable (tmp), and not using globals
; TODO Some functions can use some args directly from the stack. If they're the
; last args then you can just not declare them, but if they're in the middle
; we need more flexible macro.
; RET:
; Pops anything that was pushed by PROLOGUE
; REP_RET:
; Same, but if it doesn't pop anything it becomes a 2-byte ret, for athlons
; which are slow when a normal ret follows a branch.
%macro DECLARE_REG 6
%define r%1q %2
%define r%1d %3
%define r%1w %4
%define r%1b %5
%define r%1m %6
%define r%1 %2
%endmacro
%macro DECLARE_REG_SIZE 2
%define r%1q r%1
%define e%1q r%1
%define r%1d e%1
%define e%1d e%1
%define r%1w %1
%define e%1w %1
%define r%1b %2
%define e%1b %2
%ifndef ARCH_X86_64
%define r%1 e%1
%endif
%endmacro
DECLARE_REG_SIZE ax, al
DECLARE_REG_SIZE bx, bl
DECLARE_REG_SIZE cx, cl
DECLARE_REG_SIZE dx, dl
DECLARE_REG_SIZE si, sil
DECLARE_REG_SIZE di, dil
DECLARE_REG_SIZE bp, bpl
%ifdef ARCH_X86_64
%define gprsize 8
%else
%define gprsize 4
%endif
%macro PUSH 1
push %1
%assign stack_offset stack_offset+gprsize
%endmacro
%macro POP 1
pop %1
%assign stack_offset stack_offset-gprsize
%endmacro
%macro SUB 2
sub %1, %2
%ifidn %1, rsp
%assign stack_offset stack_offset+(%2)
%endif
%endmacro
%macro ADD 2
add %1, %2
%ifidn %1, rsp
%assign stack_offset stack_offset-(%2)
%endif
%endmacro
%macro movifnidn 2
%ifnidn %1, %2
mov %1, %2
%endif
%endmacro
%macro movsxdifnidn 2
%ifnidn %1, %2
movsxd %1, %2
%endif
%endmacro
%macro ASSERT 1
%if (%1) == 0
%error assert failed
%endif
%endmacro
%macro DEFINE_ARGS 0-*
%ifdef n_arg_names
%assign %%i 0
%rep n_arg_names
CAT_UNDEF arg_name %+ %%i, q
CAT_UNDEF arg_name %+ %%i, d
CAT_UNDEF arg_name %+ %%i, w
CAT_UNDEF arg_name %+ %%i, b
CAT_UNDEF arg_name, %%i
%assign %%i %%i+1
%endrep
%endif
%assign %%i 0
%rep %0
%xdefine %1q r %+ %%i %+ q
%xdefine %1d r %+ %%i %+ d
%xdefine %1w r %+ %%i %+ w
%xdefine %1b r %+ %%i %+ b
CAT_XDEFINE arg_name, %%i, %1
%assign %%i %%i+1
%rotate 1
%endrep
%assign n_arg_names %%i
%endmacro
%ifdef ARCH_X86_64 ;==========================================================
%ifidn __OUTPUT_FORMAT__,win32
DECLARE_REG 0, rcx, ecx, cx, cl, ecx
DECLARE_REG 1, rdx, edx, dx, dl, edx
DECLARE_REG 2, r8, r8d, r8w, r8b, r8d
DECLARE_REG 3, r9, r9d, r9w, r9b, r9d
DECLARE_REG 4, rdi, edi, di, dil, [rsp + stack_offset + 40]
DECLARE_REG 5, rsi, esi, si, sil, [rsp + stack_offset + 48]
DECLARE_REG 6, rax, eax, ax, al, [rsp + stack_offset + 56]
%define r7m [rsp + stack_offset + 64]
%define r8m [rsp + stack_offset + 72]
%macro LOAD_IF_USED 2 ; reg_id, number_of_args
%if %1 < %2
mov r%1, [rsp + 8 + %1*8]
%endif
%endmacro
%else ;=======================================================================
DECLARE_REG 0, rdi, edi, di, dil, edi
DECLARE_REG 1, rsi, esi, si, sil, esi
DECLARE_REG 2, rdx, edx, dx, dl, edx
DECLARE_REG 3, rcx, ecx, cx, cl, ecx
DECLARE_REG 4, r8, r8d, r8w, r8b, r8d
DECLARE_REG 5, r9, r9d, r9w, r9b, r9d
DECLARE_REG 6, rax, eax, ax, al, [rsp + stack_offset + 8]
%define r7m [rsp + stack_offset + 16]
%define r8m [rsp + stack_offset + 24]
%macro LOAD_IF_USED 2 ; reg_id, number_of_args
%if %1 < %2
mov r%1, [rsp - 40 + %1*8]
%endif
%endmacro
%endif ; !WIN64
%macro PROLOGUE 2-4+ 0 ; #args, #regs, pic, arg_names...
ASSERT %2 >= %1
ASSERT %2 <= 7
%assign stack_offset 0
%ifidn __OUTPUT_FORMAT__,win32
LOAD_IF_USED 4, %1
LOAD_IF_USED 5, %1
%endif
LOAD_IF_USED 6, %1
DEFINE_ARGS %4
%endmacro
%macro RET 0
ret
%endmacro
%macro REP_RET 0
rep ret
%endmacro
%else ; X86_32 ;==============================================================
DECLARE_REG 0, eax, eax, ax, al, [esp + stack_offset + 4]
DECLARE_REG 1, ecx, ecx, cx, cl, [esp + stack_offset + 8]
DECLARE_REG 2, edx, edx, dx, dl, [esp + stack_offset + 12]
DECLARE_REG 3, ebx, ebx, bx, bl, [esp + stack_offset + 16]
DECLARE_REG 4, esi, esi, si, null, [esp + stack_offset + 20]
DECLARE_REG 5, edi, edi, di, null, [esp + stack_offset + 24]
DECLARE_REG 6, ebp, ebp, bp, null, [esp + stack_offset + 28]
%define r7m [esp + stack_offset + 32]
%define r8m [esp + stack_offset + 36]
%define rsp esp
%macro PUSH_IF_USED 1 ; reg_id
%if %1 < regs_used
push r%1
%assign stack_offset stack_offset+4
%endif
%endmacro
%macro POP_IF_USED 1 ; reg_id
%if %1 < regs_used
pop r%1
%endif
%endmacro
%macro LOAD_IF_USED 2 ; reg_id, number_of_args
%if %1 < %2
mov r%1, [esp + stack_offset + 4 + %1*4]
%endif
%endmacro
%macro PROLOGUE 2-4+ 0 ; #args, #regs, pic, arg_names...
ASSERT %2 >= %1
%assign stack_offset 0
%assign regs_used %2
%ifdef PIC
%if %3
%assign regs_used regs_used+1
%endif
%endif
ASSERT regs_used <= 7
PUSH_IF_USED 3
PUSH_IF_USED 4
PUSH_IF_USED 5
PUSH_IF_USED 6
LOAD_IF_USED 0, %1
LOAD_IF_USED 1, %1
LOAD_IF_USED 2, %1
LOAD_IF_USED 3, %1
LOAD_IF_USED 4, %1
LOAD_IF_USED 5, %1
LOAD_IF_USED 6, %1
%if %3
picgetgot r%2
%endif
DEFINE_ARGS %4
%endmacro
%macro RET 0
POP_IF_USED 6
POP_IF_USED 5
POP_IF_USED 4
POP_IF_USED 3
ret
%endmacro
%macro REP_RET 0
%if regs_used > 3
RET
%else
rep ret
%endif
%endmacro
%endif ;======================================================================
;=============================================================================
; arch-independent part
;=============================================================================
%assign function_align 16
; Symbol prefix for C linkage
%macro cglobal 1-2+
%ifidn __OUTPUT_FORMAT__,elf
%ifdef PREFIX
global _%1:function hidden
%define %1 _%1
%else
global %1:function hidden
%endif
%else
%ifdef PREFIX
global _%1
%define %1 _%1
%else
global %1
%endif
%endif
align function_align
%1:
RESET_MM_PERMUTATION ; not really needed, but makes disassembly somewhat nicer
%if %0 > 1
PROLOGUE %2
%endif
%endmacro
%macro cextern 1
%ifdef PREFIX
extern _%1
%define %1 _%1
%else
extern %1
%endif
%endmacro
; This is needed for ELF, otherwise the GNU linker assumes the stack is
; executable by default.
%ifidn __OUTPUT_FORMAT__,elf
SECTION .note.GNU-stack noalloc noexec nowrite progbits
%endif
%assign FENC_STRIDE 16
%assign FDEC_STRIDE 32
; merge mmx and sse*
%macro CAT_XDEFINE 3
%xdefine %1%2 %3
%endmacro
%macro CAT_UNDEF 2
%undef %1%2
%endmacro
%macro INIT_MMX 0
%define RESET_MM_PERMUTATION INIT_MMX
%define mmsize 8
%define num_mmregs 8
%define mova movq
%define movu movq
%define movh movd
%define movnt movntq
%assign %%i 0
%rep 8
CAT_XDEFINE m, %%i, mm %+ %%i
CAT_XDEFINE nmm, %%i, %%i
%assign %%i %%i+1
%endrep
%rep 8
CAT_UNDEF m, %%i
CAT_UNDEF nmm, %%i
%assign %%i %%i+1
%endrep
%endmacro
%macro INIT_XMM 0
%define RESET_MM_PERMUTATION INIT_XMM
%define mmsize 16
%define num_mmregs 8
%ifdef ARCH_X86_64
%define num_mmregs 16
%endif
%define mova movdqa
%define movu movdqu
%define movh movq
%define movnt movntdq
%assign %%i 0
%rep num_mmregs
CAT_XDEFINE m, %%i, xmm %+ %%i
CAT_XDEFINE nxmm, %%i, %%i
%assign %%i %%i+1
%endrep
%endmacro
INIT_MMX
; I often want to use macros that permute their arguments. e.g. there's no
; efficient way to implement butterfly or transpose or dct without swapping some
; arguments.
;
; I would like to not have to manually keep track of the permutations:
; If I insert a permutation in the middle of a function, it should automatically
; change everything that follows. For more complex macros I may also have multiple
; implementations, e.g. the SSE2 and SSSE3 versions may have different permutations.
;
; Hence these macros. Insert a PERMUTE or some SWAPs at the end of a macro that
; permutes its arguments. It's equivalent to exchanging the contents of the
; registers, except that this way you exchange the register names instead, so it
; doesn't cost any cycles.
%macro PERMUTE 2-* ; takes a list of pairs to swap
%rep %0/2
%xdefine tmp%2 m%2
%xdefine ntmp%2 nm%2
%rotate 2
%endrep
%rep %0/2
%xdefine m%1 tmp%2
%xdefine nm%1 ntmp%2
%undef tmp%2
%undef ntmp%2
%rotate 2
%endrep
%endmacro
%macro SWAP 2-* ; swaps a single chain (sometimes more concise than pairs)
%rep %0-1
%ifdef m%1
%xdefine tmp m%1
%xdefine m%1 m%2
%xdefine m%2 tmp
CAT_XDEFINE n, m%1, %1
CAT_XDEFINE n, m%2, %2
%else
; If we were called as "SWAP m0,m1" rather than "SWAP 0,1" infer the original numbers here.
; Be careful using this mode in nested macros though, as in some cases there may be
; other copies of m# that have already been dereferenced and don't get updated correctly.
%xdefine %%n1 n %+ %1
%xdefine %%n2 n %+ %2
%xdefine tmp m %+ %%n1
CAT_XDEFINE m, %%n1, m %+ %%n2
CAT_XDEFINE m, %%n2, tmp
CAT_XDEFINE n, m %+ %%n1, %%n1
CAT_XDEFINE n, m %+ %%n2, %%n2
%endif
%undef tmp
%rotate 1
%endrep
%endmacro
%macro SAVE_MM_PERMUTATION 1
%assign %%i 0
%rep num_mmregs
CAT_XDEFINE %1_m, %%i, m %+ %%i
%assign %%i %%i+1
%endrep
%endmacro
%macro LOAD_MM_PERMUTATION 1
%assign %%i 0
%rep num_mmregs
CAT_XDEFINE m, %%i, %1_m %+ %%i
%assign %%i %%i+1
%endrep
%endmacro
%macro call 1
call %1
%ifdef %1_m0
LOAD_MM_PERMUTATION %1
%endif
%endmacro
; substitutions which are functionally identical but reduce code size
%define movdqa movaps
%define movdqu movups
@@ -1,27 +1,28 @@
/*
* Id Quake II CIN Video Decoder
* id Quake II CIN Video Decoder
* Copyright (C) 2003 the ffmpeg project
*
* This library is free software; you can redistribute it and/or
* 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 of the License, or (at your option) any later version.
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* 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 this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file idcinvideo.c
* Id Quake II Cin Video Decoder by Dr. Tim Ferguson
* For more information about the Id CIN format, visit:
* id Quake II Cin Video Decoder by Dr. Tim Ferguson
* For more information about the id CIN format, visit:
* http://www.csse.monash.edu.au/~timf/
*
* This video decoder outputs PAL8 colorspace data. Interacting with this
@@ -31,7 +32,7 @@
* the demuxer must use the same extradata space to transmit an
* AVPaletteControl structure.
*
* Id CIN video is purely Huffman-coded, intraframe-only codec. It achieves
* id CIN video is purely Huffman-coded, intraframe-only codec. It achieves
* a little more compression by exploiting the fact that adjacent pixels
* tend to be similar.
*
@@ -48,9 +49,7 @@
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "avcodec.h"
#include "dsputil.h"
#define HUFFMAN_TABLE_SIZE 64 * 1024
#define HUF_TOKENS 256
@@ -66,10 +65,9 @@ typedef struct
typedef struct IdcinContext {
AVCodecContext *avctx;
DSPContext dsp;
AVFrame frame;
unsigned char *buf;
const unsigned char *buf;
int size;
hnode_t huff_nodes[256][HUF_TOKENS*2];
@@ -115,7 +113,7 @@ static int huff_smallest_node(hnode_t *hnodes, int num_hnodes) {
* num_huff_nodes[prev] - contains the index to the root node of the tree.
* That is: huff_nodes[prev][num_huff_nodes[prev]] is the root node.
*/
static void huff_build_tree(IdcinContext *s, int prev) {
static av_cold void huff_build_tree(IdcinContext *s, int prev) {
hnode_t *node, *hnodes;
int num_hnodes, i;
@@ -145,20 +143,18 @@ static void huff_build_tree(IdcinContext *s, int prev) {
s->num_huff_nodes[prev] = num_hnodes - 1;
}
static int idcin_decode_init(AVCodecContext *avctx)
static av_cold int idcin_decode_init(AVCodecContext *avctx)
{
IdcinContext *s = (IdcinContext *)avctx->priv_data;
IdcinContext *s = avctx->priv_data;
int i, j, histogram_index = 0;
unsigned char *histograms;
s->avctx = avctx;
avctx->pix_fmt = PIX_FMT_PAL8;
avctx->has_b_frames = 0;
dsputil_init(&s->dsp, avctx);
/* make sure the Huffman tables make it */
if (s->avctx->extradata_size != HUFFMAN_TABLE_SIZE) {
av_log(s->avctx, AV_LOG_ERROR, " Id CIN video: expected extradata size of %d\n", HUFFMAN_TABLE_SIZE);
av_log(s->avctx, AV_LOG_ERROR, " id CIN video: expected extradata size of %d\n", HUFFMAN_TABLE_SIZE);
return -1;
}
@@ -192,7 +188,7 @@ static void idcin_decode_vlcs(IdcinContext *s)
while(node_num >= HUF_TOKENS) {
if(!bit_pos) {
if(dat_pos > s->size) {
if(dat_pos >= s->size) {
av_log(s->avctx, AV_LOG_ERROR, "Huffman decode error.\n");
return;
}
@@ -213,9 +209,9 @@ static void idcin_decode_vlcs(IdcinContext *s)
static int idcin_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size)
const uint8_t *buf, int buf_size)
{
IdcinContext *s = (IdcinContext *)avctx->priv_data;
IdcinContext *s = avctx->priv_data;
AVPaletteControl *palette_control = avctx->palctrl;
s->buf = buf;
@@ -225,7 +221,7 @@ static int idcin_decode_frame(AVCodecContext *avctx,
avctx->release_buffer(avctx, &s->frame);
if (avctx->get_buffer(avctx, &s->frame)) {
av_log(avctx, AV_LOG_ERROR, " Id CIN Video: get_buffer() failed\n");
av_log(avctx, AV_LOG_ERROR, " id CIN Video: get_buffer() failed\n");
return -1;
}
@@ -246,9 +242,9 @@ static int idcin_decode_frame(AVCodecContext *avctx,
return buf_size;
}
static int idcin_decode_end(AVCodecContext *avctx)
static av_cold int idcin_decode_end(AVCodecContext *avctx)
{
IdcinContext *s = (IdcinContext *)avctx->priv_data;
IdcinContext *s = avctx->priv_data;
if (s->frame.data[0])
avctx->release_buffer(avctx, &s->frame);
@@ -266,5 +262,6 @@ AVCodec idcin_decoder = {
idcin_decode_end,
idcin_decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("id Quake II CIN video"),
};
@@ -0,0 +1,829 @@
/*
* IMC compatible decoder
* Copyright (c) 2002-2004 Maxim Poliakovski
* Copyright (c) 2006 Benjamin Larsson
* Copyright (c) 2006 Konstantin Shishkov
*
* 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
*/
/**
* @file imc.c IMC - Intel Music Coder
* A mdct based codec using a 256 points large transform
* divied into 32 bands with some mix of scale factors.
* Only mono is supported.
*
*/
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#define ALT_BITSTREAM_READER
#include "avcodec.h"
#include "bitstream.h"
#include "dsputil.h"
#include "imcdata.h"
#define IMC_BLOCK_SIZE 64
#define IMC_FRAME_ID 0x21
#define BANDS 32
#define COEFFS 256
typedef struct {
float old_floor[BANDS];
float flcoeffs1[BANDS];
float flcoeffs2[BANDS];
float flcoeffs3[BANDS];
float flcoeffs4[BANDS];
float flcoeffs5[BANDS];
float flcoeffs6[BANDS];
float CWdecoded[COEFFS];
/** MDCT tables */
//@{
float mdct_sine_window[COEFFS];
float post_cos[COEFFS];
float post_sin[COEFFS];
float pre_coef1[COEFFS];
float pre_coef2[COEFFS];
float last_fft_im[COEFFS];
//@}
int bandWidthT[BANDS]; ///< codewords per band
int bitsBandT[BANDS]; ///< how many bits per codeword in band
int CWlengthT[COEFFS]; ///< how many bits in each codeword
int levlCoeffBuf[BANDS];
int bandFlagsBuf[BANDS]; ///< flags for each band
int sumLenArr[BANDS]; ///< bits for all coeffs in band
int skipFlagRaw[BANDS]; ///< skip flags are stored in raw form or not
int skipFlagBits[BANDS]; ///< bits used to code skip flags
int skipFlagCount[BANDS]; ///< skipped coeffients per band
int skipFlags[COEFFS]; ///< skip coefficient decoding or not
int codewords[COEFFS]; ///< raw codewords read from bitstream
float sqrt_tab[30];
GetBitContext gb;
int decoder_reset;
float one_div_log2;
DSPContext dsp;
FFTContext fft;
DECLARE_ALIGNED_16(FFTComplex, samples[COEFFS/2]);
DECLARE_ALIGNED_16(float, out_samples[COEFFS]);
} IMCContext;
static VLC huffman_vlc[4][4];
#define VLC_TABLES_SIZE 9512
static const int vlc_offsets[17] = {
0, 640, 1156, 1732, 2308, 2852, 3396, 3924,
4452, 5220, 5860, 6628, 7268, 7908, 8424, 8936, VLC_TABLES_SIZE};
static VLC_TYPE vlc_tables[VLC_TABLES_SIZE][2];
static av_cold int imc_decode_init(AVCodecContext * avctx)
{
int i, j;
IMCContext *q = avctx->priv_data;
double r1, r2;
q->decoder_reset = 1;
for(i = 0; i < BANDS; i++)
q->old_floor[i] = 1.0;
/* Build mdct window, a simple sine window normalized with sqrt(2) */
ff_sine_window_init(q->mdct_sine_window, COEFFS);
for(i = 0; i < COEFFS; i++)
q->mdct_sine_window[i] *= sqrt(2.0);
for(i = 0; i < COEFFS/2; i++){
q->post_cos[i] = cos(i / 256.0 * M_PI);
q->post_sin[i] = sin(i / 256.0 * M_PI);
r1 = sin((i * 4.0 + 1.0) / 1024.0 * M_PI);
r2 = cos((i * 4.0 + 1.0) / 1024.0 * M_PI);
if (i & 0x1)
{
q->pre_coef1[i] = (r1 + r2) * sqrt(2.0);
q->pre_coef2[i] = -(r1 - r2) * sqrt(2.0);
}
else
{
q->pre_coef1[i] = -(r1 + r2) * sqrt(2.0);
q->pre_coef2[i] = (r1 - r2) * sqrt(2.0);
}
q->last_fft_im[i] = 0;
}
/* Generate a square root table */
for(i = 0; i < 30; i++) {
q->sqrt_tab[i] = sqrt(i);
}
/* initialize the VLC tables */
for(i = 0; i < 4 ; i++) {
for(j = 0; j < 4; j++) {
huffman_vlc[i][j].table = vlc_tables[vlc_offsets[i * 4 + j]];
huffman_vlc[i][j].table_allocated = vlc_offsets[i * 4 + j + 1] - vlc_offsets[i * 4 + j];
init_vlc(&huffman_vlc[i][j], 9, imc_huffman_sizes[i],
imc_huffman_lens[i][j], 1, 1,
imc_huffman_bits[i][j], 2, 2, INIT_VLC_USE_NEW_STATIC);
}
}
q->one_div_log2 = 1/log(2);
ff_fft_init(&q->fft, 7, 1);
dsputil_init(&q->dsp, avctx);
avctx->sample_fmt = SAMPLE_FMT_S16;
return 0;
}
static void imc_calculate_coeffs(IMCContext* q, float* flcoeffs1, float* flcoeffs2, int* bandWidthT,
float* flcoeffs3, float* flcoeffs5)
{
float workT1[BANDS];
float workT2[BANDS];
float workT3[BANDS];
float snr_limit = 1.e-30;
float accum = 0.0;
int i, cnt2;
for(i = 0; i < BANDS; i++) {
flcoeffs5[i] = workT2[i] = 0.0;
if (bandWidthT[i]){
workT1[i] = flcoeffs1[i] * flcoeffs1[i];
flcoeffs3[i] = 2.0 * flcoeffs2[i];
} else {
workT1[i] = 0.0;
flcoeffs3[i] = -30000.0;
}
workT3[i] = bandWidthT[i] * workT1[i] * 0.01;
if (workT3[i] <= snr_limit)
workT3[i] = 0.0;
}
for(i = 0; i < BANDS; i++) {
for(cnt2 = i; cnt2 < cyclTab[i]; cnt2++)
flcoeffs5[cnt2] = flcoeffs5[cnt2] + workT3[i];
workT2[cnt2-1] = workT2[cnt2-1] + workT3[i];
}
for(i = 1; i < BANDS; i++) {
accum = (workT2[i-1] + accum) * imc_weights1[i-1];
flcoeffs5[i] += accum;
}
for(i = 0; i < BANDS; i++)
workT2[i] = 0.0;
for(i = 0; i < BANDS; i++) {
for(cnt2 = i-1; cnt2 > cyclTab2[i]; cnt2--)
flcoeffs5[cnt2] += workT3[i];
workT2[cnt2+1] += workT3[i];
}
accum = 0.0;
for(i = BANDS-2; i >= 0; i--) {
accum = (workT2[i+1] + accum) * imc_weights2[i];
flcoeffs5[i] += accum;
//there is missing code here, but it seems to never be triggered
}
}
static void imc_read_level_coeffs(IMCContext* q, int stream_format_code, int* levlCoeffs)
{
int i;
VLC *hufftab[4];
int start = 0;
const uint8_t *cb_sel;
int s;
s = stream_format_code >> 1;
hufftab[0] = &huffman_vlc[s][0];
hufftab[1] = &huffman_vlc[s][1];
hufftab[2] = &huffman_vlc[s][2];
hufftab[3] = &huffman_vlc[s][3];
cb_sel = imc_cb_select[s];
if(stream_format_code & 4)
start = 1;
if(start)
levlCoeffs[0] = get_bits(&q->gb, 7);
for(i = start; i < BANDS; i++){
levlCoeffs[i] = get_vlc2(&q->gb, hufftab[cb_sel[i]]->table, hufftab[cb_sel[i]]->bits, 2);
if(levlCoeffs[i] == 17)
levlCoeffs[i] += get_bits(&q->gb, 4);
}
}
static void imc_decode_level_coefficients(IMCContext* q, int* levlCoeffBuf, float* flcoeffs1,
float* flcoeffs2)
{
int i, level;
float tmp, tmp2;
//maybe some frequency division thingy
flcoeffs1[0] = 20000.0 / pow (2, levlCoeffBuf[0] * 0.18945); // 0.18945 = log2(10) * 0.05703125
flcoeffs2[0] = log(flcoeffs1[0])/log(2);
tmp = flcoeffs1[0];
tmp2 = flcoeffs2[0];
for(i = 1; i < BANDS; i++) {
level = levlCoeffBuf[i];
if (level == 16) {
flcoeffs1[i] = 1.0;
flcoeffs2[i] = 0.0;
} else {
if (level < 17)
level -=7;
else if (level <= 24)
level -=32;
else
level -=16;
tmp *= imc_exp_tab[15 + level];
tmp2 += 0.83048 * level; // 0.83048 = log2(10) * 0.25
flcoeffs1[i] = tmp;
flcoeffs2[i] = tmp2;
}
}
}
static void imc_decode_level_coefficients2(IMCContext* q, int* levlCoeffBuf, float* old_floor, float* flcoeffs1,
float* flcoeffs2) {
int i;
//FIXME maybe flag_buf = noise coding and flcoeffs1 = new scale factors
// and flcoeffs2 old scale factors
// might be incomplete due to a missing table that is in the binary code
for(i = 0; i < BANDS; i++) {
flcoeffs1[i] = 0;
if(levlCoeffBuf[i] < 16) {
flcoeffs1[i] = imc_exp_tab2[levlCoeffBuf[i]] * old_floor[i];
flcoeffs2[i] = (levlCoeffBuf[i]-7) * 0.83048 + flcoeffs2[i]; // 0.83048 = log2(10) * 0.25
} else {
flcoeffs1[i] = old_floor[i];
}
}
}
/**
* Perform bit allocation depending on bits available
*/
static int bit_allocation (IMCContext* q, int stream_format_code, int freebits, int flag) {
int i, j;
const float limit = -1.e20;
float highest = 0.0;
int indx;
int t1 = 0;
int t2 = 1;
float summa = 0.0;
int iacc = 0;
int summer = 0;
int rres, cwlen;
float lowest = 1.e10;
int low_indx = 0;
float workT[32];
int flg;
int found_indx = 0;
for(i = 0; i < BANDS; i++)
highest = FFMAX(highest, q->flcoeffs1[i]);
for(i = 0; i < BANDS-1; i++) {
q->flcoeffs4[i] = q->flcoeffs3[i] - log(q->flcoeffs5[i])/log(2);
}
q->flcoeffs4[BANDS - 1] = limit;
highest = highest * 0.25;
for(i = 0; i < BANDS; i++) {
indx = -1;
if ((band_tab[i+1] - band_tab[i]) == q->bandWidthT[i])
indx = 0;
if ((band_tab[i+1] - band_tab[i]) > q->bandWidthT[i])
indx = 1;
if (((band_tab[i+1] - band_tab[i])/2) >= q->bandWidthT[i])
indx = 2;
if (indx == -1)
return -1;
q->flcoeffs4[i] = q->flcoeffs4[i] + xTab[(indx*2 + (q->flcoeffs1[i] < highest)) * 2 + flag];
}
if (stream_format_code & 0x2) {
q->flcoeffs4[0] = limit;
q->flcoeffs4[1] = limit;
q->flcoeffs4[2] = limit;
q->flcoeffs4[3] = limit;
}
for(i = (stream_format_code & 0x2)?4:0; i < BANDS-1; i++) {
iacc += q->bandWidthT[i];
summa += q->bandWidthT[i] * q->flcoeffs4[i];
}
q->bandWidthT[BANDS-1] = 0;
summa = (summa * 0.5 - freebits) / iacc;
for(i = 0; i < BANDS/2; i++) {
rres = summer - freebits;
if((rres >= -8) && (rres <= 8)) break;
summer = 0;
iacc = 0;
for(j = (stream_format_code & 0x2)?4:0; j < BANDS; j++) {
cwlen = av_clip((int)((q->flcoeffs4[j] * 0.5) - summa + 0.5), 0, 6);
q->bitsBandT[j] = cwlen;
summer += q->bandWidthT[j] * cwlen;
if (cwlen > 0)
iacc += q->bandWidthT[j];
}
flg = t2;
t2 = 1;
if (freebits < summer)
t2 = -1;
if (i == 0)
flg = t2;
if(flg != t2)
t1++;
summa = (float)(summer - freebits) / ((t1 + 1) * iacc) + summa;
}
for(i = (stream_format_code & 0x2)?4:0; i < BANDS; i++) {
for(j = band_tab[i]; j < band_tab[i+1]; j++)
q->CWlengthT[j] = q->bitsBandT[i];
}
if (freebits > summer) {
for(i = 0; i < BANDS; i++) {
workT[i] = (q->bitsBandT[i] == 6) ? -1.e20 : (q->bitsBandT[i] * -2 + q->flcoeffs4[i] - 0.415);
}
highest = 0.0;
do{
if (highest <= -1.e20)
break;
found_indx = 0;
highest = -1.e20;
for(i = 0; i < BANDS; i++) {
if (workT[i] > highest) {
highest = workT[i];
found_indx = i;
}
}
if (highest > -1.e20) {
workT[found_indx] -= 2.0;
if (++(q->bitsBandT[found_indx]) == 6)
workT[found_indx] = -1.e20;
for(j = band_tab[found_indx]; j < band_tab[found_indx+1] && (freebits > summer); j++){
q->CWlengthT[j]++;
summer++;
}
}
}while (freebits > summer);
}
if (freebits < summer) {
for(i = 0; i < BANDS; i++) {
workT[i] = q->bitsBandT[i] ? (q->bitsBandT[i] * -2 + q->flcoeffs4[i] + 1.585) : 1.e20;
}
if (stream_format_code & 0x2) {
workT[0] = 1.e20;
workT[1] = 1.e20;
workT[2] = 1.e20;
workT[3] = 1.e20;
}
while (freebits < summer){
lowest = 1.e10;
low_indx = 0;
for(i = 0; i < BANDS; i++) {
if (workT[i] < lowest) {
lowest = workT[i];
low_indx = i;
}
}
//if(lowest >= 1.e10) break;
workT[low_indx] = lowest + 2.0;
if (!(--q->bitsBandT[low_indx]))
workT[low_indx] = 1.e20;
for(j = band_tab[low_indx]; j < band_tab[low_indx+1] && (freebits < summer); j++){
if(q->CWlengthT[j] > 0){
q->CWlengthT[j]--;
summer--;
}
}
}
}
return 0;
}
static void imc_get_skip_coeff(IMCContext* q) {
int i, j;
memset(q->skipFlagBits, 0, sizeof(q->skipFlagBits));
memset(q->skipFlagCount, 0, sizeof(q->skipFlagCount));
for(i = 0; i < BANDS; i++) {
if (!q->bandFlagsBuf[i] || !q->bandWidthT[i])
continue;
if (!q->skipFlagRaw[i]) {
q->skipFlagBits[i] = band_tab[i+1] - band_tab[i];
for(j = band_tab[i]; j < band_tab[i+1]; j++) {
if ((q->skipFlags[j] = get_bits1(&q->gb)))
q->skipFlagCount[i]++;
}
} else {
for(j = band_tab[i]; j < (band_tab[i+1]-1); j += 2) {
if(!get_bits1(&q->gb)){//0
q->skipFlagBits[i]++;
q->skipFlags[j]=1;
q->skipFlags[j+1]=1;
q->skipFlagCount[i] += 2;
}else{
if(get_bits1(&q->gb)){//11
q->skipFlagBits[i] +=2;
q->skipFlags[j]=0;
q->skipFlags[j+1]=1;
q->skipFlagCount[i]++;
}else{
q->skipFlagBits[i] +=3;
q->skipFlags[j+1]=0;
if(!get_bits1(&q->gb)){//100
q->skipFlags[j]=1;
q->skipFlagCount[i]++;
}else{//101
q->skipFlags[j]=0;
}
}
}
}
if (j < band_tab[i+1]) {
q->skipFlagBits[i]++;
if ((q->skipFlags[j] = get_bits1(&q->gb)))
q->skipFlagCount[i]++;
}
}
}
}
/**
* Increase highest' band coefficient sizes as some bits won't be used
*/
static void imc_adjust_bit_allocation (IMCContext* q, int summer) {
float workT[32];
int corrected = 0;
int i, j;
float highest = 0;
int found_indx=0;
for(i = 0; i < BANDS; i++) {
workT[i] = (q->bitsBandT[i] == 6) ? -1.e20 : (q->bitsBandT[i] * -2 + q->flcoeffs4[i] - 0.415);
}
while (corrected < summer) {
if(highest <= -1.e20)
break;
highest = -1.e20;
for(i = 0; i < BANDS; i++) {
if (workT[i] > highest) {
highest = workT[i];
found_indx = i;
}
}
if (highest > -1.e20) {
workT[found_indx] -= 2.0;
if (++(q->bitsBandT[found_indx]) == 6)
workT[found_indx] = -1.e20;
for(j = band_tab[found_indx]; j < band_tab[found_indx+1] && (corrected < summer); j++) {
if (!q->skipFlags[j] && (q->CWlengthT[j] < 6)) {
q->CWlengthT[j]++;
corrected++;
}
}
}
}
}
static void imc_imdct256(IMCContext *q) {
int i;
float re, im;
/* prerotation */
for(i=0; i < COEFFS/2; i++){
q->samples[i].re = -(q->pre_coef1[i] * q->CWdecoded[COEFFS-1-i*2]) -
(q->pre_coef2[i] * q->CWdecoded[i*2]);
q->samples[i].im = (q->pre_coef2[i] * q->CWdecoded[COEFFS-1-i*2]) -
(q->pre_coef1[i] * q->CWdecoded[i*2]);
}
/* FFT */
ff_fft_permute(&q->fft, q->samples);
ff_fft_calc (&q->fft, q->samples);
/* postrotation, window and reorder */
for(i = 0; i < COEFFS/2; i++){
re = (q->samples[i].re * q->post_cos[i]) + (-q->samples[i].im * q->post_sin[i]);
im = (-q->samples[i].im * q->post_cos[i]) - (q->samples[i].re * q->post_sin[i]);
q->out_samples[i*2] = (q->mdct_sine_window[COEFFS-1-i*2] * q->last_fft_im[i]) + (q->mdct_sine_window[i*2] * re);
q->out_samples[COEFFS-1-i*2] = (q->mdct_sine_window[i*2] * q->last_fft_im[i]) - (q->mdct_sine_window[COEFFS-1-i*2] * re);
q->last_fft_im[i] = im;
}
}
static int inverse_quant_coeff (IMCContext* q, int stream_format_code) {
int i, j;
int middle_value, cw_len, max_size;
const float* quantizer;
for(i = 0; i < BANDS; i++) {
for(j = band_tab[i]; j < band_tab[i+1]; j++) {
q->CWdecoded[j] = 0;
cw_len = q->CWlengthT[j];
if (cw_len <= 0 || q->skipFlags[j])
continue;
max_size = 1 << cw_len;
middle_value = max_size >> 1;
if (q->codewords[j] >= max_size || q->codewords[j] < 0)
return -1;
if (cw_len >= 4){
quantizer = imc_quantizer2[(stream_format_code & 2) >> 1];
if (q->codewords[j] >= middle_value)
q->CWdecoded[j] = quantizer[q->codewords[j] - 8] * q->flcoeffs6[i];
else
q->CWdecoded[j] = -quantizer[max_size - q->codewords[j] - 8 - 1] * q->flcoeffs6[i];
}else{
quantizer = imc_quantizer1[((stream_format_code & 2) >> 1) | (q->bandFlagsBuf[i] << 1)];
if (q->codewords[j] >= middle_value)
q->CWdecoded[j] = quantizer[q->codewords[j] - 1] * q->flcoeffs6[i];
else
q->CWdecoded[j] = -quantizer[max_size - 2 - q->codewords[j]] * q->flcoeffs6[i];
}
}
}
return 0;
}
static int imc_get_coeffs (IMCContext* q) {
int i, j, cw_len, cw;
for(i = 0; i < BANDS; i++) {
if(!q->sumLenArr[i]) continue;
if (q->bandFlagsBuf[i] || q->bandWidthT[i]) {
for(j = band_tab[i]; j < band_tab[i+1]; j++) {
cw_len = q->CWlengthT[j];
cw = 0;
if (get_bits_count(&q->gb) + cw_len > 512){
//av_log(NULL,0,"Band %i coeff %i cw_len %i\n",i,j,cw_len);
return -1;
}
if(cw_len && (!q->bandFlagsBuf[i] || !q->skipFlags[j]))
cw = get_bits(&q->gb, cw_len);
q->codewords[j] = cw;
}
}
}
return 0;
}
static int imc_decode_frame(AVCodecContext * avctx,
void *data, int *data_size,
const uint8_t * buf, int buf_size)
{
IMCContext *q = avctx->priv_data;
int stream_format_code;
int imc_hdr, i, j;
int flag;
int bits, summer;
int counter, bitscount;
uint16_t buf16[IMC_BLOCK_SIZE / 2];
if (buf_size < IMC_BLOCK_SIZE) {
av_log(avctx, AV_LOG_ERROR, "imc frame too small!\n");
return -1;
}
for(i = 0; i < IMC_BLOCK_SIZE / 2; i++)
buf16[i] = bswap_16(((const uint16_t*)buf)[i]);
init_get_bits(&q->gb, (const uint8_t*)buf16, IMC_BLOCK_SIZE * 8);
/* Check the frame header */
imc_hdr = get_bits(&q->gb, 9);
if (imc_hdr != IMC_FRAME_ID) {
av_log(avctx, AV_LOG_ERROR, "imc frame header check failed!\n");
av_log(avctx, AV_LOG_ERROR, "got %x instead of 0x21.\n", imc_hdr);
return -1;
}
stream_format_code = get_bits(&q->gb, 3);
if(stream_format_code & 1){
av_log(avctx, AV_LOG_ERROR, "Stream code format %X is not supported\n", stream_format_code);
return -1;
}
// av_log(avctx, AV_LOG_DEBUG, "stream_format_code = %d\n", stream_format_code);
if (stream_format_code & 0x04)
q->decoder_reset = 1;
if(q->decoder_reset) {
memset(q->out_samples, 0, sizeof(q->out_samples));
for(i = 0; i < BANDS; i++)q->old_floor[i] = 1.0;
for(i = 0; i < COEFFS; i++)q->CWdecoded[i] = 0;
q->decoder_reset = 0;
}
flag = get_bits1(&q->gb);
imc_read_level_coeffs(q, stream_format_code, q->levlCoeffBuf);
if (stream_format_code & 0x4)
imc_decode_level_coefficients(q, q->levlCoeffBuf, q->flcoeffs1, q->flcoeffs2);
else
imc_decode_level_coefficients2(q, q->levlCoeffBuf, q->old_floor, q->flcoeffs1, q->flcoeffs2);
memcpy(q->old_floor, q->flcoeffs1, 32 * sizeof(float));
counter = 0;
for (i=0 ; i<BANDS ; i++) {
if (q->levlCoeffBuf[i] == 16) {
q->bandWidthT[i] = 0;
counter++;
} else
q->bandWidthT[i] = band_tab[i+1] - band_tab[i];
}
memset(q->bandFlagsBuf, 0, BANDS * sizeof(int));
for(i = 0; i < BANDS-1; i++) {
if (q->bandWidthT[i])
q->bandFlagsBuf[i] = get_bits1(&q->gb);
}
imc_calculate_coeffs(q, q->flcoeffs1, q->flcoeffs2, q->bandWidthT, q->flcoeffs3, q->flcoeffs5);
bitscount = 0;
/* first 4 bands will be assigned 5 bits per coefficient */
if (stream_format_code & 0x2) {
bitscount += 15;
q->bitsBandT[0] = 5;
q->CWlengthT[0] = 5;
q->CWlengthT[1] = 5;
q->CWlengthT[2] = 5;
for(i = 1; i < 4; i++){
bits = (q->levlCoeffBuf[i] == 16) ? 0 : 5;
q->bitsBandT[i] = bits;
for(j = band_tab[i]; j < band_tab[i+1]; j++) {
q->CWlengthT[j] = bits;
bitscount += bits;
}
}
}
if(bit_allocation (q, stream_format_code, 512 - bitscount - get_bits_count(&q->gb), flag) < 0) {
av_log(avctx, AV_LOG_ERROR, "Bit allocations failed\n");
q->decoder_reset = 1;
return -1;
}
for(i = 0; i < BANDS; i++) {
q->sumLenArr[i] = 0;
q->skipFlagRaw[i] = 0;
for(j = band_tab[i]; j < band_tab[i+1]; j++)
q->sumLenArr[i] += q->CWlengthT[j];
if (q->bandFlagsBuf[i])
if( (((band_tab[i+1] - band_tab[i]) * 1.5) > q->sumLenArr[i]) && (q->sumLenArr[i] > 0))
q->skipFlagRaw[i] = 1;
}
imc_get_skip_coeff(q);
for(i = 0; i < BANDS; i++) {
q->flcoeffs6[i] = q->flcoeffs1[i];
/* band has flag set and at least one coded coefficient */
if (q->bandFlagsBuf[i] && (band_tab[i+1] - band_tab[i]) != q->skipFlagCount[i]){
q->flcoeffs6[i] *= q->sqrt_tab[band_tab[i+1] - band_tab[i]] /
q->sqrt_tab[(band_tab[i+1] - band_tab[i] - q->skipFlagCount[i])];
}
}
/* calculate bits left, bits needed and adjust bit allocation */
bits = summer = 0;
for(i = 0; i < BANDS; i++) {
if (q->bandFlagsBuf[i]) {
for(j = band_tab[i]; j < band_tab[i+1]; j++) {
if(q->skipFlags[j]) {
summer += q->CWlengthT[j];
q->CWlengthT[j] = 0;
}
}
bits += q->skipFlagBits[i];
summer -= q->skipFlagBits[i];
}
}
imc_adjust_bit_allocation(q, summer);
for(i = 0; i < BANDS; i++) {
q->sumLenArr[i] = 0;
for(j = band_tab[i]; j < band_tab[i+1]; j++)
if (!q->skipFlags[j])
q->sumLenArr[i] += q->CWlengthT[j];
}
memset(q->codewords, 0, sizeof(q->codewords));
if(imc_get_coeffs(q) < 0) {
av_log(avctx, AV_LOG_ERROR, "Read coefficients failed\n");
q->decoder_reset = 1;
return 0;
}
if(inverse_quant_coeff(q, stream_format_code) < 0) {
av_log(avctx, AV_LOG_ERROR, "Inverse quantization of coefficients failed\n");
q->decoder_reset = 1;
return 0;
}
memset(q->skipFlags, 0, sizeof(q->skipFlags));
imc_imdct256(q);
q->dsp.float_to_int16(data, q->out_samples, COEFFS);
*data_size = COEFFS * sizeof(int16_t);
return IMC_BLOCK_SIZE;
}
static av_cold int imc_decode_close(AVCodecContext * avctx)
{
IMCContext *q = avctx->priv_data;
ff_fft_end(&q->fft);
return 0;
}
AVCodec imc_decoder = {
.name = "imc",
.type = CODEC_TYPE_AUDIO,
.id = CODEC_ID_IMC,
.priv_data_size = sizeof(IMCContext),
.init = imc_decode_init,
.close = imc_decode_close,
.decode = imc_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("IMC (Intel Music Coder)"),
};
@@ -0,0 +1,169 @@
/*
* IMC compatible decoder
* Copyright (c) 2002-2004 Maxim Poliakovski
* Copyright (c) 2006 Benjamin Larsson
* Copyright (c) 2006 Konstantin Shishkov
*
* 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
*/
#ifndef FFMPEG_IMCDATA_H
#define FFMPEG_IMCDATA_H
#include <stdint.h>
static const uint16_t band_tab[33] = {
0, 3, 6, 9, 12, 16, 20, 24, 29, 34, 40,
46, 53, 60, 68, 76, 84, 93, 102, 111, 121, 131,
141, 151, 162, 173, 184, 195, 207, 219, 231, 243, 256,
};
static const int8_t cyclTab[32] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 32,
};
static const int8_t cyclTab2[32] = {
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29};
static const float imc_weights1[31] = {
0.119595, 0.123124, 0.129192, 9.97377e-2, 8.1923e-2, 9.61153e-2, 8.77885e-2, 8.61174e-2,
9.00882e-2, 9.91658e-2, 0.112991, 0.131126, 0.152886, 0.177292, 0.221782, 0.244917, 0.267386,
0.306816, 0.323046, 0.33729, 0.366773, 0.392557, 0.398076, 0.403302, 0.42451, 0.444777,
0.449188, 0.455445, 0.477853, 0.500669, 0.510395};
static const float imc_weights2[31] = {
3.23466e-3, 3.49886e-3, 3.98413e-3, 1.98116e-3, 1.16465e-3, 1.79283e-3, 1.40372e-3, 1.33274e-3,
1.50523e-3, 1.95064e-3, 2.77472e-3, 4.14725e-3, 6.2776e-3, 9.36401e-3, 1.71397e-2, 2.24052e-2,
2.83971e-2, 4.11689e-2, 4.73165e-2, 5.31631e-2, 6.66614e-2, 8.00824e-2, 8.31588e-2, 8.61397e-2,
9.89229e-2, 0.112197, 0.115227, 0.119613, 0.136174, 0.15445, 0.162685};
static const float imc_quantizer1[4][8] = {
{ 8.4431201e-1, 4.7358301e-1, 1.448354, 2.7073899e-1, 7.4449003e-1, 1.241991, 1.845484, 0.0},
{ 8.6876702e-1, 4.7659001e-1, 1.478224, 2.5672799e-1, 7.55777e-1, 1.3229851, 2.03438, 0.0},
{ 7.5891501e-1, 6.2272799e-1, 1.271322, 3.47904e-1, 7.5317699e-1, 1.150767, 1.628476, 0.0},
{ 7.65257e-1, 6.44647e-1, 1.263824, 3.4548101e-1, 7.6384902e-1, 1.214466, 1.7638789, 0.0},
};
static const float imc_quantizer2[2][56] = {
{ 1.39236e-1, 3.50548e-1, 5.9547901e-1, 8.5772401e-1, 1.121545, 1.3882281, 1.695882, 2.1270809,
7.2221003e-2, 1.85177e-1, 2.9521701e-1, 4.12568e-1, 5.4068601e-1, 6.7679501e-1, 8.1196898e-1, 9.4765198e-1,
1.0779999, 1.203415, 1.337265, 1.481871, 1.639982, 1.814766, 2.0701399, 2.449862,
3.7533998e-2, 1.02722e-1, 1.6021401e-1, 2.16043e-1, 2.7231601e-1, 3.3025399e-1, 3.9022601e-1, 4.52849e-1,
5.1794899e-1, 5.8529502e-1, 6.53956e-1, 7.2312802e-1, 7.9150802e-1, 8.5891002e-1, 9.28141e-1, 9.9706203e-1,
1.062153, 1.12564, 1.189834, 1.256122, 1.324469, 1.3955311, 1.468906, 1.545084,
1.6264729, 1.711524, 1.802705, 1.91023, 2.0533991, 2.22333, 2.4830019, 3.253329 },
{ 1.11654e-1, 3.54469e-1, 6.4232099e-1, 9.6128798e-1, 1.295053, 1.61777, 1.989839, 2.51107,
5.7721999e-2, 1.69879e-1, 2.97589e-1, 4.3858799e-1, 5.9039903e-1, 7.4934798e-1, 9.1628098e-1, 1.087297,
1.262751, 1.4288321, 1.6040879, 1.79067, 2.000668, 2.2394669, 2.649332, 5.2760072,
2.9722e-2, 8.7316997e-2, 1.4445201e-1, 2.04247e-1, 2.6879501e-1, 3.3716801e-1, 4.08811e-1, 4.8306999e-1,
5.6049401e-1, 6.3955498e-1, 7.2044599e-1, 8.0427998e-1, 8.8933599e-1, 9.7537601e-1, 1.062461, 1.1510431,
1.240236, 1.326715, 1.412513, 1.500502, 1.591749, 1.686413, 1.785239, 1.891233,
2.0051291, 2.127681, 2.2709141, 2.475826, 2.7219379, 3.101985, 4.686213, 6.2287788},
};
static const float xTab[14] = {7.6, 3.6, 4.4, 3.7, 6.1, 5.1, 2.3, 1.6, 6.2, 1.5, 1.8, 1.2, 0, 0}; //10014048
/* precomputed table for 10^(i/4), i=-15..16 */
static const float imc_exp_tab[32] = {
1.778280e-4, 3.162278e-4, 5.623413e-4, 1.000000e-3,
1.778280e-3, 3.162278e-3, 5.623413e-3, 1.000000e-2,
1.778280e-2, 3.162278e-2, 5.623413e-2, 1.000000e-1,
1.778280e-1, 3.162278e-1, 5.623413e-1, 1.000000e00,
1.778280e00, 3.162278e00, 5.623413e00, 1.000000e01,
1.778280e01, 3.162278e01, 5.623413e01, 1.000000e02,
1.778280e02, 3.162278e02, 5.623413e02, 1.000000e03,
1.778280e03, 3.162278e03, 5.623413e03, 1.000000e04
};
static const float * const imc_exp_tab2 = imc_exp_tab + 8;
static const uint8_t imc_cb_select[4][32] = {
{ 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2 },
{ 0, 2, 0, 3, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2 },
{ 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
static const uint8_t imc_huffman_sizes[4] = {
17, 17, 18, 18
};
static const uint8_t imc_huffman_lens[4][4][18] = {
{
{ 16, 15, 13, 11, 8, 5, 3, 1, 2, 4, 6, 9, 10, 12, 14, 16, 7, 0 },
{ 10, 8, 7, 6, 4, 4, 3, 2, 2, 3, 4, 6, 7, 9, 11, 11, 7, 0 },
{ 15, 15, 14, 11, 8, 6, 4, 2, 1, 4, 5, 7, 9, 10, 12, 13, 4, 0 },
{ 13, 11, 10, 8, 6, 4, 2, 2, 2, 3, 5, 7, 9, 12, 15, 15, 14, 0 },
},
{
{ 14, 12, 10, 8, 7, 4, 2, 2, 2, 3, 5, 7, 9, 11, 13, 14, 7, 0 },
{ 14, 13, 11, 8, 6, 4, 3, 2, 2, 3, 5, 7, 9, 10, 12, 14, 3, 0 },
{ 13, 12, 10, 7, 5, 4, 3, 2, 2, 3, 4, 6, 8, 9, 11, 13, 4, 0 },
{ 13, 12, 10, 7, 5, 4, 3, 2, 2, 3, 4, 6, 8, 9, 11, 13, 4, 0 },
},
{
{ 16, 14, 12, 10, 8, 5, 3, 1, 2, 4, 7, 9, 11, 13, 15, 17, 6, 17 },
{ 15, 13, 11, 8, 6, 4, 2, 2, 2, 3, 5, 7, 10, 12, 14, 16, 9, 16 },
{ 14, 12, 11, 9, 8, 6, 3, 1, 2, 5, 7, 10, 13, 15, 16, 17, 4, 17 },
{ 16, 14, 12, 9, 7, 5, 2, 2, 2, 3, 4, 6, 8, 11, 13, 15, 10, 16 },
},
{
{ 13, 11, 10, 8, 7, 5, 2, 2, 2, 4, 6, 9, 12, 14, 15, 16, 3, 16 },
{ 11, 11, 10, 9, 8, 7, 5, 4, 3, 3, 3, 3, 3, 3, 4, 5, 6, 5 },
{ 9, 9, 7, 6, 5, 4, 3, 3, 2, 3, 4, 5, 4, 5, 5, 6, 8, 6 },
{ 13, 12, 10, 8, 5, 3, 3, 2, 2, 3, 4, 7, 9, 11, 14, 15, 6, 15 },
}
};
static const uint16_t imc_huffman_bits[4][4][18] = {
{
{ 0xCC32, 0x6618, 0x1987, 0x0660, 0x00CD, 0x0018, 0x0007, 0x0000, 0x0002, 0x000D, 0x0032, 0x0199, 0x0331, 0x0CC2, 0x330D, 0xCC33, 0x0067, 0x0000 },
{ 0x02FE, 0x00BE, 0x005E, 0x002D, 0x000A, 0x0009, 0x0003, 0x0003, 0x0000, 0x0002, 0x0008, 0x002C, 0x005D, 0x017E, 0x05FE, 0x05FF, 0x005C, 0x0000 },
{ 0x5169, 0x5168, 0x28B5, 0x0517, 0x00A3, 0x0029, 0x0008, 0x0003, 0x0000, 0x0009, 0x0015, 0x0050, 0x0144, 0x028A, 0x0A2C, 0x145B, 0x000B, 0x0000 },
{ 0x1231, 0x048D, 0x0247, 0x0090, 0x0025, 0x0008, 0x0001, 0x0003, 0x0000, 0x0005, 0x0013, 0x0049, 0x0122, 0x0919, 0x48C3, 0x48C2, 0x2460, 0x0000 },
},
{
{ 0x2D1D, 0x0B46, 0x02D0, 0x00B5, 0x0059, 0x000A, 0x0003, 0x0001, 0x0000, 0x0004, 0x0017, 0x005B, 0x0169, 0x05A2, 0x168F, 0x2D1C, 0x0058, 0x0000 },
{ 0x1800, 0x0C01, 0x0301, 0x0061, 0x0019, 0x0007, 0x0004, 0x0003, 0x0000, 0x0005, 0x000D, 0x0031, 0x00C1, 0x0181, 0x0601, 0x1801, 0x0002, 0x0000 },
{ 0x1556, 0x0AAA, 0x02AB, 0x0054, 0x0014, 0x000B, 0x0002, 0x0003, 0x0000, 0x0003, 0x0008, 0x002B, 0x00AB, 0x0154, 0x0554, 0x1557, 0x0009, 0x0000 },
{ 0x1556, 0x0AAA, 0x02AB, 0x0054, 0x0014, 0x000B, 0x0002, 0x0003, 0x0000, 0x0003, 0x0008, 0x002B, 0x00AB, 0x0154, 0x0554, 0x1557, 0x0009, 0x0000 },
},
{
{ 0x2993, 0x0A65, 0x0298, 0x00A7, 0x0028, 0x0004, 0x0000, 0x0001, 0x0001, 0x0003, 0x0015, 0x0052, 0x014D, 0x0533, 0x14C8, 0x5324, 0x000B, 0x5325 },
{ 0x09B8, 0x026F, 0x009A, 0x0012, 0x0005, 0x0000, 0x0001, 0x0002, 0x0003, 0x0001, 0x0003, 0x0008, 0x004C, 0x0136, 0x04DD, 0x1373, 0x0027, 0x1372 },
{ 0x0787, 0x01E0, 0x00F1, 0x003D, 0x001F, 0x0006, 0x0001, 0x0001, 0x0001, 0x0002, 0x000E, 0x0079, 0x03C2, 0x0F0D, 0x1E19, 0x3C30, 0x0000, 0x3C31 },
{ 0x4B06, 0x12C0, 0x04B1, 0x0097, 0x0024, 0x0008, 0x0002, 0x0003, 0x0000, 0x0003, 0x0005, 0x0013, 0x004A, 0x0259, 0x0961, 0x2582, 0x012D, 0x4B07 },
},
{
{ 0x0A5A, 0x0297, 0x014A, 0x0053, 0x0028, 0x000B, 0x0003, 0x0000, 0x0002, 0x0004, 0x0015, 0x00A4, 0x052C, 0x14B7, 0x296C, 0x52DB, 0x0003, 0x52DA },
{ 0x0193, 0x0192, 0x00C8, 0x0065, 0x0033, 0x0018, 0x0007, 0x0004, 0x0000, 0x0004, 0x0005, 0x0007, 0x0006, 0x0003, 0x0005, 0x0005, 0x000D, 0x0004 },
{ 0x0012, 0x0013, 0x0005, 0x0003, 0x0000, 0x0003, 0x0005, 0x0004, 0x0003, 0x0003, 0x0005, 0x0005, 0x0004, 0x0004, 0x0003, 0x0005, 0x0008, 0x0004 },
{ 0x0D66, 0x06B2, 0x01AD, 0x006A, 0x000C, 0x0005, 0x0004, 0x0000, 0x0003, 0x0002, 0x0007, 0x0034, 0x00D7, 0x0358, 0x1ACF, 0x359C, 0x001B, 0x359D },
}
};
#endif /* FFMPEG_IMCDATA_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,36 @@
/*
* Misc image conversion routines
* most functionality is exported to the public API, see avcodec.h
*
* Copyright (c) 2008 Vitor Sessak
*
* 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
*/
#ifndef FFMPEG_IMGCONVERT_H
#define FFMPEG_IMGCONVERT_H
#include <stdint.h>
#include "avcodec.h"
int ff_fill_linesize(AVPicture *picture, int pix_fmt, int width);
int ff_fill_pointer(AVPicture *picture, uint8_t *ptr, int pix_fmt, int height);
int ff_get_plane_bytewidth(enum PixelFormat pix_fmt, int width, int plane);
#endif /* FFMPEG_IMGCONVERT_H */
@@ -1,22 +1,28 @@
/*
* Templates for image convertion routines
* templates for image conversion routines
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* 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 of the License, or (at your option) any later version.
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* 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 this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* This header intentionally has no multiple inclusion guards. It is meant to
* be included multiple times and generates different code depending on the
* value of certain #defines. */
#ifndef RGB_OUT
#define RGB_OUT(d, r, g, b) RGBA_OUT(d, r, g, b, 0xff)
#endif
@@ -27,7 +33,7 @@ static void glue(yuv420p_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src,
const uint8_t *y1_ptr, *y2_ptr, *cb_ptr, *cr_ptr;
uint8_t *d, *d1, *d2;
int w, y, cb, cr, r_add, g_add, b_add, width2;
uint8_t *cm = cropTbl + MAX_NEG_CROP;
uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
unsigned int r, g, b;
d = dst->data[0];
@@ -121,7 +127,7 @@ static void glue(yuvj420p_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src,
const uint8_t *y1_ptr, *y2_ptr, *cb_ptr, *cr_ptr;
uint8_t *d, *d1, *d2;
int w, y, cb, cr, r_add, g_add, b_add, width2;
uint8_t *cm = cropTbl + MAX_NEG_CROP;
uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
unsigned int r, g, b;
d = dst->data[0];
@@ -408,16 +414,20 @@ static void glue(pal8_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src,
}
}
#if !defined(FMT_RGBA32) && defined(RGBA_OUT)
// RGB24 has optimized routines
#if !defined(FMT_RGB32) && !defined(FMT_RGB24)
/* alpha support */
static void glue(rgba32_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src,
static void glue(rgb32_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src,
int width, int height)
{
const uint8_t *s;
uint8_t *d;
int src_wrap, dst_wrap, j, y;
unsigned int v, r, g, b, a;
unsigned int v, r, g, b;
#ifdef RGBA_OUT
unsigned int a;
#endif
s = src->data[0];
src_wrap = src->linesize[0] - width * 4;
@@ -428,11 +438,15 @@ static void glue(rgba32_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src,
for(y=0;y<height;y++) {
for(j = 0;j < width; j++) {
v = ((const uint32_t *)(s))[0];
a = (v >> 24) & 0xff;
r = (v >> 16) & 0xff;
g = (v >> 8) & 0xff;
b = v & 0xff;
#ifdef RGBA_OUT
a = (v >> 24) & 0xff;
RGBA_OUT(d, r, g, b, a);
#else
RGB_OUT(d, r, g, b);
#endif
s += 4;
d += BPP;
}
@@ -441,13 +455,16 @@ static void glue(rgba32_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src,
}
}
static void glue(RGB_NAME, _to_rgba32)(AVPicture *dst, const AVPicture *src,
static void glue(RGB_NAME, _to_rgb32)(AVPicture *dst, const AVPicture *src,
int width, int height)
{
const uint8_t *s;
uint8_t *d;
int src_wrap, dst_wrap, j, y;
unsigned int r, g, b, a;
unsigned int r, g, b;
#ifdef RGBA_IN
unsigned int a;
#endif
s = src->data[0];
src_wrap = src->linesize[0] - width * BPP;
@@ -457,8 +474,13 @@ static void glue(RGB_NAME, _to_rgba32)(AVPicture *dst, const AVPicture *src,
for(y=0;y<height;y++) {
for(j = 0;j < width; j++) {
#ifdef RGBA_IN
RGBA_IN(r, g, b, a, s);
((uint32_t *)(d))[0] = (a << 24) | (r << 16) | (g << 8) | b;
#else
RGB_IN(r, g, b, s);
((uint32_t *)(d))[0] = (0xff << 24) | (r << 16) | (g << 8) | b;
#endif
d += 4;
s += BPP;
}
@@ -467,7 +489,7 @@ static void glue(RGB_NAME, _to_rgba32)(AVPicture *dst, const AVPicture *src,
}
}
#endif /* !defined(FMT_RGBA32) && defined(RGBA_IN) */
#endif /* !defined(FMT_RGB32) */
#ifndef FMT_RGB24
@@ -537,7 +559,7 @@ static void yuv444p_to_rgb24(AVPicture *dst, const AVPicture *src,
const uint8_t *y1_ptr, *cb_ptr, *cr_ptr;
uint8_t *d, *d1;
int w, y, cb, cr, r_add, g_add, b_add;
uint8_t *cm = cropTbl + MAX_NEG_CROP;
uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
unsigned int r, g, b;
d = dst->data[0];
@@ -570,7 +592,7 @@ static void yuvj444p_to_rgb24(AVPicture *dst, const AVPicture *src,
const uint8_t *y1_ptr, *cb_ptr, *cr_ptr;
uint8_t *d, *d1;
int w, y, cb, cr, r_add, g_add, b_add;
uint8_t *cm = cropTbl + MAX_NEG_CROP;
uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
unsigned int r, g, b;
d = dst->data[0];
@@ -770,7 +792,7 @@ static void rgb24_to_yuvj444p(AVPicture *dst, const AVPicture *src,
#endif /* FMT_RGB24 */
#if defined(FMT_RGB24) || defined(FMT_RGBA32)
#if defined(FMT_RGB24) || defined(FMT_RGB32)
static void glue(RGB_NAME, _to_pal8)(AVPicture *dst, const AVPicture *src,
int width, int height)
@@ -787,7 +809,7 @@ static void glue(RGB_NAME, _to_pal8)(AVPicture *dst, const AVPicture *src,
q = dst->data[0];
dst_wrap = dst->linesize[0] - width;
has_alpha = 0;
for(y=0;y<height;y++) {
for(x=0;x<width;x++) {
#ifdef RGBA_IN
@@ -816,12 +838,12 @@ static void glue(RGB_NAME, _to_pal8)(AVPicture *dst, const AVPicture *src,
build_rgb_palette(dst->data[1], has_alpha);
}
#endif /* defined(FMT_RGB24) || defined(FMT_RGBA32) */
#endif /* defined(FMT_RGB24) || defined(FMT_RGB32) */
#ifdef RGBA_IN
static int glue(get_alpha_info_, RGB_NAME)(const AVPicture *src,
int width, int height)
int width, int height)
{
const unsigned char *p;
int src_wrap, ret, x, y;
@@ -854,4 +876,4 @@ static int glue(get_alpha_info_, RGB_NAME)(const AVPicture *src,
#undef BPP
#undef RGB_NAME
#undef FMT_RGB24
#undef FMT_RGBA32
#undef FMT_RGB32
@@ -1,32 +1,35 @@
/*
* High quality image resampling with polyphase filters
* High quality image resampling with polyphase filters
* Copyright (c) 2001 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* 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 of the License, or (at your option) any later version.
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* 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 this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file imgresample.c
* High quality image resampling with polyphase filters .
*/
#include "avcodec.h"
#include "dsputil.h"
#include "swscale.h"
#ifdef USE_FASTMEMCPY
#include "fastmemcpy.h"
#ifdef HAVE_ALTIVEC
#include "ppc/imgresample_altivec.h"
#endif
#define NB_COMPONENTS 3
@@ -44,14 +47,25 @@
#define LINE_BUF_HEIGHT (NB_TAPS * 4)
struct SwsContext {
const AVClass *av_class;
struct ImgReSampleContext *resampling_ctx;
enum PixelFormat src_pix_fmt, dst_pix_fmt;
};
struct ImgReSampleContext {
int iwidth, iheight, owidth, oheight, topBand, bottomBand, leftBand, rightBand;
int iwidth, iheight, owidth, oheight;
int topBand, bottomBand, leftBand, rightBand;
int padtop, padbottom, padleft, padright;
int pad_owidth, pad_oheight;
int h_incr, v_incr;
int16_t h_filters[NB_PHASES][NB_TAPS] __align8; /* horizontal filters */
int16_t v_filters[NB_PHASES][NB_TAPS] __align8; /* vertical filters */
DECLARE_ALIGNED_8(int16_t, h_filters[NB_PHASES][NB_TAPS]); /* horizontal filters */
DECLARE_ALIGNED_8(int16_t, v_filters[NB_PHASES][NB_TAPS]); /* vertical filters */
uint8_t *line_buf;
};
void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type);
static inline int get_phase(int pos)
{
return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
@@ -59,8 +73,8 @@ static inline int get_phase(int pos)
/* This function must be optimized */
static void h_resample_fast(uint8_t *dst, int dst_width, const uint8_t *src,
int src_width, int src_start, int src_incr,
int16_t *filters)
int src_width, int src_start, int src_incr,
int16_t *filters)
{
int src_pos, phase, sum, i;
const uint8_t *s;
@@ -103,7 +117,7 @@ static void h_resample_fast(uint8_t *dst, int dst_width, const uint8_t *src,
/* This function must be optimized */
static void v_resample(uint8_t *dst, int dst_width, const uint8_t *src,
int wrap, int16_t *filter)
int wrap, int16_t *filter)
{
int sum, i;
const uint8_t *s;
@@ -158,18 +172,18 @@ static void v_resample(uint8_t *dst, int dst_width, const uint8_t *src,
src_pos += src_incr;\
}
#define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016Lx\n", tmp.uq);
#define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016"PRIx64"\n", tmp.uq);
/* XXX: do four pixels at a time */
static void h_resample_fast4_mmx(uint8_t *dst, int dst_width,
const uint8_t *src, int src_width,
const uint8_t *src, int src_width,
int src_start, int src_incr, int16_t *filters)
{
int src_pos, phase;
const uint8_t *s;
int16_t *filter;
mmx_t tmp;
src_pos = src_start;
pxor_r2r(mm7, mm7);
@@ -207,13 +221,13 @@ static void h_resample_fast4_mmx(uint8_t *dst, int dst_width,
}
static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
int wrap, int16_t *filter)
int wrap, int16_t *filter)
{
int sum, i, v;
const uint8_t *s;
mmx_t tmp;
mmx_t coefs[4];
for(i=0;i<4;i++) {
v = filter[i];
coefs[i].uw[0] = v;
@@ -221,7 +235,7 @@ static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
coefs[i].uw[2] = v;
coefs[i].uw[3] = v;
}
pxor_r2r(mm7, mm7);
s = src;
while (dst_width >= 4) {
@@ -243,7 +257,7 @@ static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
paddw_r2r(mm3, mm2);
paddw_r2r(mm2, mm0);
psraw_i2r(FILTER_BITS, mm0);
packuswb_r2r(mm7, mm0);
movq_r2m(mm0, tmp);
@@ -269,138 +283,11 @@ static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
}
emms();
}
#endif
#endif /* HAVE_MMX */
#ifdef HAVE_ALTIVEC
typedef union {
vector unsigned char v;
unsigned char c[16];
} vec_uc_t;
typedef union {
vector signed short v;
signed short s[8];
} vec_ss_t;
void v_resample16_altivec(uint8_t *dst, int dst_width, const uint8_t *src,
int wrap, int16_t *filter)
{
int sum, i;
const uint8_t *s;
vector unsigned char *tv, tmp, dstv, zero;
vec_ss_t srchv[4], srclv[4], fv[4];
vector signed short zeros, sumhv, sumlv;
s = src;
for(i=0;i<4;i++)
{
/*
The vec_madds later on does an implicit >>15 on the result.
Since FILTER_BITS is 8, and we have 15 bits of magnitude in
a signed short, we have just enough bits to pre-shift our
filter constants <<7 to compensate for vec_madds.
*/
fv[i].s[0] = filter[i] << (15-FILTER_BITS);
fv[i].v = vec_splat(fv[i].v, 0);
}
zero = vec_splat_u8(0);
zeros = vec_splat_s16(0);
/*
When we're resampling, we'd ideally like both our input buffers,
and output buffers to be 16-byte aligned, so we can do both aligned
reads and writes. Sadly we can't always have this at the moment, so
we opt for aligned writes, as unaligned writes have a huge overhead.
To do this, do enough scalar resamples to get dst 16-byte aligned.
*/
i = (-(int)dst) & 0xf;
while(i>0) {
sum = s[0 * wrap] * filter[0] +
s[1 * wrap] * filter[1] +
s[2 * wrap] * filter[2] +
s[3 * wrap] * filter[3];
sum = sum >> FILTER_BITS;
if (sum<0) sum = 0; else if (sum>255) sum=255;
dst[0] = sum;
dst++;
s++;
dst_width--;
i--;
}
/* Do our altivec resampling on 16 pixels at once. */
while(dst_width>=16) {
/*
Read 16 (potentially unaligned) bytes from each of
4 lines into 4 vectors, and split them into shorts.
Interleave the multipy/accumulate for the resample
filter with the loads to hide the 3 cycle latency
the vec_madds have.
*/
tv = (vector unsigned char *) &s[0 * wrap];
tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[i * wrap]));
srchv[0].v = (vector signed short) vec_mergeh(zero, tmp);
srclv[0].v = (vector signed short) vec_mergel(zero, tmp);
sumhv = vec_madds(srchv[0].v, fv[0].v, zeros);
sumlv = vec_madds(srclv[0].v, fv[0].v, zeros);
tv = (vector unsigned char *) &s[1 * wrap];
tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[1 * wrap]));
srchv[1].v = (vector signed short) vec_mergeh(zero, tmp);
srclv[1].v = (vector signed short) vec_mergel(zero, tmp);
sumhv = vec_madds(srchv[1].v, fv[1].v, sumhv);
sumlv = vec_madds(srclv[1].v, fv[1].v, sumlv);
tv = (vector unsigned char *) &s[2 * wrap];
tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[2 * wrap]));
srchv[2].v = (vector signed short) vec_mergeh(zero, tmp);
srclv[2].v = (vector signed short) vec_mergel(zero, tmp);
sumhv = vec_madds(srchv[2].v, fv[2].v, sumhv);
sumlv = vec_madds(srclv[2].v, fv[2].v, sumlv);
tv = (vector unsigned char *) &s[3 * wrap];
tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[3 * wrap]));
srchv[3].v = (vector signed short) vec_mergeh(zero, tmp);
srclv[3].v = (vector signed short) vec_mergel(zero, tmp);
sumhv = vec_madds(srchv[3].v, fv[3].v, sumhv);
sumlv = vec_madds(srclv[3].v, fv[3].v, sumlv);
/*
Pack the results into our destination vector,
and do an aligned write of that back to memory.
*/
dstv = vec_packsu(sumhv, sumlv) ;
vec_st(dstv, 0, (vector unsigned char *) dst);
dst+=16;
s+=16;
dst_width-=16;
}
/*
If there are any leftover pixels, resample them
with the slow scalar method.
*/
while(dst_width>0) {
sum = s[0 * wrap] * filter[0] +
s[1 * wrap] * filter[1] +
s[2 * wrap] * filter[2] +
s[3 * wrap] * filter[3];
sum = sum >> FILTER_BITS;
if (sum<0) sum = 0; else if (sum>255) sum=255;
dst[0] = sum;
dst++;
s++;
dst_width--;
}
}
#endif
/* slow version to handle limit cases. Does not need optimisation */
/* slow version to handle limit cases. Does not need optimization */
static void h_resample_slow(uint8_t *dst, int dst_width,
const uint8_t *src, int src_width,
const uint8_t *src, int src_width,
int src_start, int src_incr, int16_t *filters)
{
int src_pos, phase, sum, j, v, i;
@@ -436,8 +323,8 @@ static void h_resample_slow(uint8_t *dst, int dst_width,
}
static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
int src_width, int src_start, int src_incr,
int16_t *filters)
int src_width, int src_start, int src_incr,
int16_t *filters)
{
int n, src_end;
@@ -450,29 +337,29 @@ static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
}
src_end = src_start + dst_width * src_incr;
if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
src_incr;
} else {
n = dst_width;
}
#ifdef HAVE_MMX
if ((mm_flags & MM_MMX) && NB_TAPS == 4)
h_resample_fast4_mmx(dst, n,
h_resample_fast4_mmx(dst, n,
src, src_width, src_start, src_incr, filters);
else
#endif
h_resample_fast(dst, n,
h_resample_fast(dst, n,
src, src_width, src_start, src_incr, filters);
if (n < dst_width) {
dst += n;
dst_width -= n;
src_start += n * src_incr;
h_resample_slow(dst, dst_width,
h_resample_slow(dst, dst_width,
src, src_width, src_start, src_incr, filters);
}
}
static void component_resample(ImgReSampleContext *s,
static void component_resample(ImgReSampleContext *s,
uint8_t *output, int owrap, int owidth, int oheight,
uint8_t *input, int iwrap, int iwidth, int iheight)
{
@@ -481,7 +368,7 @@ static void component_resample(ImgReSampleContext *s,
last_src_y = - FCENTER - 1;
/* position of the bottom of the filter in the source image */
src_y = (last_src_y + NB_TAPS) * POS_FRAC;
src_y = (last_src_y + NB_TAPS) * POS_FRAC;
ring_y = NB_TAPS; /* position in ring buffer */
for(y=0;y<oheight;y++) {
/* apply horizontal filter on new lines from input if needed */
@@ -501,10 +388,10 @@ static void component_resample(ImgReSampleContext *s,
src_line = input + y1 * iwrap;
new_line = s->line_buf + ring_y * owidth;
/* apply filter and handle limit cases correctly */
h_resample(new_line, owidth,
src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
h_resample(new_line, owidth,
src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
&s->h_filters[0][0]);
/* handle ring buffer wraping */
/* handle ring buffer wrapping */
if (ring_y >= LINE_BUF_HEIGHT) {
memcpy(s->line_buf + (ring_y - LINE_BUF_HEIGHT) * owidth,
new_line, owidth);
@@ -515,8 +402,8 @@ static void component_resample(ImgReSampleContext *s,
#ifdef HAVE_MMX
/* desactivated MMX because loss of precision */
if ((mm_flags & MM_MMX) && NB_TAPS == 4 && 0)
v_resample4_mmx(output, owidth,
s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
v_resample4_mmx(output, owidth,
s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
&s->v_filters[phase_y][0]);
else
#endif
@@ -527,100 +414,94 @@ static void component_resample(ImgReSampleContext *s,
&s->v_filters[phase_y][0]);
else
#endif
v_resample(output, owidth,
s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
v_resample(output, owidth,
s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
&s->v_filters[phase_y][0]);
src_y += s->v_incr;
output += owrap;
}
}
/* XXX: the following filter is quite naive, but it seems to suffice
for 4 taps */
static void build_filter(int16_t *filter, float factor)
{
int ph, i, v;
float x, y, tab[NB_TAPS], norm, mult;
/* if upsampling, only need to interpolate, no filter */
if (factor > 1.0)
factor = 1.0;
for(ph=0;ph<NB_PHASES;ph++) {
norm = 0;
for(i=0;i<NB_TAPS;i++) {
x = M_PI * ((float)(i - FCENTER) - (float)ph / NB_PHASES) * factor;
if (x == 0)
y = 1.0;
else
y = sin(x) / x;
tab[i] = y;
norm += y;
}
/* normalize so that an uniform color remains the same */
mult = (float)(1 << FILTER_BITS) / norm;
for(i=0;i<NB_TAPS;i++) {
v = (int)(tab[i] * mult);
filter[ph * NB_TAPS + i] = v;
}
}
}
ImgReSampleContext *img_resample_init(int owidth, int oheight,
int iwidth, int iheight)
{
return img_resample_full_init(owidth, oheight, iwidth, iheight, 0, 0, 0, 0);
return img_resample_full_init(owidth, oheight, iwidth, iheight,
0, 0, 0, 0, 0, 0, 0, 0);
}
ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
int iwidth, int iheight,
int topBand, int bottomBand,
int leftBand, int rightBand)
int leftBand, int rightBand,
int padtop, int padbottom,
int padleft, int padright)
{
ImgReSampleContext *s;
if (!owidth || !oheight || !iwidth || !iheight)
return NULL;
s = av_mallocz(sizeof(ImgReSampleContext));
if (!s)
return NULL;
s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
if (!s->line_buf)
if((unsigned)owidth >= UINT_MAX / (LINE_BUF_HEIGHT + NB_TAPS))
goto fail;
s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
if (!s->line_buf)
goto fail;
s->owidth = owidth;
s->oheight = oheight;
s->iwidth = iwidth;
s->iheight = iheight;
s->topBand = topBand;
s->bottomBand = bottomBand;
s->leftBand = leftBand;
s->rightBand = rightBand;
s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / owidth;
s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / oheight;
build_filter(&s->h_filters[0][0], (float) owidth / (float) (iwidth - leftBand - rightBand));
build_filter(&s->v_filters[0][0], (float) oheight / (float) (iheight - topBand - bottomBand));
s->padtop = padtop;
s->padbottom = padbottom;
s->padleft = padleft;
s->padright = padright;
s->pad_owidth = owidth - (padleft + padright);
s->pad_oheight = oheight - (padtop + padbottom);
s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / s->pad_owidth;
s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / s->pad_oheight;
av_build_filter(&s->h_filters[0][0], (float) s->pad_owidth /
(float) (iwidth - leftBand - rightBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
av_build_filter(&s->v_filters[0][0], (float) s->pad_oheight /
(float) (iheight - topBand - bottomBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
return s;
fail:
fail:
av_free(s);
return NULL;
}
void img_resample(ImgReSampleContext *s,
void img_resample(ImgReSampleContext *s,
AVPicture *output, const AVPicture *input)
{
int i, shift;
uint8_t* optr;
for(i=0;i<3;i++) {
for (i=0;i<3;i++) {
shift = (i == 0) ? 0 : 1;
component_resample(s, output->data[i], output->linesize[i],
s->owidth >> shift, s->oheight >> shift,
input->data[i] + (input->linesize[i] * (s->topBand >> shift)) + (s->leftBand >> shift),
input->linesize[i], ((s->iwidth - s->leftBand - s->rightBand) >> shift),
optr = output->data[i] + (((output->linesize[i] *
s->padtop) + s->padleft) >> shift);
component_resample(s, optr, output->linesize[i],
s->pad_owidth >> shift, s->pad_oheight >> shift,
input->data[i] + (input->linesize[i] *
(s->topBand >> shift)) + (s->leftBand >> shift),
input->linesize[i], ((s->iwidth - s->leftBand -
s->rightBand) >> shift),
(s->iheight - s->topBand - s->bottomBand) >> shift);
}
}
@@ -631,22 +512,192 @@ void img_resample_close(ImgReSampleContext *s)
av_free(s);
}
static const char *context_to_name(void* ptr)
{
return "imgconvert";
}
static const AVClass context_class = { "imgresample", context_to_name, NULL };
struct SwsContext *sws_getContext(int srcW, int srcH, int srcFormat,
int dstW, int dstH, int dstFormat,
int flags, SwsFilter *srcFilter,
SwsFilter *dstFilter, double *param)
{
struct SwsContext *ctx;
ctx = av_malloc(sizeof(struct SwsContext));
if (!ctx) {
av_log(NULL, AV_LOG_ERROR, "Cannot allocate a resampling context!\n");
return NULL;
}
ctx->av_class = &context_class;
if ((srcH != dstH) || (srcW != dstW)) {
if ((srcFormat != PIX_FMT_YUV420P) || (dstFormat != PIX_FMT_YUV420P)) {
av_log(ctx, AV_LOG_INFO, "PIX_FMT_YUV420P will be used as an intermediate format for rescaling\n");
}
ctx->resampling_ctx = img_resample_init(dstW, dstH, srcW, srcH);
} else {
ctx->resampling_ctx = av_malloc(sizeof(ImgReSampleContext));
ctx->resampling_ctx->iheight = srcH;
ctx->resampling_ctx->iwidth = srcW;
ctx->resampling_ctx->oheight = dstH;
ctx->resampling_ctx->owidth = dstW;
}
ctx->src_pix_fmt = srcFormat;
ctx->dst_pix_fmt = dstFormat;
return ctx;
}
void sws_freeContext(struct SwsContext *ctx)
{
if (!ctx)
return;
if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
(ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
img_resample_close(ctx->resampling_ctx);
} else {
av_free(ctx->resampling_ctx);
}
av_free(ctx);
}
/**
* Checks if context is valid or reallocs a new one instead.
* If context is NULL, just calls sws_getContext() to get a new one.
* Otherwise, checks if the parameters are the same already saved in context.
* If that is the case, returns the current context.
* Otherwise, frees context and gets a new one.
*
* Be warned that srcFilter, dstFilter are not checked, they are
* asumed to remain valid.
*/
struct SwsContext *sws_getCachedContext(struct SwsContext *ctx,
int srcW, int srcH, int srcFormat,
int dstW, int dstH, int dstFormat, int flags,
SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
{
if (ctx != NULL) {
if ((ctx->resampling_ctx->iwidth != srcW) ||
(ctx->resampling_ctx->iheight != srcH) ||
(ctx->src_pix_fmt != srcFormat) ||
(ctx->resampling_ctx->owidth != dstW) ||
(ctx->resampling_ctx->oheight != dstH) ||
(ctx->dst_pix_fmt != dstFormat))
{
sws_freeContext(ctx);
ctx = NULL;
}
}
if (ctx == NULL) {
return sws_getContext(srcW, srcH, srcFormat,
dstW, dstH, dstFormat, flags,
srcFilter, dstFilter, param);
}
return ctx;
}
int sws_scale(struct SwsContext *ctx, uint8_t* src[], int srcStride[],
int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[])
{
AVPicture src_pict, dst_pict;
int i, res = 0;
AVPicture picture_format_temp;
AVPicture picture_resample_temp, *formatted_picture, *resampled_picture;
uint8_t *buf1 = NULL, *buf2 = NULL;
enum PixelFormat current_pix_fmt;
for (i = 0; i < 4; i++) {
src_pict.data[i] = src[i];
src_pict.linesize[i] = srcStride[i];
dst_pict.data[i] = dst[i];
dst_pict.linesize[i] = dstStride[i];
}
if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
(ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
/* We have to rescale the picture, but only YUV420P rescaling is supported... */
if (ctx->src_pix_fmt != PIX_FMT_YUV420P) {
int size;
/* create temporary picture for rescaling input*/
size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
buf1 = av_malloc(size);
if (!buf1) {
res = -1;
goto the_end;
}
formatted_picture = &picture_format_temp;
avpicture_fill((AVPicture*)formatted_picture, buf1,
PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
if (img_convert((AVPicture*)formatted_picture, PIX_FMT_YUV420P,
&src_pict, ctx->src_pix_fmt,
ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight) < 0) {
av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
res = -1;
goto the_end;
}
} else {
formatted_picture = &src_pict;
}
if (ctx->dst_pix_fmt != PIX_FMT_YUV420P) {
int size;
/* create temporary picture for rescaling output*/
size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
buf2 = av_malloc(size);
if (!buf2) {
res = -1;
goto the_end;
}
resampled_picture = &picture_resample_temp;
avpicture_fill((AVPicture*)resampled_picture, buf2,
PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
} else {
resampled_picture = &dst_pict;
}
/* ...and finally rescale!!! */
img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
current_pix_fmt = PIX_FMT_YUV420P;
} else {
resampled_picture = &src_pict;
current_pix_fmt = ctx->src_pix_fmt;
}
if (current_pix_fmt != ctx->dst_pix_fmt) {
if (img_convert(&dst_pict, ctx->dst_pix_fmt,
resampled_picture, current_pix_fmt,
ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight) < 0) {
av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
res = -1;
goto the_end;
}
} else if (resampled_picture != &dst_pict) {
av_picture_copy(&dst_pict, resampled_picture, current_pix_fmt,
ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
}
the_end:
av_free(buf1);
av_free(buf2);
return res;
}
#ifdef TEST
void *av_mallocz(int size)
{
void *ptr;
ptr = malloc(size);
memset(ptr, 0, size);
return ptr;
}
void av_free(void *ptr)
{
/* XXX: this test should not be needed on most libcs */
if (ptr)
free(ptr);
}
#include <stdio.h>
#undef exit
/* input */
#define XSIZE 256
@@ -661,11 +712,13 @@ uint8_t img2[XSIZE1 * YSIZE1];
void save_pgm(const char *filename, uint8_t *img, int xsize, int ysize)
{
#undef fprintf
FILE *f;
f=fopen(filename,"w");
fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
fwrite(img,1, xsize * ysize,f);
fclose(f);
#define fprintf please_use_av_log
}
static void dump_filter(int16_t *filter)
@@ -673,11 +726,11 @@ static void dump_filter(int16_t *filter)
int i, ph;
for(ph=0;ph<NB_PHASES;ph++) {
printf("%2d: ", ph);
av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
for(i=0;i<NB_TAPS;i++) {
printf(" %5.2f", filter[ph * NB_TAPS + i] / 256.0);
av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
}
printf("\n");
av_log(NULL, AV_LOG_INFO, "\n");
}
}
@@ -703,20 +756,20 @@ int main(int argc, char **argv)
else
v = 0x00;
} else if (x < XSIZE/4) {
if (x & 1)
if (x & 1)
v = 0xff;
else
else
v = 0;
} else if (y < XSIZE/4) {
if (y & 1)
if (y & 1)
v = 0xff;
else
else
v = 0;
} else {
if (y < YSIZE*3/8) {
if ((y+x) & 1)
if ((y+x) & 1)
v = 0xff;
else
else
v = 0;
} else {
if (((x+3) % 4) <= 1 &&
@@ -741,20 +794,20 @@ int main(int argc, char **argv)
fact = factors[i];
xsize = (int)(XSIZE * fact);
ysize = (int)((YSIZE - 100) * fact);
s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0);
printf("Factor=%0.2f\n", fact);
s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0, 0, 0, 0, 0);
av_log(NULL, AV_LOG_INFO, "Factor=%0.2f\n", fact);
dump_filter(&s->h_filters[0][0]);
component_resample(s, img1, xsize, xsize, ysize,
img + 50 * XSIZE, XSIZE, XSIZE, YSIZE - 100);
img_resample_close(s);
sprintf(buf, "/tmp/out%d.pgm", i);
snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
save_pgm(buf, img1, xsize, ysize);
}
/* mmx test */
#ifdef HAVE_MMX
printf("MMX test\n");
av_log(NULL, AV_LOG_INFO, "MMX test\n");
fact = 0.72;
xsize = (int)(XSIZE * fact);
ysize = (int)(YSIZE * fact);
@@ -768,12 +821,12 @@ int main(int argc, char **argv)
component_resample(s, img2, xsize, xsize, ysize,
img, XSIZE, XSIZE, YSIZE);
if (memcmp(img1, img2, xsize * ysize) != 0) {
fprintf(stderr, "mmx error\n");
av_log(NULL, AV_LOG_ERROR, "mmx error\n");
exit(1);
}
printf("MMX OK\n");
#endif
av_log(NULL, AV_LOG_INFO, "MMX OK\n");
#endif /* HAVE_MMX */
return 0;
}
#endif
#endif /* TEST */
@@ -0,0 +1,59 @@
/*
* imx dump header bitstream filter
* Copyright (c) 2007 Baptiste Coudurier.
*
* 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
*/
/**
* @file imx_dump_header_bsf.c
* imx dump header bitstream filter
* modifies bitstream to fit in mov and be decoded by final cut pro decoder
*/
#include "avcodec.h"
#include "bytestream.h"
static int imx_dump_header(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size, int keyframe)
{
/* MXF essence element key */
static const uint8_t imx_header[16] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x05,0x01,0x01,0x00 };
uint8_t *poutbufp;
if (avctx->codec_id != CODEC_ID_MPEG2VIDEO) {
av_log(avctx, AV_LOG_ERROR, "imx bitstream filter only applies to mpeg2video codec\n");
return 0;
}
*poutbuf = av_malloc(buf_size + 20 + FF_INPUT_BUFFER_PADDING_SIZE);
poutbufp = *poutbuf;
bytestream_put_buffer(&poutbufp, imx_header, 16);
bytestream_put_byte(&poutbufp, 0x83); /* KLV BER long form */
bytestream_put_be24(&poutbufp, buf_size);
bytestream_put_buffer(&poutbufp, buf, buf_size);
*poutbuf_size = poutbufp - *poutbuf;
return 1;
}
AVBitStreamFilter imx_dump_header_bsf = {
"imxdump",
0,
imx_dump_header,
};
@@ -0,0 +1,223 @@
/*
* Intel Indeo 2 codec
* Copyright (c) 2005 Konstantin Shishkov
*
* 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
*/
/**
* @file indeo2.c
* Intel Indeo 2 decoder.
*/
#define ALT_BITSTREAM_READER_LE
#include "avcodec.h"
#include "bitstream.h"
#include "indeo2data.h"
typedef struct Ir2Context{
AVCodecContext *avctx;
AVFrame picture;
GetBitContext gb;
int decode_delta;
} Ir2Context;
#define CODE_VLC_BITS 14
static VLC ir2_vlc;
/* Indeo 2 codes are in range 0x01..0x7F and 0x81..0x90 */
static inline int ir2_get_code(GetBitContext *gb)
{
return get_vlc2(gb, ir2_vlc.table, CODE_VLC_BITS, 1) + 1;
}
static int ir2_decode_plane(Ir2Context *ctx, int width, int height, uint8_t *dst, int stride,
const uint8_t *table)
{
int i;
int j;
int out = 0;
int c;
int t;
if(width&1)
return -1;
/* first line contain absolute values, other lines contain deltas */
while (out < width){
c = ir2_get_code(&ctx->gb);
if(c >= 0x80) { /* we have a run */
c -= 0x7F;
if(out + c*2 > width)
return -1;
for (i = 0; i < c * 2; i++)
dst[out++] = 0x80;
} else { /* copy two values from table */
dst[out++] = table[c * 2];
dst[out++] = table[(c * 2) + 1];
}
}
dst += stride;
for (j = 1; j < height; j++){
out = 0;
while (out < width){
c = ir2_get_code(&ctx->gb);
if(c >= 0x80) { /* we have a skip */
c -= 0x7F;
if(out + c*2 > width)
return -1;
for (i = 0; i < c * 2; i++) {
dst[out] = dst[out - stride];
out++;
}
} else { /* add two deltas from table */
t = dst[out - stride] + (table[c * 2] - 128);
t= av_clip_uint8(t);
dst[out] = t;
out++;
t = dst[out - stride] + (table[(c * 2) + 1] - 128);
t= av_clip_uint8(t);
dst[out] = t;
out++;
}
}
dst += stride;
}
return 0;
}
static int ir2_decode_plane_inter(Ir2Context *ctx, int width, int height, uint8_t *dst, int stride,
const uint8_t *table)
{
int j;
int out = 0;
int c;
int t;
if(width&1)
return -1;
for (j = 0; j < height; j++){
out = 0;
while (out < width){
c = ir2_get_code(&ctx->gb);
if(c >= 0x80) { /* we have a skip */
c -= 0x7F;
out += c * 2;
} else { /* add two deltas from table */
t = dst[out] + (((table[c * 2] - 128)*3) >> 2);
t= av_clip_uint8(t);
dst[out] = t;
out++;
t = dst[out] + (((table[(c * 2) + 1] - 128)*3) >> 2);
t= av_clip_uint8(t);
dst[out] = t;
out++;
}
}
dst += stride;
}
return 0;
}
static int ir2_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
const uint8_t *buf, int buf_size)
{
Ir2Context * const s = avctx->priv_data;
AVFrame *picture = data;
AVFrame * const p= (AVFrame*)&s->picture;
int start;
if(p->data[0])
avctx->release_buffer(avctx, p);
p->reference = 1;
p->buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
if (avctx->reget_buffer(avctx, p)) {
av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
return -1;
}
s->decode_delta = buf[18];
/* decide whether frame uses deltas or not */
#ifndef ALT_BITSTREAM_READER_LE
for (i = 0; i < buf_size; i++)
buf[i] = ff_reverse[buf[i]];
#endif
start = 48; /* hardcoded for now */
init_get_bits(&s->gb, buf + start, buf_size - start);
if (s->decode_delta) { /* intraframe */
ir2_decode_plane(s, avctx->width, avctx->height,
s->picture.data[0], s->picture.linesize[0], ir2_luma_table);
/* swapped U and V */
ir2_decode_plane(s, avctx->width >> 2, avctx->height >> 2,
s->picture.data[2], s->picture.linesize[2], ir2_luma_table);
ir2_decode_plane(s, avctx->width >> 2, avctx->height >> 2,
s->picture.data[1], s->picture.linesize[1], ir2_luma_table);
} else { /* interframe */
ir2_decode_plane_inter(s, avctx->width, avctx->height,
s->picture.data[0], s->picture.linesize[0], ir2_luma_table);
/* swapped U and V */
ir2_decode_plane_inter(s, avctx->width >> 2, avctx->height >> 2,
s->picture.data[2], s->picture.linesize[2], ir2_luma_table);
ir2_decode_plane_inter(s, avctx->width >> 2, avctx->height >> 2,
s->picture.data[1], s->picture.linesize[1], ir2_luma_table);
}
*picture= *(AVFrame*)&s->picture;
*data_size = sizeof(AVPicture);
return buf_size;
}
static av_cold int ir2_decode_init(AVCodecContext *avctx){
Ir2Context * const ic = avctx->priv_data;
ic->avctx = avctx;
avctx->pix_fmt= PIX_FMT_YUV410P;
if (!ir2_vlc.table)
#ifdef ALT_BITSTREAM_READER_LE
init_vlc(&ir2_vlc, CODE_VLC_BITS, IR2_CODES,
&ir2_codes[0][1], 4, 2,
&ir2_codes[0][0], 4, 2, INIT_VLC_USE_STATIC | INIT_VLC_LE);
#else
init_vlc(&ir2_vlc, CODE_VLC_BITS, IR2_CODES,
&ir2_codes[0][1], 4, 2,
&ir2_codes[0][0], 4, 2, INIT_VLC_USE_STATIC);
#endif
return 0;
}
AVCodec indeo2_decoder = {
"indeo2",
CODEC_TYPE_VIDEO,
CODEC_ID_INDEO2,
sizeof(Ir2Context),
ir2_decode_init,
NULL,
NULL,
ir2_decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Intel Indeo 2"),
};
@@ -0,0 +1,141 @@
/*
* Intel Indeo 2 codec
* copyright (c) 2005 Konstantin Shishkov
*
* 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
*/
#ifndef FFMPEG_INDEO2DATA_H
#define FFMPEG_INDEO2DATA_H
#include <stdint.h>
#define IR2_CODES 143
static const uint16_t ir2_codes[IR2_CODES][2] = {
#ifdef ALT_BITSTREAM_READER_LE
{0x0000, 3}, {0x0004, 3}, {0x0006, 3}, {0x0001, 5},
{0x0009, 5}, {0x0019, 5}, {0x000D, 5}, {0x001D, 5},
{0x0023, 6}, {0x0013, 6}, {0x0033, 6}, {0x000B, 6},
{0x002B, 6}, {0x001B, 6}, {0x0007, 8}, {0x0087, 8},
{0x0027, 8}, {0x00A7, 8}, {0x0067, 8}, {0x00E7, 8},
{0x0097, 8}, {0x0057, 8}, {0x0037, 8}, {0x00B7, 8},
{0x00F7, 8}, {0x000F, 9}, {0x008F, 9}, {0x018F, 9},
{0x014F, 9}, {0x00CF, 9}, {0x002F, 9}, {0x012F, 9},
{0x01AF, 9}, {0x006F, 9}, {0x00EF, 9}, {0x01EF, 9},
{0x001F, 10}, {0x021F, 10}, {0x011F, 10}, {0x031F, 10},
{0x009F, 10}, {0x029F, 10}, {0x019F, 10}, {0x039F, 10},
{0x005F, 10}, {0x025F, 10}, {0x015F, 10}, {0x035F, 10},
{0x00DF, 10}, {0x02DF, 10}, {0x01DF, 10}, {0x03DF, 10},
{0x003F, 13}, {0x103F, 13}, {0x083F, 13}, {0x183F, 13},
{0x043F, 13}, {0x143F, 13}, {0x0C3F, 13}, {0x1C3F, 13},
{0x023F, 13}, {0x123F, 13}, {0x0A3F, 13}, {0x1A3F, 13},
{0x063F, 13}, {0x163F, 13}, {0x0E3F, 13}, {0x1E3F, 13},
{0x013F, 13}, {0x113F, 13}, {0x093F, 13}, {0x193F, 13},
{0x053F, 13}, {0x153F, 13}, {0x0D3F, 13}, {0x1D3F, 13},
{0x033F, 13}, {0x133F, 13}, {0x0B3F, 13}, {0x1B3F, 13},
{0x073F, 13}, {0x173F, 13}, {0x0F3F, 13}, {0x1F3F, 13},
{0x00BF, 13}, {0x10BF, 13}, {0x08BF, 13}, {0x18BF, 13},
{0x04BF, 13}, {0x14BF, 13}, {0x0CBF, 13}, {0x1CBF, 13},
{0x02BF, 13}, {0x12BF, 13}, {0x0ABF, 13}, {0x1ABF, 13},
{0x06BF, 13}, {0x16BF, 13}, {0x0EBF, 13}, {0x1EBF, 13},
{0x01BF, 13}, {0x11BF, 13}, {0x09BF, 13}, {0x19BF, 13},
{0x05BF, 13}, {0x15BF, 13}, {0x0DBF, 13}, {0x1DBF, 13},
{0x03BF, 13}, {0x13BF, 13}, {0x0BBF, 13}, {0x1BBF, 13},
{0x07BF, 13}, {0x17BF, 13}, {0x0FBF, 13}, {0x1FBF, 13},
{0x007F, 14}, {0x207F, 14}, {0x107F, 14}, {0x307F, 14},
{0x087F, 14}, {0x287F, 14}, {0x187F, 14}, {0x387F, 14},
{0x047F, 14}, {0x247F, 14}, {0x147F, 14}, {0x0002, 3},
{0x0011, 5}, {0x0005, 5}, {0x0015, 5}, {0x0003, 6},
{0x003B, 6}, {0x0047, 8}, {0x00C7, 8}, {0x0017, 8},
{0x00D7, 8}, {0x0077, 8}, {0x010F, 9}, {0x004F, 9},
{0x01CF, 9}, {0x00AF, 9}, {0x016F, 9},
#else
{0x0000, 3}, {0x0001, 3}, {0x0003, 3}, {0x0010, 5},
{0x0012, 5}, {0x0013, 5}, {0x0016, 5}, {0x0017, 5},
{0x0031, 6}, {0x0032, 6}, {0x0033, 6}, {0x0034, 6},
{0x0035, 6}, {0x0036, 6}, {0x00E0, 8}, {0x00E1, 8},
{0x00E4, 8}, {0x00E5, 8}, {0x00E6, 8}, {0x00E7, 8},
{0x00E9, 8}, {0x00EA, 8}, {0x00EC, 8}, {0x00ED, 8},
{0x00EF, 8}, {0x01E0, 9}, {0x01E2, 9}, {0x01E3, 9},
{0x01E5, 9}, {0x01E6, 9}, {0x01E8, 9}, {0x01E9, 9},
{0x01EB, 9}, {0x01EC, 9}, {0x01EE, 9}, {0x01EF, 9},
{0x03E0, 10}, {0x03E1, 10}, {0x03E2, 10}, {0x03E3, 10},
{0x03E4, 10}, {0x03E5, 10}, {0x03E6, 10}, {0x03E7, 10},
{0x03E8, 10}, {0x03E9, 10}, {0x03EA, 10}, {0x03EB, 10},
{0x03EC, 10}, {0x03ED, 10}, {0x03EE, 10}, {0x03EF, 10},
{0x1F80, 13}, {0x1F81, 13}, {0x1F82, 13}, {0x1F83, 13},
{0x1F84, 13}, {0x1F85, 13}, {0x1F86, 13}, {0x1F87, 13},
{0x1F88, 13}, {0x1F89, 13}, {0x1F8A, 13}, {0x1F8B, 13},
{0x1F8C, 13}, {0x1F8D, 13}, {0x1F8E, 13}, {0x1F8F, 13},
{0x1F90, 13}, {0x1F91, 13}, {0x1F92, 13}, {0x1F93, 13},
{0x1F94, 13}, {0x1F95, 13}, {0x1F96, 13}, {0x1F97, 13},
{0x1F98, 13}, {0x1F99, 13}, {0x1F9A, 13}, {0x1F9B, 13},
{0x1F9C, 13}, {0x1F9D, 13}, {0x1F9E, 13}, {0x1F9F, 13},
{0x1FA0, 13}, {0x1FA1, 13}, {0x1FA2, 13}, {0x1FA3, 13},
{0x1FA4, 13}, {0x1FA5, 13}, {0x1FA6, 13}, {0x1FA7, 13},
{0x1FA8, 13}, {0x1FA9, 13}, {0x1FAA, 13}, {0x1FAB, 13},
{0x1FAC, 13}, {0x1FAD, 13}, {0x1FAE, 13}, {0x1FAF, 13},
{0x1FB0, 13}, {0x1FB1, 13}, {0x1FB2, 13}, {0x1FB3, 13},
{0x1FB4, 13}, {0x1FB5, 13}, {0x1FB6, 13}, {0x1FB7, 13},
{0x1FB8, 13}, {0x1FB9, 13}, {0x1FBA, 13}, {0x1FBB, 13},
{0x1FBC, 13}, {0x1FBD, 13}, {0x1FBE, 13}, {0x1FBF, 13},
{0x3F80, 14}, {0x3F81, 14}, {0x3F82, 14}, {0x3F83, 14},
{0x3F84, 14}, {0x3F85, 14}, {0x3F86, 14}, {0x3F87, 14},
{0x3F88, 14}, {0x3F89, 14}, {0x3F8A, 14}, {0x0002, 3},
{0x0011, 5}, {0x0014, 5}, {0x0015, 5}, {0x0030, 6},
{0x0037, 6}, {0x00E2, 8}, {0x00E3, 8}, {0x00E8, 8},
{0x00EB, 8}, {0x00EE, 8}, {0x01E1, 9}, {0x01E4, 9},
{0x01E7, 9}, {0x01EA, 9}, {0x01ED, 9}
#endif
};
static const uint8_t ir2_luma_table[256] = {
0x80, 0x80, 0x84, 0x84, 0x7C, 0x7C, 0x7F, 0x85,
0x81, 0x7B, 0x85, 0x7F, 0x7B, 0x81, 0x8C, 0x8C,
0x74, 0x74, 0x83, 0x8D, 0x7D, 0x73, 0x8D, 0x83,
0x73, 0x7D, 0x77, 0x89, 0x89, 0x77, 0x89, 0x77,
0x77, 0x89, 0x8C, 0x95, 0x74, 0x6B, 0x95, 0x8C,
0x6B, 0x74, 0x7C, 0x90, 0x84, 0x70, 0x90, 0x7C,
0x70, 0x84, 0x96, 0x96, 0x6A, 0x6A, 0x82, 0x98,
0x7E, 0x68, 0x98, 0x82, 0x68, 0x7E, 0x97, 0xA2,
0x69, 0x5E, 0xA2, 0x97, 0x5E, 0x69, 0xA2, 0xA2,
0x5E, 0x5E, 0x8B, 0xA3, 0x75, 0x5D, 0xA3, 0x8B,
0x5D, 0x75, 0x71, 0x95, 0x8F, 0x6B, 0x95, 0x71,
0x6B, 0x8F, 0x78, 0x9D, 0x88, 0x63, 0x9D, 0x78,
0x63, 0x88, 0x7F, 0xA7, 0x81, 0x59, 0xA7, 0x7F,
0x59, 0x81, 0xA4, 0xB1, 0x5C, 0x4F, 0xB1, 0xA4,
0x4F, 0x5C, 0x96, 0xB1, 0x6A, 0x4F, 0xB1, 0x96,
0x4F, 0x6A, 0xB2, 0xB2, 0x4E, 0x4E, 0x65, 0x9B,
0x9B, 0x65, 0x9B, 0x65, 0x65, 0x9B, 0x89, 0xB4,
0x77, 0x4C, 0xB4, 0x89, 0x4C, 0x77, 0x6A, 0xA3,
0x96, 0x5D, 0xA3, 0x6A, 0x5D, 0x96, 0x73, 0xAC,
0x8D, 0x54, 0xAC, 0x73, 0x54, 0x8D, 0xB4, 0xC3,
0x4C, 0x3D, 0xC3, 0xB4, 0x3D, 0x4C, 0xA4, 0xC3,
0x5C, 0x3D, 0xC3, 0xA4, 0x3D, 0x5C, 0xC4, 0xC4,
0x3C, 0x3C, 0x96, 0xC6, 0x6A, 0x3A, 0xC6, 0x96,
0x3A, 0x6A, 0x7C, 0xBA, 0x84, 0x46, 0xBA, 0x7C,
0x46, 0x84, 0x5B, 0xAB, 0xA5, 0x55, 0xAB, 0x5B,
0x55, 0xA5, 0x63, 0xB4, 0x9D, 0x4C, 0xB4, 0x63,
0x4C, 0x9D, 0x86, 0xCA, 0x7A, 0x36, 0xCA, 0x86,
0x36, 0x7A, 0xB6, 0xD7, 0x4A, 0x29, 0xD7, 0xB6,
0x29, 0x4A, 0xC8, 0xD7, 0x38, 0x29, 0xD7, 0xC8,
0x29, 0x38, 0xA4, 0xD8, 0x5C, 0x28, 0xD8, 0xA4,
0x28, 0x5C, 0x6C, 0xC1, 0x94, 0x3F, 0xC1, 0x6C,
0x3F, 0x94, 0xD9, 0xD9, 0x27, 0x27, 0x80, 0x80
};
#endif /* FFMPEG_INDEO2DATA_H */
@@ -2,19 +2,21 @@
* Intel Indeo 3 (IV31, IV32, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*
* This library is free software; you can redistribute it and/or
* 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 of the License, or (at your option) any later version.
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* 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 this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
@@ -22,10 +24,9 @@
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
#include "bytestream.h"
#include "indeo3data.h"
@@ -53,15 +54,15 @@ typedef struct Indeo3DecodeContext {
unsigned short *corrector_type;
} Indeo3DecodeContext;
static int corrector_type_0[24] = {
static const int corrector_type_0[24] = {
195, 159, 133, 115, 101, 93, 87, 77,
195, 159, 133, 115, 101, 93, 87, 77,
128, 79, 79, 79, 79, 79, 79, 79
};
static int corrector_type_2[8] = { 9, 7, 6, 8, 5, 4, 3, 2 };
static const int corrector_type_2[8] = { 9, 7, 6, 8, 5, 4, 3, 2 };
static void build_modpred(Indeo3DecodeContext *s)
static av_cold void build_modpred(Indeo3DecodeContext *s)
{
int i, j;
@@ -70,13 +71,13 @@ static void build_modpred(Indeo3DecodeContext *s)
for (i=0; i < 128; ++i) {
s->ModPred[i+0*128] = (i > 126) ? 254 : 2*((i + 1) - ((i + 1) % 2));
s->ModPred[i+1*128] = (i == 7) ? 20 : ((i == 119 || i == 120)
? 236 : 2*((i + 2) - ((i + 1) % 3)));
? 236 : 2*((i + 2) - ((i + 1) % 3)));
s->ModPred[i+2*128] = (i > 125) ? 248 : 2*((i + 2) - ((i + 2) % 4));
s->ModPred[i+3*128] = 2*((i + 1) - ((i - 3) % 5));
s->ModPred[i+3*128] = 2*((i + 1) - ((i - 3) % 5));
s->ModPred[i+4*128] = (i == 8) ? 20 : 2*((i + 1) - ((i - 3) % 6));
s->ModPred[i+5*128] = 2*((i + 4) - ((i + 3) % 7));
s->ModPred[i+5*128] = 2*((i + 4) - ((i + 3) % 7));
s->ModPred[i+6*128] = (i > 123) ? 240 : 2*((i + 4) - ((i + 4) % 8));
s->ModPred[i+7*128] = 2*((i + 5) - ((i + 4) % 9));
s->ModPred[i+7*128] = 2*((i + 5) - ((i + 4) % 9));
}
s->corrector_type = (unsigned short *) av_malloc (24 * 256 * sizeof(unsigned short));
@@ -84,31 +85,30 @@ static void build_modpred(Indeo3DecodeContext *s)
for (i=0; i < 24; ++i) {
for (j=0; j < 256; ++j) {
s->corrector_type[i*256+j] = (j < corrector_type_0[i])
? 1 : ((j < 248 || (i == 16 && j == 248))
? 0 : corrector_type_2[j - 248]);
? 1 : ((j < 248 || (i == 16 && j == 248))
? 0 : corrector_type_2[j - 248]);
}
}
}
static void iv_Decode_Chunk(Indeo3DecodeContext *s, unsigned char *cur,
unsigned char *ref, int width, int height, unsigned char *buf1,
long fflags2, unsigned char *hdr,
unsigned char *buf2, int min_width_160);
#define min(a,b) ((a) < (b) ? (a) : (b))
static void iv_Decode_Chunk(Indeo3DecodeContext *s, unsigned char *cur,
unsigned char *ref, int width, int height, const unsigned char *buf1,
long fflags2, const unsigned char *hdr,
const unsigned char *buf2, int min_width_160);
/* ---------------------------------------------------------------------- */
static void iv_alloc_frames(Indeo3DecodeContext *s)
static av_cold void iv_alloc_frames(Indeo3DecodeContext *s)
{
int luma_width, luma_height, luma_pixels, chroma_width, chroma_height,
chroma_pixels, bufsize, i;
chroma_pixels, i;
unsigned int bufsize;
luma_width = (s->width + 3) & (~3);
luma_height = (s->height + 3) & (~3);
s->iv_frame[0].y_w = s->iv_frame[0].y_h =
s->iv_frame[0].y_w = s->iv_frame[0].y_h =
s->iv_frame[0].the_buf_size = 0;
s->iv_frame[1].y_w = s->iv_frame[1].y_h =
s->iv_frame[1].y_w = s->iv_frame[1].y_h =
s->iv_frame[1].the_buf_size = 0;
s->iv_frame[1].the_buf = NULL;
@@ -117,11 +117,11 @@ static void iv_alloc_frames(Indeo3DecodeContext *s)
luma_pixels = luma_width * luma_height;
chroma_pixels = chroma_width * chroma_height;
bufsize = luma_pixels * 2 + luma_width * 3 +
bufsize = luma_pixels * 2 + luma_width * 3 +
(chroma_pixels + chroma_width) * 4;
if((s->iv_frame[0].the_buf =
(s->iv_frame[0].the_buf_size == 0 ? av_malloc(bufsize) :
if((s->iv_frame[0].the_buf =
(s->iv_frame[0].the_buf_size == 0 ? av_malloc(bufsize) :
av_realloc(s->iv_frame[0].the_buf, bufsize))) == NULL)
return;
s->iv_frame[0].y_w = s->iv_frame[1].y_w = luma_width;
@@ -143,7 +143,7 @@ static void iv_alloc_frames(Indeo3DecodeContext *s)
s->iv_frame[1].Vbuf = s->iv_frame[0].the_buf + i;
for(i = 1; i <= luma_width; i++)
s->iv_frame[0].Ybuf[-i] = s->iv_frame[1].Ybuf[-i] =
s->iv_frame[0].Ybuf[-i] = s->iv_frame[1].Ybuf[-i] =
s->iv_frame[0].Ubuf[-i] = 0x80;
for(i = 1; i <= chroma_width; i++) {
@@ -155,14 +155,14 @@ static void iv_alloc_frames(Indeo3DecodeContext *s)
}
/* ---------------------------------------------------------------------- */
static void iv_free_func(Indeo3DecodeContext *s)
static av_cold void iv_free_func(Indeo3DecodeContext *s)
{
int i;
for(i = 0 ; i < 2 ; i++) {
if(s->iv_frame[i].the_buf != NULL)
if(s->iv_frame[i].the_buf != NULL)
av_free(s->iv_frame[i].the_buf);
s->iv_frame[i].Ybuf = s->iv_frame[i].Ubuf =
s->iv_frame[i].Ybuf = s->iv_frame[i].Ubuf =
s->iv_frame[i].Vbuf = NULL;
s->iv_frame[i].the_buf = NULL;
s->iv_frame[i].the_buf_size = 0;
@@ -175,35 +175,33 @@ static void iv_free_func(Indeo3DecodeContext *s)
}
/* ---------------------------------------------------------------------- */
static unsigned long iv_decode_frame(Indeo3DecodeContext *s,
unsigned char *buf, int buf_size)
static unsigned long iv_decode_frame(Indeo3DecodeContext *s,
const unsigned char *buf, int buf_size)
{
unsigned int hdr_width, hdr_height,
chroma_width, chroma_height;
unsigned long fflags1, fflags2, fflags3, offs1, offs2, offs3, offs;
unsigned char *hdr_pos, *buf_pos;
const unsigned char *hdr_pos, *buf_pos;
buf_pos = buf;
buf_pos += 18;
fflags1 = le2me_16(*(uint16_t *)buf_pos);
buf_pos += 2;
fflags3 = le2me_32(*(uint32_t *)buf_pos);
buf_pos += 4;
fflags1 = bytestream_get_le16(&buf_pos);
fflags3 = bytestream_get_le32(&buf_pos);
fflags2 = *buf_pos++;
buf_pos += 3;
hdr_height = le2me_16(*(uint16_t *)buf_pos);
buf_pos += 2;
hdr_width = le2me_16(*(uint16_t *)buf_pos);
buf_pos += 2;
hdr_height = bytestream_get_le16(&buf_pos);
hdr_width = bytestream_get_le16(&buf_pos);
if(avcodec_check_dimensions(NULL, hdr_width, hdr_height))
return -1;
chroma_height = ((hdr_height >> 2) + 3) & 0x7ffc;
chroma_width = ((hdr_width >> 2) + 3) & 0x7ffc;
offs1 = le2me_32(*(uint32_t *)buf_pos);
offs1 = bytestream_get_le32(&buf_pos);
offs2 = bytestream_get_le32(&buf_pos);
offs3 = bytestream_get_le32(&buf_pos);
buf_pos += 4;
offs2 = le2me_32(*(uint32_t *)buf_pos);
buf_pos += 4;
offs3 = le2me_32(*(uint32_t *)buf_pos);
buf_pos += 8;
hdr_pos = buf_pos;
if(fflags3 == 0x80) return 4;
@@ -216,28 +214,30 @@ static unsigned long iv_decode_frame(Indeo3DecodeContext *s,
}
buf_pos = buf + 16 + offs1;
offs = le2me_32(*(uint32_t *)buf_pos);
buf_pos += 4;
offs = bytestream_get_le32(&buf_pos);
iv_Decode_Chunk(s, s->cur_frame->Ybuf, s->ref_frame->Ybuf, hdr_width,
hdr_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos,
min(hdr_width, 160));
iv_Decode_Chunk(s, s->cur_frame->Ybuf, s->ref_frame->Ybuf, hdr_width,
hdr_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos,
FFMIN(hdr_width, 160));
if (!(s->avctx->flags & CODEC_FLAG_GRAY))
{
buf_pos = buf + 16 + offs2;
offs = le2me_32(*(uint32_t *)buf_pos);
buf_pos += 4;
offs = bytestream_get_le32(&buf_pos);
iv_Decode_Chunk(s, s->cur_frame->Vbuf, s->ref_frame->Vbuf, chroma_width,
chroma_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos,
min(chroma_width, 40));
iv_Decode_Chunk(s, s->cur_frame->Vbuf, s->ref_frame->Vbuf, chroma_width,
chroma_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos,
FFMIN(chroma_width, 40));
buf_pos = buf + 16 + offs3;
offs = le2me_32(*(uint32_t *)buf_pos);
buf_pos += 4;
offs = bytestream_get_le32(&buf_pos);
iv_Decode_Chunk(s, s->cur_frame->Ubuf, s->ref_frame->Ubuf, chroma_width,
chroma_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos,
min(chroma_width, 40));
iv_Decode_Chunk(s, s->cur_frame->Ubuf, s->ref_frame->Ubuf, chroma_width,
chroma_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos,
FFMIN(chroma_width, 40));
}
return 8;
}
@@ -297,14 +297,14 @@ typedef struct {
lp2 = 4;
static void iv_Decode_Chunk(Indeo3DecodeContext *s,
unsigned char *cur, unsigned char *ref, int width, int height,
unsigned char *buf1, long fflags2, unsigned char *hdr,
unsigned char *buf2, int min_width_160)
unsigned char *cur, unsigned char *ref, int width, int height,
const unsigned char *buf1, long fflags2, const unsigned char *hdr,
const unsigned char *buf2, int min_width_160)
{
unsigned char bit_buf;
unsigned long bit_pos, lv, lv1, lv2;
long *width_tbl, width_tbl_arr[10];
char *ref_vectors;
const signed char *ref_vectors;
unsigned char *cur_frm_pos, *ref_frm_pos, *cp, *cp2;
uint32_t *cur_lp, *ref_lp;
const uint32_t *correction_lp[2], *correctionloworder_lp[2], *correctionhighorder_lp[2];
@@ -312,13 +312,14 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
ustr_t strip_tbl[20], *strip;
int i, j, k, lp1, lp2, flag1, cmd, blks_width, blks_height, region_160_width,
rle_v1, rle_v2, rle_v3;
unsigned short res;
bit_buf = 0;
ref_vectors = NULL;
width_tbl = width_tbl_arr + 1;
i = (width < 0 ? width + 3 : width)/4;
for(j = -1; j < 8; j++)
for(j = -1; j < 8; j++)
width_tbl[j] = i * j;
strip = strip_tbl;
@@ -368,7 +369,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
} else if(cmd == 3) {
if(strip->usl7 == 0) {
strip->usl7 = 1;
ref_vectors = buf2 + (*buf1 * 2);
ref_vectors = (const signed char*)buf2 + (*buf1 * 2);
buf1++;
continue;
}
@@ -376,7 +377,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
cur_frm_pos = cur + width * strip->ypos + strip->xpos;
if((blks_width = strip->width) < 0)
if((blks_width = strip->width) < 0)
blks_width += 3;
blks_width >>= 2;
blks_height = strip->height;
@@ -384,7 +385,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
if(ref_vectors != NULL) {
ref_frm_pos = ref + (ref_vectors[0] + strip->ypos) * width +
ref_vectors[1] + strip->xpos;
} else
} else
ref_frm_pos = cur_frm_pos - width_tbl[4];
if(cmd == 2) {
@@ -403,7 +404,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
cur_frm_pos += 4;
ref_frm_pos += 4;
}
} else if(cmd != 1)
} else if(cmd != 1)
return;
} else {
k = *buf1 >> 4;
@@ -414,9 +415,9 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
if((lv - 8) <= 7 && (k == 0 || k == 3 || k == 10)) {
cp2 = s->ModPred + ((lv - 8) << 7);
cp = ref_frm_pos;
for(i = 0; i < blks_width << 2; i++) {
for(i = 0; i < blks_width << 2; i++) {
int v = *cp >> 1;
*(cp++) = cp2[v];
*(cp++) = cp2[v];
}
}
@@ -446,14 +447,15 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
switch(correction_type_sp[0][k]) {
case 0:
*cur_lp = ((*ref_lp >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
*cur_lp = le2me_32(((le2me_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
lp2++;
break;
case 1:
((unsigned short *)cur_lp)[0] = ((((unsigned short *)(ref_lp))[0] >> 1)
+ correction_lp[lp2 & 0x01][*buf1++]) << 1;
((unsigned short *)cur_lp)[1] = ((((unsigned short *)(ref_lp))[1] >> 1)
+ correction_lp[lp2 & 0x01][k]) << 1;
res = ((le2me_16(((unsigned short *)(ref_lp))[0]) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1;
((unsigned short *)cur_lp)[0] = le2me_16(res);
res = ((le2me_16(((unsigned short *)(ref_lp))[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
((unsigned short *)cur_lp)[1] = le2me_16(res);
buf1++;
lp2++;
break;
case 2:
@@ -494,7 +496,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
break;
case 7:
if(rle_v3 != 0)
if(rle_v3 != 0)
rle_v3 = 0;
else {
buf1--;
@@ -518,7 +520,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
LV1_CHECK(buf1,rle_v3,lv1,lp2)
break;
default:
default:
return;
}
}
@@ -534,7 +536,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
case 4:
case 3: /********** CASE 3 **********/
if(ref_vectors != NULL)
if(ref_vectors != NULL)
return;
flag1 = 1;
@@ -548,23 +550,25 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
switch(correction_type_sp[lp2 & 0x01][k]) {
case 0:
cur_lp[width_tbl[1]] = ((*ref_lp >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
cur_lp[width_tbl[1]] = le2me_32(((le2me_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
if(lp2 > 0 || flag1 == 0 || strip->ypos != 0)
cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
else
cur_lp[0] = ((*ref_lp >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
cur_lp[0] = le2me_32(((le2me_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
lp2++;
break;
case 1:
((unsigned short *)cur_lp)[width_tbl[2]] =
((((unsigned short *)ref_lp)[0] >> 1) + correction_lp[lp2 & 0x01][*buf1++]) << 1;
((unsigned short *)cur_lp)[width_tbl[2]+1] =
((((unsigned short *)ref_lp)[1] >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
res = ((le2me_16(((unsigned short *)ref_lp)[0]) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1;
((unsigned short *)cur_lp)[width_tbl[2]] = le2me_16(res);
res = ((le2me_16(((unsigned short *)ref_lp)[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
((unsigned short *)cur_lp)[width_tbl[2]+1] = le2me_16(res);
if(lp2 > 0 || flag1 == 0 || strip->ypos != 0)
cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
else
cur_lp[0] = cur_lp[width_tbl[1]];
buf1++;
lp2++;
break;
@@ -589,7 +593,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
break;
case 7:
if(rle_v3 != 0)
if(rle_v3 != 0)
rle_v3 = 0;
else {
buf1--;
@@ -634,7 +638,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
LV1_CHECK(buf1,rle_v3,lv1,lp2)
break;
default:
default:
return;
}
}
@@ -660,16 +664,23 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
lv1 = ref_lp[0];
lv2 = ref_lp[1];
if(lp2 == 0 && flag1 != 0) {
#ifdef WORDS_BIGENDIAN
lv1 = lv1 & 0xFF00FF00;
lv1 = (lv1 >> 8) | lv1;
lv2 = lv2 & 0xFF00FF00;
lv2 = (lv2 >> 8) | lv2;
#else
lv1 = lv1 & 0x00FF00FF;
lv1 = (lv1 << 8) | lv1;
lv2 = lv2 & 0x00FF00FF;
lv2 = (lv2 << 8) | lv2;
#endif
}
switch(correction_type_sp[lp2 & 0x01][k]) {
case 0:
cur_lp[width_tbl[1]] = ((lv1 >> 1) + correctionloworder_lp[lp2 & 0x01][k]) << 1;
cur_lp[width_tbl[1]+1] = ((lv2 >> 1) + correctionhighorder_lp[lp2 & 0x01][k]) << 1;
cur_lp[width_tbl[1]] = le2me_32(((le2me_32(lv1) >> 1) + correctionloworder_lp[lp2 & 0x01][k]) << 1);
cur_lp[width_tbl[1]+1] = le2me_32(((le2me_32(lv2) >> 1) + correctionhighorder_lp[lp2 & 0x01][k]) << 1);
if(lp2 > 0 || strip->ypos != 0 || flag1 == 0) {
cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
cur_lp[1] = ((cur_lp[-width_tbl[1]+1] >> 1) + (cur_lp[width_tbl[1]+1] >> 1)) & 0xFEFEFEFE;
@@ -681,8 +692,8 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
break;
case 1:
cur_lp[width_tbl[1]] = ((lv1 >> 1) + correctionloworder_lp[lp2 & 0x01][*buf1++]) << 1;
cur_lp[width_tbl[1]+1] = ((lv2 >> 1) + correctionloworder_lp[lp2 & 0x01][k]) << 1;
cur_lp[width_tbl[1]] = le2me_32(((le2me_32(lv1) >> 1) + correctionloworder_lp[lp2 & 0x01][*buf1]) << 1);
cur_lp[width_tbl[1]+1] = le2me_32(((le2me_32(lv2) >> 1) + correctionloworder_lp[lp2 & 0x01][k]) << 1);
if(lp2 > 0 || strip->ypos != 0 || flag1 == 0) {
cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
cur_lp[1] = ((cur_lp[-width_tbl[1]+1] >> 1) + (cur_lp[width_tbl[1]+1] >> 1)) & 0xFEFEFEFE;
@@ -690,6 +701,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
cur_lp[0] = cur_lp[width_tbl[1]];
cur_lp[1] = cur_lp[width_tbl[1]+1];
}
buf1++;
lp2++;
break;
@@ -780,7 +792,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
case 7:
if(lp2 == 0) {
if(rle_v3 != 0)
if(rle_v3 != 0)
rle_v3 = 0;
else {
buf1--;
@@ -801,7 +813,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
LV1_CHECK(buf1,rle_v3,lv1,lp2)
break;
default:
default:
return;
}
}
@@ -824,20 +836,20 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
case 0:
lv1 = correctionloworder_lp[lp2 & 0x01][k];
lv2 = correctionhighorder_lp[lp2 & 0x01][k];
cur_lp[0] = ((ref_lp[0] >> 1) + lv1) << 1;
cur_lp[1] = ((ref_lp[1] >> 1) + lv2) << 1;
cur_lp[width_tbl[1]] = ((ref_lp[width_tbl[1]] >> 1) + lv1) << 1;
cur_lp[width_tbl[1]+1] = ((ref_lp[width_tbl[1]+1] >> 1) + lv2) << 1;
cur_lp[0] = le2me_32(((le2me_32(ref_lp[0]) >> 1) + lv1) << 1);
cur_lp[1] = le2me_32(((le2me_32(ref_lp[1]) >> 1) + lv2) << 1);
cur_lp[width_tbl[1]] = le2me_32(((le2me_32(ref_lp[width_tbl[1]]) >> 1) + lv1) << 1);
cur_lp[width_tbl[1]+1] = le2me_32(((le2me_32(ref_lp[width_tbl[1]+1]) >> 1) + lv2) << 1);
lp2++;
break;
case 1:
lv1 = correctionloworder_lp[lp2 & 0x01][*buf1++];
lv2 = correctionloworder_lp[lp2 & 0x01][k];
cur_lp[0] = ((ref_lp[0] >> 1) + lv1) << 1;
cur_lp[1] = ((ref_lp[1] >> 1) + lv2) << 1;
cur_lp[width_tbl[1]] = ((ref_lp[width_tbl[1]] >> 1) + lv1) << 1;
cur_lp[width_tbl[1]+1] = ((ref_lp[width_tbl[1]+1] >> 1) + lv2) << 1;
cur_lp[0] = le2me_32(((le2me_32(ref_lp[0]) >> 1) + lv1) << 1);
cur_lp[1] = le2me_32(((le2me_32(ref_lp[1]) >> 1) + lv2) << 1);
cur_lp[width_tbl[1]] = le2me_32(((le2me_32(ref_lp[width_tbl[1]]) >> 1) + lv1) << 1);
cur_lp[width_tbl[1]+1] = le2me_32(((le2me_32(ref_lp[width_tbl[1]+1]) >> 1) + lv2) << 1);
lp2++;
break;
@@ -897,7 +909,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
LV1_CHECK(buf1,rle_v3,lv1,lp2)
break;
default:
default:
return;
}
}
@@ -913,7 +925,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
break;
case 11: /********** CASE 11 **********/
if(ref_vectors == NULL)
if(ref_vectors == NULL)
return;
for( ; blks_height > 0; blks_height -= 8) {
@@ -925,18 +937,22 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
switch(correction_type_sp[lp2 & 0x01][k]) {
case 0:
cur_lp[0] = ((*ref_lp >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
cur_lp[width_tbl[1]] = ((ref_lp[width_tbl[1]] >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
cur_lp[0] = le2me_32(((le2me_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
cur_lp[width_tbl[1]] = le2me_32(((le2me_32(ref_lp[width_tbl[1]]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
lp2++;
break;
case 1:
lv1 = (unsigned short)(correction_lp[lp2 & 0x01][*buf1++]);
lv2 = (unsigned short)(correction_lp[lp2 & 0x01][k]);
((unsigned short *)cur_lp)[0] = ((((unsigned short *)ref_lp)[0] >> 1) + lv1) << 1;
((unsigned short *)cur_lp)[1] = ((((unsigned short *)ref_lp)[1] >> 1) + lv2) << 1;
((unsigned short *)cur_lp)[width_tbl[2]] = ((((unsigned short *)ref_lp)[width_tbl[2]] >> 1) + lv1) << 1;
((unsigned short *)cur_lp)[width_tbl[2]+1] = ((((unsigned short *)ref_lp)[width_tbl[2]+1] >> 1) + lv2) << 1;
res = (unsigned short)(((le2me_16(((unsigned short *)ref_lp)[0]) >> 1) + lv1) << 1);
((unsigned short *)cur_lp)[0] = le2me_16(res);
res = (unsigned short)(((le2me_16(((unsigned short *)ref_lp)[1]) >> 1) + lv2) << 1);
((unsigned short *)cur_lp)[1] = le2me_16(res);
res = (unsigned short)(((le2me_16(((unsigned short *)ref_lp)[width_tbl[2]]) >> 1) + lv1) << 1);
((unsigned short *)cur_lp)[width_tbl[2]] = le2me_16(res);
res = (unsigned short)(((le2me_16(((unsigned short *)ref_lp)[width_tbl[2]+1]) >> 1) + lv2) << 1);
((unsigned short *)cur_lp)[width_tbl[2]+1] = le2me_16(res);
lp2++;
break;
@@ -990,7 +1006,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
LV1_CHECK(buf1,rle_v3,lv1,lp2)
break;
default:
default:
return;
}
}
@@ -1004,12 +1020,12 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
}
break;
default:
default:
return;
}
}
if(strip < strip_tbl)
if(strip < strip_tbl)
return;
for( ; strip >= strip_tbl; strip--) {
@@ -1032,7 +1048,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s,
}
}
static int indeo3_decode_init(AVCodecContext *avctx)
static av_cold int indeo3_decode_init(AVCodecContext *avctx)
{
Indeo3DecodeContext *s = avctx->priv_data;
@@ -1040,7 +1056,6 @@ static int indeo3_decode_init(AVCodecContext *avctx)
s->width = avctx->width;
s->height = avctx->height;
avctx->pix_fmt = PIX_FMT_YUV410P;
avctx->has_b_frames = 0;
build_modpred(s);
iv_alloc_frames(s);
@@ -1050,7 +1065,7 @@ static int indeo3_decode_init(AVCodecContext *avctx)
static int indeo3_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
unsigned char *buf, int buf_size)
const unsigned char *buf, int buf_size)
{
Indeo3DecodeContext *s=avctx->priv_data;
unsigned char *src, *dest;
@@ -1075,6 +1090,8 @@ static int indeo3_decode_frame(AVCodecContext *avctx,
dest += s->frame.linesize[0];
}
if (!(s->avctx->flags & CODEC_FLAG_GRAY))
{
src = s->cur_frame->Ubuf;
dest = s->frame.data[1];
for (y = 0; y < s->height / 4; y++) {
@@ -1090,6 +1107,7 @@ static int indeo3_decode_frame(AVCodecContext *avctx,
src += s->cur_frame->uv_w;
dest += s->frame.linesize[2];
}
}
*data_size=sizeof(AVFrame);
*(AVFrame*)data= s->frame;
@@ -1097,7 +1115,7 @@ static int indeo3_decode_frame(AVCodecContext *avctx,
return buf_size;
}
static int indeo3_decode_end(AVCodecContext *avctx)
static av_cold int indeo3_decode_end(AVCodecContext *avctx)
{
Indeo3DecodeContext *s = avctx->priv_data;
@@ -1116,5 +1134,6 @@ AVCodec indeo3_decoder = {
indeo3_decode_end,
indeo3_decode_frame,
0,
NULL
NULL,
.long_name = NULL_IF_CONFIG_SMALL("Intel Indeo 3"),
};
File diff suppressed because it is too large Load Diff
@@ -2,20 +2,21 @@
* Interplay MVE Video Decoder
* Copyright (C) 2003 the ffmpeg project
*
* This library is free software; you can redistribute it and/or
* 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 of the License, or (at your option) any later version.
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* 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 this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
@@ -38,8 +39,8 @@
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "avcodec.h"
#include "bytestream.h"
#include "dsputil.h"
#define PALETTE_COUNT 256
@@ -47,7 +48,7 @@
/* debugging support */
#define DEBUG_INTERPLAY 0
#if DEBUG_INTERPLAY
#define debug_interplay printf
#define debug_interplay(x,...) av_log(NULL, AV_LOG_DEBUG, x, __VA_ARGS__)
#else
static inline void debug_interplay(const char *format, ...) { }
#endif
@@ -59,14 +60,14 @@ typedef struct IpvideoContext {
AVFrame second_last_frame;
AVFrame last_frame;
AVFrame current_frame;
unsigned char *decoding_map;
const unsigned char *decoding_map;
int decoding_map_size;
unsigned char *buf;
const unsigned char *buf;
int size;
unsigned char *stream_ptr;
unsigned char *stream_end;
const unsigned char *stream_ptr;
const unsigned char *stream_end;
unsigned char *pixel_ptr;
int line_inc;
int stride;
@@ -296,10 +297,8 @@ static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s)
/* need 2 more bytes from the stream */
CHECK_STREAM_PTR(2);
B[0] = *s->stream_ptr++;
B[1] = *s->stream_ptr++;
flags = (B[1] << 8) | B[0];
flags = bytestream_get_le16(&s->stream_ptr);
bitmask = 0x0001;
for (y = 0; y < 8; y += 2) {
for (x = 0; x < 8; x += 2, bitmask <<= 1) {
@@ -477,7 +476,6 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
{
int x, y;
unsigned char P[4];
unsigned char B[4];
unsigned int flags = 0;
int shifter = 0;
unsigned char pix;
@@ -495,8 +493,7 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
for (y = 0; y < 8; y++) {
/* get the next set of 8 2-bit flags */
flags = (s->stream_ptr[1] << 8) | s->stream_ptr[0];
s->stream_ptr += 2;
flags = bytestream_get_le16(&s->stream_ptr);
for (x = 0, shifter = 0; x < 8; x++, shifter += 2) {
*s->pixel_ptr++ = P[(flags >> shifter) & 0x03];
}
@@ -508,11 +505,7 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
/* 1 of 4 colors for each 2x2 block, need 4 more bytes */
CHECK_STREAM_PTR(4);
B[0] = *s->stream_ptr++;
B[1] = *s->stream_ptr++;
B[2] = *s->stream_ptr++;
B[3] = *s->stream_ptr++;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
flags = bytestream_get_le32(&s->stream_ptr);
shifter = 0;
for (y = 0; y < 8; y += 2) {
@@ -534,11 +527,7 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
for (y = 0; y < 8; y++) {
/* time to reload flags? */
if ((y == 0) || (y == 4)) {
B[0] = *s->stream_ptr++;
B[1] = *s->stream_ptr++;
B[2] = *s->stream_ptr++;
B[3] = *s->stream_ptr++;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
flags = bytestream_get_le32(&s->stream_ptr);
shifter = 0;
}
for (x = 0; x < 8; x += 2, shifter += 2) {
@@ -557,11 +546,7 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
for (y = 0; y < 8; y += 2) {
/* time to reload flags? */
if ((y == 0) || (y == 4)) {
B[0] = *s->stream_ptr++;
B[1] = *s->stream_ptr++;
B[2] = *s->stream_ptr++;
B[3] = *s->stream_ptr++;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
flags = bytestream_get_le32(&s->stream_ptr);
shifter = 0;
}
for (x = 0; x < 8; x++, shifter += 2) {
@@ -819,7 +804,6 @@ static void ipvideo_decode_opcodes(IpvideoContext *s)
s->line_inc = s->stride - 8;
s->upper_motion_limit_offset = (s->avctx->height - 8) * s->stride
+ s->avctx->width - 8;
s->dsp = s->dsp;
for (y = 0; y < (s->stride * s->avctx->height); y += s->stride * 8) {
for (x = y; x < y + s->avctx->width; x += 8) {
@@ -846,12 +830,12 @@ static void ipvideo_decode_opcodes(IpvideoContext *s)
}
if ((s->stream_ptr != s->stream_end) &&
(s->stream_ptr + 1 != s->stream_end)) {
av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %d bytes left over\n",
av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n",
s->stream_end - s->stream_ptr);
}
}
static int ipvideo_decode_init(AVCodecContext *avctx)
static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
{
IpvideoContext *s = avctx->priv_data;
@@ -863,7 +847,6 @@ static int ipvideo_decode_init(AVCodecContext *avctx)
}
avctx->pix_fmt = PIX_FMT_PAL8;
avctx->has_b_frames = 0;
dsputil_init(&s->dsp, avctx);
/* decoding map contains 4 bits of information per 8x8 block */
@@ -895,7 +878,7 @@ static int ipvideo_decode_init(AVCodecContext *avctx)
static int ipvideo_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size)
const uint8_t *buf, int buf_size)
{
IpvideoContext *s = avctx->priv_data;
AVPaletteControl *palette_control = avctx->palctrl;
@@ -936,7 +919,7 @@ static int ipvideo_decode_frame(AVCodecContext *avctx,
return buf_size;
}
static int ipvideo_decode_end(AVCodecContext *avctx)
static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
{
IpvideoContext *s = avctx->priv_data;
@@ -959,4 +942,5 @@ AVCodec interplay_video_decoder = {
ipvideo_decode_end,
ipvideo_decode_frame,
CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Interplay MVE Video"),
};
@@ -0,0 +1,764 @@
/*
* 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
*/
/**
* @file intrax8.c
* @brief IntraX8 (J-Frame) subdecoder, used by WMV2 and VC-1
*/
#include "avcodec.h"
#include "bitstream.h"
#include "mpegvideo.h"
#include "msmpeg4data.h"
#include "intrax8huf.h"
#include "intrax8.h"
#define MAX_TABLE_DEPTH(table_bits, max_bits) ((max_bits+table_bits-1)/table_bits)
#define DC_VLC_BITS 9
#define AC_VLC_BITS 9
#define OR_VLC_BITS 7
#define DC_VLC_MTD MAX_TABLE_DEPTH(DC_VLC_BITS, MAX_DC_VLC_BITS)
#define AC_VLC_MTD MAX_TABLE_DEPTH(AC_VLC_BITS, MAX_AC_VLC_BITS)
#define OR_VLC_MTD MAX_TABLE_DEPTH(OR_VLC_BITS, MAX_OR_VLC_BITS)
static VLC j_ac_vlc[2][2][8]; //[quant<13],[intra/inter],[select]
static VLC j_dc_vlc[2][8]; //[quant], [select]
static VLC j_orient_vlc[2][4]; //[quant], [select]
static void x8_vlc_init(){
int i;
#define init_ac_vlc(dst,src) \
init_vlc(&dst, \
AC_VLC_BITS,77, \
&src[1],4,2, \
&src[0],4,2, \
1)
//set ac tables
for(i=0;i<8;i++){
init_ac_vlc( j_ac_vlc[0][0][i], x8_ac0_highquant_table[i][0] );
init_ac_vlc( j_ac_vlc[0][1][i], x8_ac1_highquant_table[i][0] );
init_ac_vlc( j_ac_vlc[1][0][i], x8_ac0_lowquant_table [i][0] );
init_ac_vlc( j_ac_vlc[1][1][i], x8_ac1_lowquant_table [i][0] );
}
#undef init_ac_vlc
//set dc tables
#define init_dc_vlc(dst,src) \
init_vlc(&dst, \
DC_VLC_BITS,34, \
&src[1],4,2, \
&src[0],4,2, \
1);
for(i=0;i<8;i++){
init_dc_vlc( j_dc_vlc[0][i], x8_dc_highquant_table[i][0]);
init_dc_vlc( j_dc_vlc[1][i], x8_dc_lowquant_table [i][0]);
}
#undef init_dc_vlc
//set orient tables
#define init_or_vlc(dst,src) \
init_vlc(&dst, \
OR_VLC_BITS,12, \
&src[1],4,2, \
&src[0],4,2, \
1);
for(i=0;i<2;i++){
init_or_vlc( j_orient_vlc[0][i], x8_orient_highquant_table[i][0]);
}
for(i=0;i<4;i++){
init_or_vlc( j_orient_vlc[1][i], x8_orient_lowquant_table [i][0])
}
}
#undef init_or_vlc
static void x8_reset_vlc_tables(IntraX8Context * w){
memset(w->j_dc_vlc,0,sizeof(w->j_dc_vlc));
memset(w->j_ac_vlc,0,sizeof(w->j_ac_vlc));
w->j_orient_vlc=NULL;
}
static inline void x8_select_ac_table(IntraX8Context * const w , int mode){
MpegEncContext * const s= w->s;
int table_index;
assert(mode<4);
if( w->j_ac_vlc[mode] ) return;
table_index = get_bits(&s->gb, 3);
w->j_ac_vlc[mode] = &j_ac_vlc[w->quant<13][mode>>1][table_index];//2 modes use same tables
assert(w->j_ac_vlc[mode]);
}
static inline int x8_get_orient_vlc(IntraX8Context * w){
MpegEncContext * const s= w->s;
int table_index;
if(!w->j_orient_vlc ){
table_index = get_bits(&s->gb, 1+(w->quant<13) );
w->j_orient_vlc = &j_orient_vlc[w->quant<13][table_index];
}
assert(w->j_orient_vlc);
assert(w->j_orient_vlc->table);
return get_vlc2(&s->gb, w->j_orient_vlc->table, OR_VLC_BITS, OR_VLC_MTD);
}
#define extra_bits(eb) (eb)
#define extra_run (0xFF<<8)
#define extra_level (0x00<<8)
#define run_offset(r) ((r)<<16)
#define level_offset(l) ((l)<<24)
static const uint32_t ac_decode_table[]={
/*46*/ extra_bits(3) | extra_run | run_offset(16) | level_offset( 0),
/*47*/ extra_bits(3) | extra_run | run_offset(24) | level_offset( 0),
/*48*/ extra_bits(2) | extra_run | run_offset( 4) | level_offset( 1),
/*49*/ extra_bits(3) | extra_run | run_offset( 8) | level_offset( 1),
/*50*/ extra_bits(5) | extra_run | run_offset(32) | level_offset( 0),
/*51*/ extra_bits(4) | extra_run | run_offset(16) | level_offset( 1),
/*52*/ extra_bits(2) | extra_level | run_offset( 0) | level_offset( 4),
/*53*/ extra_bits(2) | extra_level | run_offset( 0) | level_offset( 8),
/*54*/ extra_bits(2) | extra_level | run_offset( 0) | level_offset(12),
/*55*/ extra_bits(3) | extra_level | run_offset( 0) | level_offset(16),
/*56*/ extra_bits(3) | extra_level | run_offset( 0) | level_offset(24),
/*57*/ extra_bits(2) | extra_level | run_offset( 1) | level_offset( 3),
/*58*/ extra_bits(3) | extra_level | run_offset( 1) | level_offset( 7),
/*59*/ extra_bits(2) | extra_run | run_offset(16) | level_offset( 0),
/*60*/ extra_bits(2) | extra_run | run_offset(20) | level_offset( 0),
/*61*/ extra_bits(2) | extra_run | run_offset(24) | level_offset( 0),
/*62*/ extra_bits(2) | extra_run | run_offset(28) | level_offset( 0),
/*63*/ extra_bits(4) | extra_run | run_offset(32) | level_offset( 0),
/*64*/ extra_bits(4) | extra_run | run_offset(48) | level_offset( 0),
/*65*/ extra_bits(2) | extra_run | run_offset( 4) | level_offset( 1),
/*66*/ extra_bits(3) | extra_run | run_offset( 8) | level_offset( 1),
/*67*/ extra_bits(4) | extra_run | run_offset(16) | level_offset( 1),
/*68*/ extra_bits(2) | extra_level | run_offset( 0) | level_offset( 4),
/*69*/ extra_bits(3) | extra_level | run_offset( 0) | level_offset( 8),
/*70*/ extra_bits(4) | extra_level | run_offset( 0) | level_offset(16),
/*71*/ extra_bits(2) | extra_level | run_offset( 1) | level_offset( 3),
/*72*/ extra_bits(3) | extra_level | run_offset( 1) | level_offset( 7),
};
//extra_bits = 3bits; extra_run/level = 1 bit; run_offset = 6bits; level_offset = 5 bits;
#undef extra_bits
#undef extra_run
#undef extra_level
#undef run_offset
#undef level_offset
static void x8_get_ac_rlf(IntraX8Context * const w, const int mode,
int * const run, int * const level, int * const final){
MpegEncContext * const s= w->s;
int i,e;
// x8_select_ac_table(w,mode);
i = get_vlc2(&s->gb, w->j_ac_vlc[mode]->table, AC_VLC_BITS, AC_VLC_MTD);
if(i<46){ //[0-45]
int t,l;
if(i<0){
(*level)=(*final)=//prevent 'may be used unilitialized'
(*run)=64;//this would cause error exit in the ac loop
return;
}
(*final) = t = (i>22);
i-=23*t;
/*
i== 0-15 r=0-15 l=0 ;r=i& %01111
i==16-19 r=0-3 l=1 ;r=i& %00011
i==20-21 r=0-1 l=2 ;r=i& %00001
i==22 r=0 l=3 ;r=i& %00000
l=lut_l[i/2]={0,0,0,0,0,0,0,0,1,1,2,3}[i>>1];// 11 10'01 01'00 00'00 00'00 00'00 00 => 0xE50000
t=lut_mask[l]={0x0f,0x03,0x01,0x00}[l]; as i<256 the higher bits do not matter */
l=(0xE50000>>(i&(0x1E)))&3;/*0x1E or (~1) or ((i>>1)<<1)*/
t=(0x01030F>>(l<<3));
(*run) = i&t;
(*level) = l;
}else if(i<73){//[46-72]
uint32_t sm;
uint32_t mask;
i-=46;
sm=ac_decode_table[i];
e=get_bits(&s->gb,sm&0xF);sm>>=8;//3bits
mask=sm&0xff;sm>>=8; //1bit
(*run) =(sm&0xff) + (e&( mask));//6bits
(*level)=(sm>>8) + (e&(~mask));//5bits
(*final)=i>(58-46);
}else if(i<75){//[73-74]
static const uint8_t crazy_mix_runlevel[32]={
0x22,0x32,0x33,0x53,0x23,0x42,0x43,0x63,
0x24,0x52,0x34,0x73,0x25,0x62,0x44,0x83,
0x26,0x72,0x35,0x54,0x27,0x82,0x45,0x64,
0x28,0x92,0x36,0x74,0x29,0xa2,0x46,0x84};
(*final)=!(i&1);
e=get_bits(&s->gb,5);//get the extra bits
(*run) =crazy_mix_runlevel[e]>>4;
(*level)=crazy_mix_runlevel[e]&0x0F;
}else{
(*level)=get_bits( &s->gb, 7-3*(i&1));
(*run) =get_bits( &s->gb, 6);
(*final)=get_bits1(&s->gb);
}
return;
}
//static const uint8_t dc_extra_sbits[] ={0, 1,1, 1,1, 2,2, 3,3, 4,4, 5,5, 6,6, 7,7 };
static const uint8_t dc_index_offset[] ={ 0, 1,2, 3,4, 5,7, 9,13, 17,25, 33,49, 65,97, 129,193};
static int x8_get_dc_rlf(IntraX8Context * const w,int const mode, int * const level, int * const final){
MpegEncContext * const s= w->s;
int i,e,c;
assert(mode<3);
if( !w->j_dc_vlc[mode] ) {
int table_index;
table_index = get_bits(&s->gb, 3);
//4 modes, same table
w->j_dc_vlc[mode]= &j_dc_vlc[w->quant<13][table_index];
}
assert(w->j_dc_vlc);
assert(w->j_dc_vlc[mode]->table);
i=get_vlc2(&s->gb, w->j_dc_vlc[mode]->table, DC_VLC_BITS, DC_VLC_MTD);
/*(i>=17) {i-=17;final=1;}*/
c= i>16;
(*final)=c;
i-=17*c;
if(i<=0){
(*level)=0;
return -i;
}
c=(i+1)>>1;//hackish way to calculate dc_extra_sbits[]
c-=c>1;
e=get_bits(&s->gb,c);//get the extra bits
i=dc_index_offset[i]+(e>>1);
e= -(e & 1);//0,0xffffff
(*level)= (i ^ e) - e;// (i^0)-0 , (i^0xff)-(-1)
return 0;
}
//end of huffman
static int x8_setup_spatial_predictor(IntraX8Context * const w, const int chroma){
MpegEncContext * const s= w->s;
int range;
int sum;
int quant;
s->dsp.x8_setup_spatial_compensation(s->dest[chroma], s->edge_emu_buffer,
s->current_picture.linesize[chroma>0],
&range, &sum, w->edges);
if(chroma){
w->orient=w->chroma_orient;
quant=w->quant_dc_chroma;
}else{
quant=w->quant;
}
w->flat_dc=0;
if(range < quant || range < 3){
w->orient=0;
if(range < 3){//yep you read right, a +-1 idct error may break decoding!
w->flat_dc=1;
sum+=9;
w->predicted_dc = (sum*6899)>>17;//((1<<17)+9)/(8+8+1+2)=6899
}
}
if(chroma)
return 0;
assert(w->orient < 3);
if(range < 2*w->quant){
if( (w->edges&3) == 0){
if(w->orient==1) w->orient=11;
if(w->orient==2) w->orient=10;
}else{
w->orient=0;
}
w->raw_orient=0;
}else{
static const uint8_t prediction_table[3][12]={
{0,8,4, 10,11, 2,6,9,1,3,5,7},
{4,0,8, 11,10, 3,5,2,6,9,1,7},
{8,0,4, 10,11, 1,7,2,6,9,3,5}
};
w->raw_orient=x8_get_orient_vlc(w);
if(w->raw_orient<0) return -1;
assert(w->raw_orient < 12 );
assert(w->orient<3);
w->orient=prediction_table[w->orient][w->raw_orient];
}
return 0;
}
static void x8_update_predictions(IntraX8Context * const w, const int orient, const int est_run ){
MpegEncContext * const s= w->s;
w->prediction_table[s->mb_x*2+(s->mb_y&1)] = (est_run<<2) + 1*(orient==4) + 2*(orient==8);
/*
y=2n+0 ->//0 2 4
y=2n+1 ->//1 3 5
*/
}
static void x8_get_prediction_chroma(IntraX8Context * const w){
MpegEncContext * const s= w->s;
w->edges = 1*( !(s->mb_x>>1) );
w->edges|= 2*( !(s->mb_y>>1) );
w->edges|= 4*( s->mb_x >= (2*s->mb_width-1) );//mb_x for chroma would always be odd
w->raw_orient=0;
if(w->edges&3){//lut_co[8]={inv,4,8,8, inv,4,8,8}<- =>{1,1,0,0;1,1,0,0} => 0xCC
w->chroma_orient=4<<((0xCC>>w->edges)&1);
return;
}
w->chroma_orient = (w->prediction_table[2*s->mb_x-2] & 0x03)<<2;//block[x-1][y|1-1)]
}
static void x8_get_prediction(IntraX8Context * const w){
MpegEncContext * const s= w->s;
int a,b,c,i;
w->edges = 1*( !s->mb_x );
w->edges|= 2*( !s->mb_y );
w->edges|= 4*( s->mb_x >= (2*s->mb_width-1) );
switch(w->edges&3){
case 0:
break;
case 1:
//take the one from the above block[0][y-1]
w->est_run = w->prediction_table[!(s->mb_y&1)]>>2;
w->orient = 1;
return;
case 2:
//take the one from the previous block[x-1][0]
w->est_run = w->prediction_table[2*s->mb_x-2]>>2;
w->orient = 2;
return;
case 3:
w->est_run = 16;
w->orient = 0;
return;
}
//no edge cases
b= w->prediction_table[2*s->mb_x + !(s->mb_y&1) ];//block[x ][y-1]
a= w->prediction_table[2*s->mb_x-2 + (s->mb_y&1) ];//block[x-1][y ]
c= w->prediction_table[2*s->mb_x-2 + !(s->mb_y&1) ];//block[x-1][y-1]
w->est_run = FFMIN(b,a);
/* This condition has nothing to do with w->edges, even if it looks
similar it would trigger if e.g. x=3;y=2;
I guess somebody wrote something wrong and it became standard. */
if( (s->mb_x & s->mb_y) != 0 ) w->est_run=FFMIN(c,w->est_run);
w->est_run>>=2;
a&=3;
b&=3;
c&=3;
i=( 0xFFEAF4C4>>(2*b+8*a) )&3;
if(i!=3) w->orient=i;
else w->orient=( 0xFFEAD8>>(2*c+8*(w->quant>12)) )&3;
/*
lut1[b][a]={
->{0, 1, 0, pad},
{0, 1, X, pad},
{2, 2, 2, pad}}
pad 2 2 2; pad X 1 0; pad 0 1 0 <-
-> 11 10 '10 10 '11 11'01 00 '11 00'01 00=>0xEAF4C4
lut2[q>12][c]={
->{0,2,1,pad},
{2,2,2,pad}}
pad 2 2 2; pad 1 2 0 <-
-> 11 10'10 10 '11 01'10 00=>0xEAD8
*/
}
static void x8_ac_compensation(IntraX8Context * const w, int const direction, int const dc_level){
MpegEncContext * const s= w->s;
int t;
#define B(x,y) s->block[0][s->dsp.idct_permutation[(x)+(y)*8]]
#define T(x) ((x) * dc_level + 0x8000) >> 16;
switch(direction){
case 0:
t = T(3811);//h
B(1,0) -= t;
B(0,1) -= t;
t = T(487);//e
B(2,0) -= t;
B(0,2) -= t;
t = T(506);//f
B(3,0) -= t;
B(0,3) -= t;
t = T(135);//c
B(4,0) -= t;
B(0,4) -= t;
B(2,1) += t;
B(1,2) += t;
B(3,1) += t;
B(1,3) += t;
t = T(173);//d
B(5,0) -= t;
B(0,5) -= t;
t = T(61);//b
B(6,0) -= t;
B(0,6) -= t;
B(5,1) += t;
B(1,5) += t;
t = T(42); //a
B(7,0) -= t;
B(0,7) -= t;
B(4,1) += t;
B(1,4) += t;
B(4,4) += t;
t = T(1084);//g
B(1,1) += t;
s->block_last_index[0] = FFMAX(s->block_last_index[0], 7*8);
break;
case 1:
B(0,1) -= T(6269);
B(0,3) -= T( 708);
B(0,5) -= T( 172);
B(0,7) -= T( 73);
s->block_last_index[0] = FFMAX(s->block_last_index[0], 7*8);
break;
case 2:
B(1,0) -= T(6269);
B(3,0) -= T( 708);
B(5,0) -= T( 172);
B(7,0) -= T( 73);
s->block_last_index[0] = FFMAX(s->block_last_index[0], 7);
break;
}
#undef B
#undef T
}
static void dsp_x8_put_solidcolor(uint8_t const pix, uint8_t * dst, int const linesize){
int k;
for(k=0;k<8;k++){
memset(dst,pix,8);
dst+=linesize;
}
}
static const int16_t quant_table[64] = {
256, 256, 256, 256, 256, 256, 259, 262,
265, 269, 272, 275, 278, 282, 285, 288,
292, 295, 299, 303, 306, 310, 314, 317,
321, 325, 329, 333, 337, 341, 345, 349,
353, 358, 362, 366, 371, 375, 379, 384,
389, 393, 398, 403, 408, 413, 417, 422,
428, 433, 438, 443, 448, 454, 459, 465,
470, 476, 482, 488, 493, 499, 505, 511
};
static int x8_decode_intra_mb(IntraX8Context* const w, const int chroma){
MpegEncContext * const s= w->s;
uint8_t * scantable;
int final,run,level;
int ac_mode,dc_mode,est_run,dc_level;
int pos,n;
int zeros_only;
int use_quant_matrix;
int sign;
assert(w->orient<12);
memset(s->block[0],0x00,64*sizeof(DCTELEM));
if(chroma){
dc_mode=2;
}else{
dc_mode=!!w->est_run;//0,1
}
if(x8_get_dc_rlf(w, dc_mode, &dc_level, &final)) return -1;
n=0;
zeros_only=0;
if(!final){//decode ac
use_quant_matrix=w->use_quant_matrix;
if(chroma){
ac_mode = 1;
est_run = 64;//not used
}else{
if (w->raw_orient < 3){
use_quant_matrix = 0;
}
if(w->raw_orient > 4){
ac_mode = 0;
est_run = 64;
}else{
if(w->est_run > 1){
ac_mode = 2;
est_run=w->est_run;
}else{
ac_mode = 3;
est_run = 64;
}
}
}
x8_select_ac_table(w,ac_mode);
/*scantable_selector[12]={0,2,0,1,1,1,0,2,2,0,1,2};<-
-> 10'01' 00'10' 10'00' 01'01' 01'00' 10'00 =>0x928548 */
scantable = w->scantable[ (0x928548>>(2*w->orient))&3 ].permutated;
pos=0;
do {
n++;
if( n >= est_run ){
ac_mode=3;
x8_select_ac_table(w,3);
}
x8_get_ac_rlf(w,ac_mode,&run,&level,&final);
pos+=run+1;
if(pos>63){
//this also handles vlc error in x8_get_ac_rlf
return -1;
}
level= (level+1) * w->dquant;
level+= w->qsum;
sign = - get_bits1(&s->gb);
level = (level ^ sign) - sign;
if(use_quant_matrix){
level = (level*quant_table[pos])>>8;
}
s->block[0][ scantable[pos] ]=level;
}while(!final);
s->block_last_index[0]=pos;
}else{//DC only
s->block_last_index[0]=0;
if(w->flat_dc && ((unsigned)(dc_level+1)) < 3){//[-1;1]
int32_t divide_quant= !chroma ? w->divide_quant_dc_luma:
w->divide_quant_dc_chroma;
int32_t dc_quant = !chroma ? w->quant:
w->quant_dc_chroma;
//original intent dc_level+=predicted_dc/quant; but it got lost somewhere in the rounding
dc_level+= (w->predicted_dc*divide_quant + (1<<12) )>>13;
dsp_x8_put_solidcolor( av_clip_uint8((dc_level*dc_quant+4)>>3),
s->dest[chroma], s->current_picture.linesize[!!chroma]);
goto block_placed;
}
zeros_only = (dc_level == 0);
}
if(!chroma){
s->block[0][0] = dc_level*w->quant;
}else{
s->block[0][0] = dc_level*w->quant_dc_chroma;
}
//there is !zero_only check in the original, but dc_level check is enough
if( (unsigned int)(dc_level+1) >= 3 && (w->edges&3) != 3 ){
int direction;
/*ac_comp_direction[orient] = { 0, 3, 3, 1, 1, 0, 0, 0, 2, 2, 2, 1 };<-
-> 01'10' 10'10' 00'00' 00'01' 01'11' 11'00 =>0x6A017C */
direction= (0x6A017C>>(w->orient*2))&3;
if (direction != 3){
x8_ac_compensation(w, direction, s->block[0][0]);//modify block_last[]
}
}
if(w->flat_dc){
dsp_x8_put_solidcolor(w->predicted_dc, s->dest[chroma], s->current_picture.linesize[!!chroma]);
}else{
s->dsp.x8_spatial_compensation[w->orient]( s->edge_emu_buffer,
s->dest[chroma],
s->current_picture.linesize[!!chroma] );
}
if(!zeros_only)
s->dsp.idct_add ( s->dest[chroma],
s->current_picture.linesize[!!chroma],
s->block[0] );
block_placed:
if(!chroma){
x8_update_predictions(w,w->orient,n);
}
if(s->loop_filter){
uint8_t* ptr = s->dest[chroma];
int linesize = s->current_picture.linesize[!!chroma];
if(!( (w->edges&2) || ( zeros_only && (w->orient|4)==4 ) )){
s->dsp.x8_h_loop_filter(ptr, linesize, w->quant);
}
if(!( (w->edges&1) || ( zeros_only && (w->orient|8)==8 ) )){
s->dsp.x8_v_loop_filter(ptr, linesize, w->quant);
}
}
return 0;
}
static void x8_init_block_index(MpegEncContext *s){ //FIXME maybe merge with ff_*
//not s->linesize as this would be wrong for field pics
//not that IntraX8 has interlacing support ;)
const int linesize = s->current_picture.linesize[0];
const int uvlinesize= s->current_picture.linesize[1];
s->dest[0] = s->current_picture.data[0];
s->dest[1] = s->current_picture.data[1];
s->dest[2] = s->current_picture.data[2];
s->dest[0] += s->mb_y * linesize << 3;
s->dest[1] += ( s->mb_y&(~1) ) * uvlinesize << 2;//chroma blocks are on add rows
s->dest[2] += ( s->mb_y&(~1) ) * uvlinesize << 2;
}
/**
* Initialize IntraX8 frame decoder.
* Requires valid MpegEncContext with valid s->mb_width before calling.
* @param w pointer to IntraX8Context
* @param s pointer to MpegEncContext of the parent codec
*/
void ff_intrax8_common_init(IntraX8Context * w, MpegEncContext * const s){
w->s=s;
x8_vlc_init();
assert(s->mb_width>0);
w->prediction_table=av_mallocz(s->mb_width*2*2);//two rows, 2 blocks per cannon mb
ff_init_scantable(s->dsp.idct_permutation, &w->scantable[0], wmv1_scantable[0]);
ff_init_scantable(s->dsp.idct_permutation, &w->scantable[1], wmv1_scantable[2]);
ff_init_scantable(s->dsp.idct_permutation, &w->scantable[2], wmv1_scantable[3]);
}
/**
* Destroy IntraX8 frame structure.
* @param w pointer to IntraX8Context
*/
void ff_intrax8_common_end(IntraX8Context * w)
{
av_freep(&w->prediction_table);
}
/**
* Decode single IntraX8 frame.
* The parent codec must fill s->loopfilter and s->gb (bitstream).
* The parent codec must call MPV_frame_start(), ff_er_frame_start() before calling this function.
* The parent codec must call ff_er_frame_end(), MPV_frame_end() after calling this function.
* This function does not use MPV_decode_mb().
* lowres decoding is theoretically impossible.
* @param w pointer to IntraX8Context
* @param dquant doubled quantizer, it would be odd in case of VC-1 halfpq==1.
* @param quant_offset offset away from zero
*/
//FIXME extern uint8_t wmv3_dc_scale_table[32];
int ff_intrax8_decode_picture(IntraX8Context * const w, int dquant, int quant_offset){
MpegEncContext * const s= w->s;
int mb_xy;
assert(s);
w->use_quant_matrix = get_bits1(&s->gb);
w->dquant = dquant;
w->quant = dquant >> 1;
w->qsum = quant_offset;
w->divide_quant_dc_luma = ((1<<16) + (w->quant>>1)) / w->quant;
if(w->quant < 5){
w->quant_dc_chroma = w->quant;
w->divide_quant_dc_chroma = w->divide_quant_dc_luma;
}else{
w->quant_dc_chroma = w->quant+((w->quant+3)>>3);
w->divide_quant_dc_chroma = ((1<<16) + (w->quant_dc_chroma>>1)) / w->quant_dc_chroma;
}
x8_reset_vlc_tables(w);
s->resync_mb_x=0;
s->resync_mb_y=0;
for(s->mb_y=0; s->mb_y < s->mb_height*2; s->mb_y++){
x8_init_block_index(s);
mb_xy=(s->mb_y>>1)*s->mb_stride;
for(s->mb_x=0; s->mb_x < s->mb_width*2; s->mb_x++){
x8_get_prediction(w);
if(x8_setup_spatial_predictor(w,0)) goto error;
if(x8_decode_intra_mb(w,0)) goto error;
if( s->mb_x & s->mb_y & 1 ){
x8_get_prediction_chroma(w);
/*when setting up chroma, no vlc is read,
so no error condition can be reached*/
x8_setup_spatial_predictor(w,1);
if(x8_decode_intra_mb(w,1)) goto error;
x8_setup_spatial_predictor(w,2);
if(x8_decode_intra_mb(w,2)) goto error;
s->dest[1]+= 8;
s->dest[2]+= 8;
/*emulate MB info in the relevant tables*/
s->mbskip_table [mb_xy]=0;
s->mbintra_table[mb_xy]=1;
s->current_picture.qscale_table[mb_xy]=w->quant;
mb_xy++;
}
s->dest[0]+= 8;
}
if(s->mb_y&1){
ff_draw_horiz_band(s, (s->mb_y-1)*8, 16);
}
}
error:
ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y,
(s->mb_x>>1)-1, (s->mb_y>>1)-1,
(AC_END|DC_END|MV_END) );
return 0;
}
@@ -0,0 +1,57 @@
/*
* 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
*/
#ifndef FFMPEG_INTRAX8_H
#define FFMPEG_INTRAX8_H
#include "bitstream.h"
#include "mpegvideo.h"
typedef struct{
VLC * j_ac_vlc[4];//they point to the static j_mb_vlc
VLC * j_orient_vlc;
VLC * j_dc_vlc[3];
int use_quant_matrix;
//set by ff_intrax8_common_init
uint8_t * prediction_table;//2*(mb_w*2)
ScanTable scantable[3];
//set by the caller codec
MpegEncContext * s;
int quant;
int dquant;
int qsum;
//calculated per frame
int quant_dc_chroma;
int divide_quant_dc_luma;
int divide_quant_dc_chroma;
//changed per block
int edges;
int flat_dc;
int predicted_dc;
int raw_orient;
int chroma_orient;
int orient;
int est_run;
} IntraX8Context;
void ff_intrax8_common_init(IntraX8Context * w, MpegEncContext * const s);
void ff_intrax8_common_end(IntraX8Context * w);
int ff_intrax8_decode_picture(IntraX8Context * w, int quant, int halfpq);
#endif /* FFMPEG_INTRAX8_H */
@@ -0,0 +1,432 @@
/*
* 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
*/
/**
* @file intrax8dsp.c
*@brief IntraX8 frame subdecoder image manipulation routines
*/
#include "dsputil.h"
/*
area positions, #3 is 1 pixel only, other are 8 pixels
|66666666|
3|44444444|55555555|
- -+--------+--------+
1 2|XXXXXXXX|
1 2|XXXXXXXX|
1 2|XXXXXXXX|
1 2|XXXXXXXX|
1 2|XXXXXXXX|
1 2|XXXXXXXX|
1 2|XXXXXXXX|
1 2|XXXXXXXX|
^-start
*/
#define area1 (0)
#define area2 (8)
#define area3 (8+8)
#define area4 (8+8+1)
#define area5 (8+8+1+8)
#define area6 (8+8+1+16)
/**
Collect statistics and prepare the edge pixels required by the other spatial compensation functions.
* @param src pointer to the beginning of the processed block
* @param dst pointer to emu_edge, edge pixels are stored the way other compensation routines do.
* @param linesize byte offset between 2 vertical pixels in the source image
* @param range pointer to the variable where the edge pixel range is to be stored (max-min values)
* @param psum pointer to the variable where the edge pixel sum is to be stored
* @param edges Informs this routine that the block is on an image border, so it has to interpolate the missing edge pixels.
and some of the edge pixels should be interpolated, the flag has the following meaning:
1 - mb_x==0 - first block in the row, interpolate area #1,#2,#3;
2 - mb_y==0 - first row, interpolate area #3,#4,#5,#6;
note: 1|2 - mb_x==mb_y==0 - first block, use 0x80 value for all areas;
4 - mb_x>= (mb_width-1) last block in the row, interpolate area #5;
*/
static void x8_setup_spatial_compensation(uint8_t *src, uint8_t *dst, int linesize,
int * range, int * psum, int edges){
uint8_t * ptr;
int sum;
int i;
int min_pix,max_pix;
uint8_t c;
if((edges&3)==3){
*psum=0x80*(8+1+8+2);
*range=0;
memset(dst,0x80,16+1+16+8);
//this triggers flat_dc for sure.
//flat_dc avoids all (other) prediction modes, but requires dc_level decoding.
return;
}
min_pix=256;
max_pix=-1;
sum=0;
if(!(edges&1)){//(mb_x!=0)//there is previous block on this row
ptr=src-1;//left column, area 2
for(i=7;i>=0;i--){
c=*(ptr-1);//area1, same mb as area2, no need to check
dst[area1+i]=c;
c=*(ptr);
sum+=c;
min_pix=FFMIN(min_pix,c);
max_pix=FFMAX(max_pix,c);
dst[area2+i]=c;
ptr+=linesize;
}
}
if(!(edges&2)){ //(mb_y!=0)//there is row above
ptr=src-linesize;//top line
for(i=0;i<8;i++){
c=*(ptr+i);
sum+=c;
min_pix=FFMIN(min_pix, c);
max_pix=FFMAX(max_pix, c);
}
if(edges&4){//last block on the row?
memset(dst+area5,c,8);//set with last pixel fr
memcpy(dst+area4, ptr, 8);
}else{
memcpy(dst+area4, ptr, 16);//both area4 and 5
}
memcpy(dst+area6, ptr-linesize, 8);//area6 always present in the above block
}
//now calculate the stuff we need
if(edges&3){//mb_x==0 || mb_y==0){
int avg=(sum+4)>>3;
if(edges&1){ //(mb_x==0) {//implies mb_y!=0
memset(dst+area1,avg,8+8+1);//areas 1,2 and 3 are averaged
}else{//implies y==0 x!=0
memset(dst+area3,avg, 1+16+8);//areas 3, 4,5,6
}
sum+=avg*9;
}else{
uint8_t c=*(src-1-linesize);//the edge pixel, in the top line and left column
dst[area3]=c;
sum+=c;
//edge pixel is not part of min/max
}
(*range) = max_pix - min_pix;
sum += *(dst+area5) + *(dst+area5+1);
*psum = sum;
}
static const uint16_t zero_prediction_weights[64*2] = {
640, 640, 669, 480, 708, 354, 748, 257, 792, 198, 760, 143, 808, 101, 772, 72,
480, 669, 537, 537, 598, 416, 661, 316, 719, 250, 707, 185, 768, 134, 745, 97,
354, 708, 416, 598, 488, 488, 564, 388, 634, 317, 642, 241, 716, 179, 706, 132,
257, 748, 316, 661, 388, 564, 469, 469, 543, 395, 571, 311, 655, 238, 660, 180,
198, 792, 250, 719, 317, 634, 395, 543, 469, 469, 507, 380, 597, 299, 616, 231,
161, 855, 206, 788, 266, 710, 340, 623, 411, 548, 455, 455, 548, 366, 576, 288,
122, 972, 159, 914, 211, 842, 276, 758, 341, 682, 389, 584, 483, 483, 520, 390,
110, 1172, 144, 1107, 193, 1028, 254, 932, 317, 846, 366, 731, 458, 611, 499, 499
};
static void spatial_compensation_0(uint8_t *src , uint8_t *dst, int linesize){
int i,j;
int x,y;
unsigned int p;//power divided by 2
int a;
uint16_t left_sum[2][8];
uint16_t top_sum[2][8];
memset(left_sum,0,2*8*sizeof(uint16_t));
memset( top_sum,0,2*8*sizeof(uint16_t));
for(i=0;i<8;i++){
a=src[area2+7-i]<<4;
for(j=0;j<8;j++){
p=abs(i-j);
left_sum[p&1][j]+= a>>(p>>1);
}
}
for(i=0;i<8;i++){
a=src[area4+i]<<4;
for(j=0;j<8;j++){
p=abs(i-j);
top_sum[p&1][j]+= a>>(p>>1);
}
}
for(;i<10;i++){
a=src[area4+i]<<4;
for(j=5;j<8;j++){
p=abs(i-j);
top_sum[p&1][j]+= a>>(p>>1);
}
}
for(;i<12;i++){
a=src[area4+i]<<4;
for(j=7;j<8;j++){
p=abs(i-j);
top_sum[p&1][j]+= a>>(p>>1);
}
}
for(i=0;i<8;i++){
top_sum [0][i]+=(top_sum [1][i]*181 + 128 )>>8;//181 is sqrt(2)/2
left_sum[0][i]+=(left_sum[1][i]*181 + 128 )>>8;
}
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x] = (
(uint32_t)top_sum [0][x]*zero_prediction_weights[y*16+x*2+0] +
(uint32_t)left_sum[0][y]*zero_prediction_weights[y*16+x*2+1] +
0x8000
)>>16;
}
dst+=linesize;
}
}
static void spatial_compensation_1(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=src[area4 + FFMIN(2*y+x+2, 15) ];
}
dst+=linesize;
}
}
static void spatial_compensation_2(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=src[area4 +1+y+x];
}
dst+=linesize;
}
}
static void spatial_compensation_3(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=src[area4 +((y+1)>>1)+x];
}
dst+=linesize;
}
}
static void spatial_compensation_4(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=( src[area4+x] + src[area6+x] + 1 )>>1;
}
dst+=linesize;
}
}
static void spatial_compensation_5(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
if(2*x-y<0){
dst[x]=src[area2+9+2*x-y];
}else{
dst[x]=src[area4 +x-((y+1)>>1)];
}
}
dst+=linesize;
}
}
static void spatial_compensation_6(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=src[area3+x-y];
}
dst+=linesize;
}
}
static void spatial_compensation_7(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
if(x-2*y>0){
dst[x]=( src[area3-1+x-2*y] + src[area3+x-2*y] + 1)>>1;
}else{
dst[x]=src[area2+8-y +(x>>1)];
}
}
dst+=linesize;
}
}
static void spatial_compensation_8(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=( src[area1+7-y] + src[area2+7-y] + 1 )>>1;
}
dst+=linesize;
}
}
static void spatial_compensation_9(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=src[area2+6-FFMIN(x+y,6)];
}
dst+=linesize;
}
}
static void spatial_compensation_10(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=(src[area2+7-y]*(8-x)+src[area4+x]*x+4)>>3;
}
dst+=linesize;
}
}
static void spatial_compensation_11(uint8_t *src , uint8_t *dst, int linesize){
int x,y;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
dst[x]=(src[area2+7-y]*y+src[area4+x]*(8-y)+4)>>3;
}
dst+=linesize;
}
}
static void x8_loop_filter(uint8_t * ptr, const int a_stride, const int b_stride, int quant){
int i,t;
int p0,p1,p2,p3,p4,p5,p6,p7,p8,p9;
int ql=(quant+10)>>3;
for(i=0; i<8; i++,ptr+=b_stride){
p0=ptr[-5*a_stride];
p1=ptr[-4*a_stride];
p2=ptr[-3*a_stride];
p3=ptr[-2*a_stride];
p4=ptr[-1*a_stride];
p5=ptr[ 0 ];
p6=ptr[ 1*a_stride];
p7=ptr[ 2*a_stride];
p8=ptr[ 3*a_stride];
p9=ptr[ 4*a_stride];
t=
(FFABS(p1-p2) <= ql) +
(FFABS(p2-p3) <= ql) +
(FFABS(p3-p4) <= ql) +
(FFABS(p4-p5) <= ql);
if(t>0){//You need at least 1 to be able to reach a total score of 6.
t+=
(FFABS(p5-p6) <= ql) +
(FFABS(p6-p7) <= ql) +
(FFABS(p7-p8) <= ql) +
(FFABS(p8-p9) <= ql) +
(FFABS(p0-p1) <= ql);
if(t>=6){
int min,max;
min=max=p1;
min=FFMIN(min,p3); max=FFMAX(max,p3);
min=FFMIN(min,p5); max=FFMAX(max,p5);
min=FFMIN(min,p8); max=FFMAX(max,p8);
if(max-min<2*quant){//early stop
min=FFMIN(min,p2); max=FFMAX(max,p2);
min=FFMIN(min,p4); max=FFMAX(max,p4);
min=FFMIN(min,p6); max=FFMAX(max,p6);
min=FFMIN(min,p7); max=FFMAX(max,p7);
if(max-min<2*quant){
ptr[-2*a_stride]=(4*p2 + 3*p3 + 1*p7 + 4)>>3;
ptr[-1*a_stride]=(3*p2 + 3*p4 + 2*p7 + 4)>>3;
ptr[ 0 ]=(2*p2 + 3*p5 + 3*p7 + 4)>>3;
ptr[ 1*a_stride]=(1*p2 + 3*p6 + 4*p7 + 4)>>3;
continue;
};
}
}
}
{
int x,x0,x1,x2;
int m;
x0 = (2*p3 - 5*p4 + 5*p5 - 2*p6 + 4)>>3;
if(FFABS(x0) < quant){
x1=(2*p1 - 5*p2 + 5*p3 - 2*p4 + 4)>>3;
x2=(2*p5 - 5*p6 + 5*p7 - 2*p8 + 4)>>3;
x=FFABS(x0) - FFMIN( FFABS(x1), FFABS(x2) );
m=p4-p5;
if( x > 0 && (m^x0) <0){
int32_t sign;
sign=m>>31;
m=(m^sign)-sign;//abs(m)
m>>=1;
x=(5*x)>>3;
if(x>m) x=m;
x=(x^sign)-sign;
ptr[-1*a_stride] -= x;
ptr[ 0] += x;
}
}
}
}
}
static void x8_h_loop_filter(uint8_t *src, int stride, int qscale){
x8_loop_filter(src, stride, 1, qscale);
}
static void x8_v_loop_filter(uint8_t *src, int stride, int qscale){
x8_loop_filter(src, 1, stride, qscale);
}
void ff_intrax8dsp_init(DSPContext* dsp, AVCodecContext *avctx) {
dsp->x8_h_loop_filter=x8_h_loop_filter;
dsp->x8_v_loop_filter=x8_v_loop_filter;
dsp->x8_setup_spatial_compensation=x8_setup_spatial_compensation;
dsp->x8_spatial_compensation[0]=spatial_compensation_0;
dsp->x8_spatial_compensation[1]=spatial_compensation_1;
dsp->x8_spatial_compensation[2]=spatial_compensation_2;
dsp->x8_spatial_compensation[3]=spatial_compensation_3;
dsp->x8_spatial_compensation[4]=spatial_compensation_4;
dsp->x8_spatial_compensation[5]=spatial_compensation_5;
dsp->x8_spatial_compensation[6]=spatial_compensation_6;
dsp->x8_spatial_compensation[7]=spatial_compensation_7;
dsp->x8_spatial_compensation[8]=spatial_compensation_8;
dsp->x8_spatial_compensation[9]=spatial_compensation_9;
dsp->x8_spatial_compensation[10]=spatial_compensation_10;
dsp->x8_spatial_compensation[11]=spatial_compensation_11;
}
@@ -0,0 +1,918 @@
/*
* 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
*/
#ifndef FFMPEG_INTRAX8HUF_H
#define FFMPEG_INTRAX8HUF_H
#include <inttypes.h>
static const uint16_t x8_orient_lowquant_table[4][12][2]={
{//0
{0x0000, 1}, {0x0004, 3}, {0x0005, 3}, {0x000C, 4},
{0x000D, 4}, {0x0038, 6}, {0x001D, 5}, {0x0039, 6},
{0x003C, 6}, {0x003D, 6}, {0x003E, 6}, {0x003F, 6},
},{//1
{0x0000, 5}, {0x0001, 5}, {0x0002, 5}, {0x0001, 2},
{0x0002, 2}, {0x0002, 4}, {0x0003, 5}, {0x0006, 3},
{0x0003, 4}, {0x000E, 4}, {0x001E, 5}, {0x001F, 5},
},{//2
{0x0000, 2}, {0x0001, 2}, {0x0004, 3}, {0x0005, 3},
{0x0006, 3}, {0x0038, 6}, {0x0039, 6}, {0x001D, 5},
{0x003C, 6}, {0x003D, 6}, {0x003E, 6}, {0x003F, 6},
},{//3
{0x0000, 3}, {0x0002, 4}, {0x0003, 4}, {0x0001, 2},
{0x0002, 2}, {0x0018, 5}, {0x0019, 5}, {0x000D, 4},
{0x001C, 5}, {0x001D, 5}, {0x001E, 5}, {0x001F, 5},
}
};
static const uint16_t x8_orient_highquant_table[2][12][2]={
{//0
{0x0000, 2}, {0x0001, 2}, {0x0004, 3}, {0x0005, 3},
{0x0006, 3}, {0x0038, 6}, {0x001D, 5}, {0x0039, 6},
{0x003C, 6}, {0x003D, 6}, {0x003E, 6}, {0x003F, 6},
},{//1
{0x0000, 1}, {0x0002, 2}, {0x0006, 3}, {0x001C, 5},
{0x001D, 5}, {0x0078, 7}, {0x003D, 6}, {0x0079, 7},
{0x007C, 7}, {0x007D, 7}, {0x007E, 7}, {0x007F, 7},
}
};
#define MAX_OR_VLC_BITS 7
static const uint16_t x8_dc_lowquant_table[8][34][2]={
{//0
{0x0000, 5}, {0x0001, 4}, {0x0001, 5}, {0x0004, 5},
{0x0005, 5}, {0x0006, 5}, {0x000E, 6}, {0x000F, 6},
{0x0040, 8}, {0x0041, 8}, {0x0840, 13}, {0x0841, 13},
{0x0842, 13}, {0x0843, 13}, {0x0844, 13}, {0x0845, 13},
{0x0846, 13}, {0x0002, 2}, {0x0003, 2}, {0x0003, 3},
{0x0005, 4}, {0x0009, 5}, {0x0011, 6}, {0x0043, 8},
{0x0085, 9}, {0x0847, 13}, {0x0848, 13}, {0x0849, 13},
{0x084A, 13}, {0x084B, 13}, {0x084C, 13}, {0x084D, 13},
{0x084E, 13}, {0x084F, 13},
},{//1
{0x0000, 4}, {0x0001, 3}, {0x0002, 3}, {0x0001, 4},
{0x0006, 4}, {0x0004, 3}, {0x0007, 4}, {0x0005, 3},
{0x000C, 4}, {0x000D, 4}, {0x001C, 5}, {0x003A, 6},
{0x01D8, 9}, {0x01D9, 9}, {0x1DA0, 13}, {0x1DA1, 13},
{0x1DA2, 13}, {0x003C, 6}, {0x003D, 6}, {0x003E, 6},
{0x0077, 7}, {0x01DB, 9}, {0x007E, 7}, {0x00FE, 8},
{0x01FE, 9}, {0x1DA3, 13}, {0x1DA4, 13}, {0x1DA5, 13},
{0x0ED3, 12}, {0x0ED4, 12}, {0x01FF, 9}, {0x0ED5, 12},
{0x0ED6, 12}, {0x0ED7, 12},
},{//2
{0x0000, 4}, {0x0001, 3}, {0x0002, 3}, {0x0001, 4},
{0x0006, 4}, {0x0007, 4}, {0x0008, 4}, {0x0009, 4},
{0x0028, 6}, {0x0029, 6}, {0x0054, 7}, {0x0055, 7},
{0x0AC0, 12}, {0x0AC1, 12}, {0x0AC2, 12}, {0x0AC3, 12},
{0x0AC4, 12}, {0x000B, 4}, {0x0006, 3}, {0x000E, 4},
{0x001E, 5}, {0x003E, 6}, {0x003F, 6}, {0x0057, 7},
{0x00AD, 8}, {0x0AC5, 12}, {0x0AC6, 12}, {0x0AC7, 12},
{0x0AC8, 12}, {0x0AC9, 12}, {0x0ACA, 12}, {0x0ACB, 12},
{0x0566, 11}, {0x0567, 11},
},{//3
{0x0000, 4}, {0x0001, 2}, {0x0001, 3}, {0x0004, 3},
{0x0005, 3}, {0x0006, 3}, {0x0001, 4}, {0x000E, 4},
{0x003C, 6}, {0x003D, 6}, {0x007C, 7}, {0x00FA, 8},
{0x3EC0, 14}, {0x3EC1, 14}, {0x3EC2, 14}, {0x3EC3, 14},
{0x1F62, 13}, {0x01F7, 9}, {0x007E, 7}, {0x00FE, 8},
{0x00FF, 8}, {0x1F63, 13}, {0x1F64, 13}, {0x1F65, 13},
{0x1F66, 13}, {0x1F67, 13}, {0x1F68, 13}, {0x1F69, 13},
{0x1F6A, 13}, {0x1F6B, 13}, {0x1F6C, 13}, {0x1F6D, 13},
{0x1F6E, 13}, {0x1F6F, 13},
},{//4
{0x0000, 7}, {0x0001, 7}, {0x0002, 7}, {0x0003, 7},
{0x0004, 7}, {0x0005, 7}, {0x0006, 7}, {0x0007, 7},
{0x0008, 7}, {0x0009, 7}, {0x000A, 7}, {0x000B, 7},
{0x000C, 7}, {0x000D, 7}, {0x000E, 7}, {0x000F, 7},
{0x0010, 7}, {0x0001, 1}, {0x0001, 2}, {0x0011, 7},
{0x0012, 7}, {0x0013, 7}, {0x0014, 7}, {0x0015, 7},
{0x0016, 7}, {0x0017, 7}, {0x0018, 7}, {0x0019, 7},
{0x001A, 7}, {0x001B, 7}, {0x001C, 7}, {0x001D, 7},
{0x001E, 7}, {0x001F, 7},
},{//5
{0x0000, 5}, {0x0001, 4}, {0x0001, 5}, {0x0008, 6},
{0x0009, 6}, {0x000A, 6}, {0x0016, 7}, {0x000C, 6},
{0x0017, 7}, {0x000D, 6}, {0x0038, 8}, {0x001D, 7},
{0x0039, 8}, {0x0780, 13}, {0x0781, 13}, {0x0782, 13},
{0x0783, 13}, {0x0002, 3}, {0x0001, 1}, {0x0003, 3},
{0x001F, 7}, {0x003D, 8}, {0x0079, 9}, {0x0784, 13},
{0x0785, 13}, {0x0786, 13}, {0x0787, 13}, {0x0788, 13},
{0x0789, 13}, {0x078A, 13}, {0x078B, 13}, {0x078C, 13},
{0x078D, 13}, {0x03C7, 12},
},{//6
{0x0000, 4}, {0x0001, 2}, {0x0001, 3}, {0x0004, 3},
{0x0001, 4}, {0x000A, 4}, {0x0016, 5}, {0x002E, 6},
{0x005E, 7}, {0x005F, 7}, {0x00C0, 8}, {0x3040, 14},
{0x3041, 14}, {0x0305, 10}, {0x0183, 9}, {0x3042, 14},
{0x3043, 14}, {0x000D, 4}, {0x0007, 3}, {0x0019, 5},
{0x0031, 6}, {0x00C2, 8}, {0x00C3, 8}, {0x3044, 14},
{0x3045, 14}, {0x3046, 14}, {0x3047, 14}, {0x3048, 14},
{0x3049, 14}, {0x304A, 14}, {0x304B, 14}, {0x304C, 14},
{0x304D, 14}, {0x1827, 13},
},{//7
{0x0000, 6}, {0x0001, 6}, {0x0002, 6}, {0x0006, 7},
{0x0007, 7}, {0x0004, 6}, {0x0005, 6}, {0x0006, 6},
{0x000E, 7}, {0x001E, 8}, {0x001F, 8}, {0x0040, 9},
{0x0082, 10}, {0x0830, 14}, {0x0831, 14}, {0x0832, 14},
{0x0833, 14}, {0x0001, 1}, {0x0001, 2}, {0x0003, 4},
{0x0005, 5}, {0x0009, 6}, {0x0011, 7}, {0x0021, 8},
{0x0834, 14}, {0x0835, 14}, {0x0836, 14}, {0x0837, 14},
{0x0838, 14}, {0x0839, 14}, {0x083A, 14}, {0x083B, 14},
{0x041E, 13}, {0x041F, 13},
}
};
static const uint16_t x8_dc_highquant_table[8][34][2]={
{//0
{0x0000, 5}, {0x0001, 4}, {0x0002, 4}, {0x0001, 5},
{0x0006, 5}, {0x0004, 4}, {0x0007, 5}, {0x000A, 5},
{0x002C, 7}, {0x002D, 7}, {0x05C0, 12}, {0x05C1, 12},
{0x05C2, 12}, {0x05C3, 12}, {0x05C4, 12}, {0x05C5, 12},
{0x05C6, 12}, {0x0003, 3}, {0x0002, 2}, {0x0006, 3},
{0x000E, 4}, {0x001E, 5}, {0x001F, 5}, {0x002F, 7},
{0x005D, 8}, {0x05C7, 12}, {0x05C8, 12}, {0x05C9, 12},
{0x05CA, 12}, {0x05CB, 12}, {0x05CC, 12}, {0x05CD, 12},
{0x05CE, 12}, {0x05CF, 12},
},{//1
{0x0000, 3}, {0x0001, 3}, {0x0002, 3}, {0x0006, 4},
{0x0007, 4}, {0x0004, 3}, {0x000A, 4}, {0x000B, 4},
{0x0030, 6}, {0x0062, 7}, {0x0063, 7}, {0x0640, 11},
{0x0641, 11}, {0x0642, 11}, {0x0643, 11}, {0x0644, 11},
{0x0645, 11}, {0x0033, 6}, {0x000D, 4}, {0x001C, 5},
{0x001D, 5}, {0x003C, 6}, {0x001F, 5}, {0x0065, 7},
{0x007A, 7}, {0x0646, 11}, {0x007B, 7}, {0x0647, 11},
{0x0648, 11}, {0x0649, 11}, {0x064A, 11}, {0x064B, 11},
{0x0326, 10}, {0x0327, 10},
},{//2
{0x0000, 7}, {0x0001, 7}, {0x0001, 6}, {0x0004, 7},
{0x0003, 6}, {0x0005, 7}, {0x0010, 8}, {0x0011, 8},
{0x0240, 13}, {0x0241, 13}, {0x0242, 13}, {0x0243, 13},
{0x0244, 13}, {0x0245, 13}, {0x0246, 13}, {0x0247, 13},
{0x0124, 12}, {0x0001, 1}, {0x0001, 2}, {0x0001, 3},
{0x0003, 5}, {0x0005, 6}, {0x0013, 8}, {0x0125, 12},
{0x0126, 12}, {0x0127, 12}, {0x0128, 12}, {0x0129, 12},
{0x012A, 12}, {0x012B, 12}, {0x012C, 12}, {0x012D, 12},
{0x012E, 12}, {0x012F, 12},
},{//3
{0x0000, 4}, {0x0001, 3}, {0x0002, 3}, {0x0001, 4},
{0x0006, 4}, {0x0004, 3}, {0x0005, 3}, {0x0006, 3},
{0x000E, 5}, {0x000F, 5}, {0x0070, 7}, {0x0710, 11},
{0x0711, 11}, {0x0712, 11}, {0x0713, 11}, {0x0714, 11},
{0x0715, 11}, {0x001D, 5}, {0x0072, 7}, {0x003C, 6},
{0x003D, 6}, {0x0073, 7}, {0x007C, 7}, {0x007D, 7},
{0x007E, 7}, {0x0716, 11}, {0x0717, 11}, {0x0718, 11},
{0x007F, 7}, {0x0719, 11}, {0x071A, 11}, {0x071B, 11},
{0x038E, 10}, {0x038F, 10},
},{//4
{0x0000, 8}, {0x0001, 7}, {0x0002, 7}, {0x0003, 7},
{0x0002, 9}, {0x0008, 8}, {0x0003, 9}, {0x0240, 14},
{0x0241, 14}, {0x0242, 14}, {0x0243, 14}, {0x0244, 14},
{0x0245, 14}, {0x0246, 14}, {0x0247, 14}, {0x0124, 13},
{0x0125, 13}, {0x0001, 2}, {0x0001, 1}, {0x0001, 3},
{0x0001, 4}, {0x0003, 6}, {0x0005, 7}, {0x0013, 9},
{0x0126, 13}, {0x0127, 13}, {0x0128, 13}, {0x0129, 13},
{0x012A, 13}, {0x012B, 13}, {0x012C, 13}, {0x012D, 13},
{0x012E, 13}, {0x012F, 13},
},{//5
{0x0000, 7}, {0x0001, 7}, {0x0001, 6}, {0x0002, 6},
{0x0003, 6}, {0x0004, 6}, {0x0005, 6}, {0x0006, 6},
{0x0007, 6}, {0x0008, 6}, {0x0009, 6}, {0x000A, 6},
{0x000B, 6}, {0x000C, 6}, {0x000D, 6}, {0x000E, 6},
{0x000F, 6}, {0x0010, 6}, {0x0011, 6}, {0x0012, 6},
{0x0013, 6}, {0x0014, 6}, {0x0015, 6}, {0x0016, 6},
{0x0017, 6}, {0x0018, 6}, {0x0019, 6}, {0x0001, 1},
{0x001A, 6}, {0x001B, 6}, {0x001C, 6}, {0x001D, 6},
{0x001E, 6}, {0x001F, 6},
},{//6
{0x0000, 5}, {0x0001, 4}, {0x0001, 5}, {0x0004, 5},
{0x000A, 6}, {0x0006, 5}, {0x000B, 6}, {0x000E, 6},
{0x003C, 8}, {0x003D, 8}, {0x07C0, 13}, {0x07C1, 13},
{0x07C2, 13}, {0x07C3, 13}, {0x07C4, 13}, {0x07C5, 13},
{0x07C6, 13}, {0x0001, 2}, {0x0002, 2}, {0x0006, 3},
{0x000E, 4}, {0x001E, 5}, {0x001F, 5}, {0x003F, 8},
{0x007D, 9}, {0x07C7, 13}, {0x07C8, 13}, {0x07C9, 13},
{0x07CA, 13}, {0x07CB, 13}, {0x07CC, 13}, {0x07CD, 13},
{0x07CE, 13}, {0x07CF, 13},
},{//7
{0x0000, 7}, {0x0001, 7}, {0x0002, 7}, {0x0003, 7},
{0x0004, 7}, {0x0005, 7}, {0x0006, 7}, {0x0007, 7},
{0x0008, 7}, {0x0009, 7}, {0x000A, 7}, {0x000B, 7},
{0x000C, 7}, {0x000D, 7}, {0x000E, 7}, {0x000F, 7},
{0x0010, 7}, {0x0001, 1}, {0x0001, 2}, {0x0011, 7},
{0x0012, 7}, {0x0013, 7}, {0x0014, 7}, {0x0015, 7},
{0x0016, 7}, {0x0017, 7}, {0x0018, 7}, {0x0019, 7},
{0x001A, 7}, {0x001B, 7}, {0x001C, 7}, {0x001D, 7},
{0x001E, 7}, {0x001F, 7},
}
};
#define MAX_DC_VLC_BITS 14
static const uint16_t x8_ac0_lowquant_table[8][77][2]={
{//0
{0x0000, 2}, {0x0002, 3}, {0x0006, 4}, {0x000E, 5},
{0x001E, 6}, {0x003E, 7}, {0x003F, 7}, {0x0040, 7},
{0x0104, 9}, {0x0083, 8}, {0x0084, 8}, {0x0085, 8},
{0x020A, 10}, {0x020B, 10}, {0x0218, 10}, {0x0219, 10},
{0x0009, 4}, {0x0044, 7}, {0x010D, 9}, {0x021C, 10},
{0x0023, 6}, {0x0045, 7}, {0x0050, 7}, {0x000B, 4},
{0x000C, 4}, {0x0015, 5}, {0x001A, 5}, {0x001B, 5},
{0x0029, 6}, {0x0038, 6}, {0x0039, 6}, {0x003A, 6},
{0x0051, 7}, {0x0076, 7}, {0x0077, 7}, {0x0078, 7},
{0x0079, 7}, {0x007A, 7}, {0x007B, 7}, {0x00F8, 8},
{0x010F, 9}, {0x021D, 10}, {0x3E40, 14}, {0x3E41, 14},
{0x3E42, 14}, {0x3E43, 14}, {0x03E5, 10}, {0x3E44, 14},
{0x01F3, 9}, {0x3E45, 14}, {0x3E46, 14}, {0x3E47, 14},
{0x00FA, 8}, {0x3E48, 14}, {0x3E49, 14}, {0x3E4A, 14},
{0x3E4B, 14}, {0x03EC, 10}, {0x3E4C, 14}, {0x007E, 7},
{0x00FE, 8}, {0x00FF, 8}, {0x01F7, 9}, {0x3E4D, 14},
{0x3E4E, 14}, {0x3E4F, 14}, {0x3ED0, 14}, {0x3ED1, 14},
{0x3ED2, 14}, {0x3ED3, 14}, {0x3ED4, 14}, {0x3ED5, 14},
{0x1F6B, 13}, {0x1F6C, 13}, {0x1F6D, 13}, {0x1F6E, 13},
{0x1F6F, 13},
},{//1
{0x0000, 3}, {0x0004, 5}, {0x0014, 7}, {0x000B, 6},
{0x000C, 6}, {0x002A, 8}, {0x002B, 8}, {0x0034, 8},
{0x0D40, 14}, {0x0D41, 14}, {0x001B, 7}, {0x0D42, 14},
{0x0D43, 14}, {0x0D44, 14}, {0x0D45, 14}, {0x0D46, 14},
{0x000E, 6}, {0x003C, 8}, {0x0D47, 14}, {0x003D, 8},
{0x0D48, 14}, {0x0D49, 14}, {0x0D4A, 14}, {0x0001, 2},
{0x0004, 3}, {0x0014, 5}, {0x000B, 4}, {0x000C, 4},
{0x000D, 4}, {0x002A, 6}, {0x001F, 7}, {0x0056, 7},
{0x0057, 7}, {0x0070, 7}, {0x00E2, 8}, {0x0072, 7},
{0x003A, 6}, {0x003B, 6}, {0x003C, 6}, {0x003D, 6},
{0x00E3, 8}, {0x0D4B, 14}, {0x00E6, 8}, {0x00E7, 8},
{0x00F8, 8}, {0x0D4C, 14}, {0x0D4D, 14}, {0x0D4E, 14},
{0x00F9, 8}, {0x0D4F, 14}, {0x0D50, 14}, {0x0D51, 14},
{0x06A9, 13}, {0x06AA, 13}, {0x06AB, 13}, {0x06AC, 13},
{0x06AD, 13}, {0x06AE, 13}, {0x06AF, 13}, {0x003F, 6},
{0x06B0, 13}, {0x06B1, 13}, {0x06B2, 13}, {0x06B3, 13},
{0x06B4, 13}, {0x007D, 7}, {0x06B5, 13}, {0x06B6, 13},
{0x06B7, 13}, {0x06B8, 13}, {0x06B9, 13}, {0x06BA, 13},
{0x06BB, 13}, {0x06BC, 13}, {0x06BD, 13}, {0x06BE, 13},
{0x06BF, 13},
},{//2
{0x0000, 2}, {0x0002, 3}, {0x0003, 3}, {0x0008, 4},
{0x0012, 5}, {0x0013, 5}, {0x0028, 6}, {0x0029, 6},
{0x0054, 7}, {0x0055, 7}, {0x0056, 7}, {0x00AE, 8},
{0x00AF, 8}, {0x00B0, 8}, {0x0162, 9}, {0x02C6, 10},
{0x000C, 4}, {0x002D, 6}, {0x00B2, 8}, {0x0166, 9},
{0x002E, 6}, {0x0167, 9}, {0x00BC, 8}, {0x001A, 5},
{0x0036, 6}, {0x0037, 6}, {0x0038, 6}, {0x005F, 7},
{0x0072, 7}, {0x0073, 7}, {0x0074, 7}, {0x0075, 7},
{0x0076, 7}, {0x0077, 7}, {0x0078, 7}, {0x0079, 7},
{0x007A, 7}, {0x007B, 7}, {0x00BD, 8}, {0xB1C0, 16},
{0xB1C1, 16}, {0x58E1, 15}, {0x0B1D, 12}, {0x58E2, 15},
{0x58E3, 15}, {0x58E4, 15}, {0x00F8, 8}, {0x03E4, 10},
{0x01F3, 9}, {0x0B1E, 12}, {0x58E5, 15}, {0x58E6, 15},
{0x00FA, 8}, {0x58E7, 15}, {0x58F8, 15}, {0x58F9, 15},
{0x58FA, 15}, {0x01F6, 9}, {0x58FB, 15}, {0x007E, 7},
{0x00FE, 8}, {0x00FF, 8}, {0x07CA, 11}, {0x0F96, 12},
{0x58FC, 15}, {0x58FD, 15}, {0x58FE, 15}, {0x58FF, 15},
{0x7CB8, 15}, {0x7CB9, 15}, {0x7CBA, 15}, {0x7CBB, 15},
{0x7CBC, 15}, {0x01F7, 9}, {0x7CBD, 15}, {0x7CBE, 15},
{0x7CBF, 15},
},{//3
{0x0000, 2}, {0x0002, 3}, {0x0006, 4}, {0x000E, 5},
{0x000F, 5}, {0x0020, 6}, {0x0021, 6}, {0x0044, 7},
{0x0045, 7}, {0x008C, 8}, {0x008D, 8}, {0x011C, 9},
{0x011D, 9}, {0x011E, 9}, {0x023E, 10}, {0x023F, 10},
{0x0005, 3}, {0x0012, 5}, {0x004C, 7}, {0x004D, 7},
{0x000C, 4}, {0x004E, 7}, {0x001A, 5}, {0x0036, 6},
{0x004F, 7}, {0x006E, 7}, {0x006F, 7}, {0x00E0, 8},
{0x00E1, 8}, {0x00E2, 8}, {0x00E3, 8}, {0x00E4, 8},
{0x00E5, 8}, {0x01CC, 9}, {0x00E7, 8}, {0x00E8, 8},
{0x00E9, 8}, {0x01CD, 9}, {0x0750, 11}, {0x03A9, 10},
{0x0751, 11}, {0x7540, 15}, {0x03AB, 10}, {0x7541, 15},
{0x7542, 15}, {0x7543, 15}, {0x01D6, 9}, {0x0755, 11},
{0x0076, 7}, {0x0EA9, 12}, {0x7544, 15}, {0x7545, 15},
{0x001E, 5}, {0x0077, 7}, {0x00F8, 8}, {0x03AE, 10},
{0x075E, 11}, {0x007D, 7}, {0x03E4, 10}, {0x00FC, 8},
{0x00FD, 8}, {0x03E5, 10}, {0x03E6, 10}, {0x0EBE, 12},
{0x7546, 15}, {0x07CE, 11}, {0x7547, 15}, {0x75F8, 15},
{0x75F9, 15}, {0x75FA, 15}, {0x75FB, 15}, {0x75FC, 15},
{0x75FD, 15}, {0x007F, 7}, {0x3AFF, 14}, {0x0F9E, 12},
{0x0F9F, 12},
},{//4
{0x0000, 3}, {0x0002, 4}, {0x0003, 4}, {0x0008, 5},
{0x0012, 6}, {0x0013, 6}, {0x0014, 6}, {0x002A, 7},
{0x0016, 6}, {0x002B, 7}, {0x005C, 8}, {0x005D, 8},
{0x005E, 8}, {0x00BE, 9}, {0x00BF, 9}, {0x0060, 8},
{0x0007, 4}, {0x000D, 5}, {0x0019, 6}, {0x0020, 6},
{0x0009, 4}, {0x0021, 6}, {0x0011, 5}, {0x0014, 5},
{0x002A, 6}, {0x002B, 6}, {0x002C, 6}, {0x002D, 6},
{0x002E, 6}, {0x002F, 6}, {0x0030, 6}, {0x0031, 7},
{0x0062, 7}, {0x0063, 7}, {0x0064, 7}, {0x0065, 7},
{0x0066, 7}, {0x0061, 8}, {0x0670, 11}, {0x0068, 7},
{0x0069, 7}, {0x00CF, 8}, {0x019D, 9}, {0x01A8, 9},
{0x01A9, 9}, {0x0339, 10}, {0x01AA, 9}, {0x0356, 10},
{0x0036, 6}, {0x00D6, 8}, {0x6710, 15}, {0x6711, 15},
{0x000E, 4}, {0x006E, 7}, {0x01AE, 9}, {0x6712, 15},
{0x6713, 15}, {0x003C, 6}, {0x0357, 10}, {0x006F, 7},
{0x00F4, 8}, {0x00F5, 8}, {0x035E, 10}, {0x01EC, 9},
{0x6714, 15}, {0x01ED, 9}, {0x035F, 10}, {0x03DC, 10},
{0x03DD, 10}, {0x6715, 15}, {0x338B, 14}, {0x338C, 14},
{0x338D, 14}, {0x001F, 5}, {0x01EF, 9}, {0x338E, 14},
{0x338F, 14},
},{//5
{0x0000, 2}, {0x0004, 4}, {0x000A, 5}, {0x000B, 5},
{0x0018, 6}, {0x0019, 6}, {0x0034, 7}, {0x006A, 8},
{0x006B, 8}, {0x006C, 8}, {0x00DA, 9}, {0x036C, 11},
{0x006E, 8}, {0x01B7, 10}, {0x036D, 11}, {0x3780, 15},
{0x0004, 3}, {0x000E, 5}, {0x001E, 6}, {0x003E, 7},
{0x000A, 4}, {0x002C, 6}, {0x0017, 5}, {0x002D, 6},
{0x003F, 7}, {0x00C0, 8}, {0x0061, 7}, {0x00C1, 8},
{0x0062, 7}, {0x00C6, 8}, {0x0064, 7}, {0x00C7, 8},
{0x00CA, 8}, {0x00DF, 9}, {0x0196, 9}, {0x0197, 9},
{0x0198, 9}, {0x0199, 9}, {0x0379, 11}, {0x019A, 9},
{0x01BD, 10}, {0x066C, 11}, {0x3781, 15}, {0x0337, 10},
{0x066D, 11}, {0x0670, 11}, {0x0339, 10}, {0x0671, 11},
{0x0034, 6}, {0x00CF, 8}, {0x3782, 15}, {0x3783, 15},
{0x000E, 4}, {0x001B, 5}, {0x006A, 7}, {0x006B, 7},
{0x019D, 9}, {0x003C, 6}, {0x00F4, 8}, {0x00F5, 8},
{0x03D8, 10}, {0x07B2, 11}, {0x3784, 15}, {0x03DA, 10},
{0x3785, 15}, {0x03DB, 10}, {0x03DC, 10}, {0x3786, 15},
{0x3787, 15}, {0x1BC4, 14}, {0x1BC5, 14}, {0x1BC6, 14},
{0x1BC7, 14}, {0x001F, 5}, {0x03DD, 10}, {0x07B3, 11},
{0x01EF, 9},
},{//6
{0x0000, 2}, {0x0004, 4}, {0x000A, 5}, {0x0016, 6},
{0x0017, 6}, {0x0060, 8}, {0x00C2, 9}, {0x0186, 10},
{0x0187, 10}, {0x00C4, 9}, {0x3140, 15}, {0x3141, 15},
{0x018B, 10}, {0x3142, 15}, {0x018C, 10}, {0x3143, 15},
{0x0007, 4}, {0x000D, 5}, {0x0064, 8}, {0x0065, 8},
{0x0010, 5}, {0x00C7, 9}, {0x0066, 8}, {0x0005, 3},
{0x0006, 3}, {0x0009, 4}, {0x0011, 5}, {0x0038, 6},
{0x0039, 6}, {0x0074, 7}, {0x0075, 7}, {0x0076, 7},
{0x0067, 8}, {0x00EE, 8}, {0x01DE, 9}, {0x00F0, 8},
{0x018D, 10}, {0x3144, 15}, {0x01DF, 9}, {0x003D, 6},
{0x003E, 6}, {0x01E2, 9}, {0x03C6, 10}, {0x00F2, 8},
{0x00F3, 8}, {0x03C7, 10}, {0x3145, 15}, {0x3146, 15},
{0x01F8, 9}, {0x3147, 15}, {0x3148, 15}, {0x3149, 15},
{0x00FD, 8}, {0x314A, 15}, {0x314B, 15}, {0x314C, 15},
{0x314D, 15}, {0x01F9, 9}, {0x314E, 15}, {0x01FC, 9},
{0x314F, 15}, {0x3150, 15}, {0x3151, 15}, {0x3152, 15},
{0x3153, 15}, {0x03FA, 10}, {0x03FB, 10}, {0x3154, 15},
{0x3155, 15}, {0x3156, 15}, {0x3157, 15}, {0x3158, 15},
{0x3159, 15}, {0x00FF, 8}, {0x18AD, 14}, {0x18AE, 14},
{0x18AF, 14},
},{//7
{0x0000, 4}, {0x0080, 11}, {0x0081, 11}, {0x0082, 11},
{0x0083, 11}, {0x0084, 11}, {0x0085, 11}, {0x0086, 11},
{0x0087, 11}, {0x0088, 11}, {0x0089, 11}, {0x008A, 11},
{0x008B, 11}, {0x008C, 11}, {0x008D, 11}, {0x008E, 11},
{0x008F, 11}, {0x0048, 10}, {0x0049, 10}, {0x004A, 10},
{0x004B, 10}, {0x004C, 10}, {0x004D, 10}, {0x0001, 1},
{0x0001, 2}, {0x004E, 10}, {0x0002, 4}, {0x0003, 4},
{0x004F, 10}, {0x0050, 10}, {0x0051, 10}, {0x0052, 10},
{0x0053, 10}, {0x0054, 10}, {0x0055, 10}, {0x0056, 10},
{0x0057, 10}, {0x0058, 10}, {0x0059, 10}, {0x005A, 10},
{0x005B, 10}, {0x005C, 10}, {0x005D, 10}, {0x005E, 10},
{0x005F, 10}, {0x0060, 10}, {0x0061, 10}, {0x0062, 10},
{0x0063, 10}, {0x0064, 10}, {0x0065, 10}, {0x0066, 10},
{0x0067, 10}, {0x0068, 10}, {0x0069, 10}, {0x006A, 10},
{0x006B, 10}, {0x006C, 10}, {0x006D, 10}, {0x006E, 10},
{0x006F, 10}, {0x0070, 10}, {0x0071, 10}, {0x0072, 10},
{0x0073, 10}, {0x0074, 10}, {0x0075, 10}, {0x0076, 10},
{0x0077, 10}, {0x0078, 10}, {0x0079, 10}, {0x007A, 10},
{0x007B, 10}, {0x007C, 10}, {0x007D, 10}, {0x007E, 10},
{0x007F, 10},
}
};
static const uint16_t x8_ac0_highquant_table[8][77][2]={
{//0
{0x0000, 3}, {0x0002, 4}, {0x000C, 6}, {0x000D, 6},
{0x001C, 7}, {0x000F, 6}, {0x1D00, 15}, {0x003B, 8},
{0x1D01, 15}, {0x0075, 9}, {0x1D02, 15}, {0x0080, 9},
{0x1D03, 15}, {0x1D04, 15}, {0x1D05, 15}, {0x0E83, 14},
{0x0009, 5}, {0x0011, 6}, {0x0081, 9}, {0x0082, 9},
{0x0021, 7}, {0x0028, 7}, {0x0083, 9}, {0x0002, 2},
{0x0003, 3}, {0x000C, 4}, {0x000D, 4}, {0x000B, 5},
{0x0015, 6}, {0x0052, 8}, {0x0070, 7}, {0x0039, 6},
{0x0071, 7}, {0x0053, 8}, {0x0E84, 14}, {0x0074, 7},
{0x0075, 7}, {0x0076, 7}, {0x01DC, 9}, {0x001E, 5},
{0x003E, 6}, {0x01DD, 9}, {0x00EF, 8}, {0x01F8, 9},
{0x01F9, 9}, {0x0E85, 14}, {0x0E86, 14}, {0x0E87, 14},
{0x00FD, 8}, {0x0E88, 14}, {0x0E89, 14}, {0x0E8A, 14},
{0x0E8B, 14}, {0x0E8C, 14}, {0x0E8D, 14}, {0x0E8E, 14},
{0x0E8F, 14}, {0x0E90, 14}, {0x0E91, 14}, {0x01FC, 9},
{0x0E92, 14}, {0x0E93, 14}, {0x0E94, 14}, {0x0E95, 14},
{0x0E96, 14}, {0x0E97, 14}, {0x01FD, 9}, {0x0E98, 14},
{0x01FE, 9}, {0x0E99, 14}, {0x0E9A, 14}, {0x0E9B, 14},
{0x0E9C, 14}, {0x01FF, 9}, {0x0E9D, 14}, {0x0E9E, 14},
{0x0E9F, 14},
},{//1
{0x0000, 3}, {0x0002, 4}, {0x0003, 4}, {0x0008, 5},
{0x0012, 6}, {0x0013, 6}, {0x0014, 6}, {0x0015, 6},
{0x002C, 7}, {0x005A, 8}, {0x005B, 8}, {0x005C, 8},
{0x005D, 8}, {0x1780, 14}, {0x0179, 10}, {0x017A, 10},
{0x0006, 4}, {0x000E, 5}, {0x001E, 6}, {0x003E, 7},
{0x0010, 5}, {0x0022, 6}, {0x0012, 5}, {0x000A, 4},
{0x0013, 5}, {0x0016, 5}, {0x0023, 6}, {0x002E, 6},
{0x002F, 6}, {0x0030, 6}, {0x0031, 6}, {0x003F, 7},
{0x005F, 8}, {0x00C8, 8}, {0x0065, 7}, {0x0066, 7},
{0x0067, 7}, {0x0068, 7}, {0x00C9, 8}, {0x0069, 7},
{0x006A, 7}, {0x00D6, 8}, {0x00D7, 8}, {0x00D8, 8},
{0x1781, 14}, {0x017B, 10}, {0x01B2, 9}, {0x1782, 14},
{0x001C, 5}, {0x01B3, 9}, {0x1783, 14}, {0x1784, 14},
{0x001D, 5}, {0x00DA, 8}, {0x1785, 14}, {0x1786, 14},
{0x1787, 14}, {0x0037, 6}, {0x00DB, 8}, {0x0078, 7},
{0x00F2, 8}, {0x01E6, 9}, {0x00F4, 8}, {0x1788, 14},
{0x1789, 14}, {0x00F5, 8}, {0x01E7, 9}, {0x178A, 14},
{0x178B, 14}, {0x178C, 14}, {0x178D, 14}, {0x01EC, 9},
{0x178E, 14}, {0x001F, 5}, {0x00F7, 8}, {0x01ED, 9},
{0x178F, 14},
},{//2
{0x0000, 4}, {0x0002, 5}, {0x0180, 12}, {0x0181, 12},
{0x0182, 12}, {0x0183, 12}, {0x0184, 12}, {0x0185, 12},
{0x0186, 12}, {0x0187, 12}, {0x0188, 12}, {0x0189, 12},
{0x00C5, 11}, {0x00C6, 11}, {0x00C7, 11}, {0x00C8, 11},
{0x00C9, 11}, {0x00CA, 11}, {0x00CB, 11}, {0x00CC, 11},
{0x00CD, 11}, {0x00CE, 11}, {0x00CF, 11}, {0x0001, 1},
{0x0001, 2}, {0x0004, 5}, {0x0005, 5}, {0x0006, 5},
{0x00D0, 11}, {0x00D1, 11}, {0x00D2, 11}, {0x00D3, 11},
{0x00D4, 11}, {0x00D5, 11}, {0x00D6, 11}, {0x00D7, 11},
{0x00D8, 11}, {0x00D9, 11}, {0x00DA, 11}, {0x0007, 5},
{0x00DB, 11}, {0x00DC, 11}, {0x00DD, 11}, {0x00DE, 11},
{0x00DF, 11}, {0x00E0, 11}, {0x00E1, 11}, {0x00E2, 11},
{0x00E3, 11}, {0x00E4, 11}, {0x00E5, 11}, {0x00E6, 11},
{0x00E7, 11}, {0x00E8, 11}, {0x00E9, 11}, {0x00EA, 11},
{0x00EB, 11}, {0x00EC, 11}, {0x00ED, 11}, {0x00EE, 11},
{0x00EF, 11}, {0x00F0, 11}, {0x00F1, 11}, {0x00F2, 11},
{0x00F3, 11}, {0x00F4, 11}, {0x00F5, 11}, {0x00F6, 11},
{0x00F7, 11}, {0x00F8, 11}, {0x00F9, 11}, {0x00FA, 11},
{0x00FB, 11}, {0x00FC, 11}, {0x00FD, 11}, {0x00FE, 11},
{0x00FF, 11},
},{//3
{0x0000, 8}, {0x0001, 8}, {0x0002, 8}, {0x0003, 8},
{0x0004, 8}, {0x0005, 8}, {0x0006, 8}, {0x0007, 8},
{0x0008, 8}, {0x0009, 8}, {0x000A, 8}, {0x000B, 8},
{0x000C, 8}, {0x000D, 8}, {0x000E, 8}, {0x000F, 8},
{0x0010, 8}, {0x0011, 8}, {0x0012, 8}, {0x0013, 8},
{0x0014, 8}, {0x0015, 8}, {0x0016, 8}, {0x0001, 1},
{0x0017, 8}, {0x000C, 7}, {0x000D, 7}, {0x000E, 7},
{0x000F, 7}, {0x0010, 7}, {0x0011, 7}, {0x0012, 7},
{0x0013, 7}, {0x0014, 7}, {0x0015, 7}, {0x0016, 7},
{0x0017, 7}, {0x0018, 7}, {0x0019, 7}, {0x001A, 7},
{0x001B, 7}, {0x001C, 7}, {0x001D, 7}, {0x001E, 7},
{0x001F, 7}, {0x0020, 7}, {0x0021, 7}, {0x0022, 7},
{0x0023, 7}, {0x0024, 7}, {0x0025, 7}, {0x0026, 7},
{0x0027, 7}, {0x0028, 7}, {0x0029, 7}, {0x002A, 7},
{0x002B, 7}, {0x002C, 7}, {0x002D, 7}, {0x002E, 7},
{0x002F, 7}, {0x0030, 7}, {0x0031, 7}, {0x0032, 7},
{0x0033, 7}, {0x0034, 7}, {0x0035, 7}, {0x0036, 7},
{0x0037, 7}, {0x0038, 7}, {0x0039, 7}, {0x003A, 7},
{0x003B, 7}, {0x003C, 7}, {0x003D, 7}, {0x003E, 7},
{0x003F, 7},
},{//4
{0x0000, 9}, {0x0001, 9}, {0x0002, 9}, {0x0003, 9},
{0x0004, 9}, {0x0005, 9}, {0x0006, 9}, {0x0007, 9},
{0x0008, 9}, {0x0009, 9}, {0x000A, 9}, {0x000B, 9},
{0x000C, 9}, {0x000D, 9}, {0x000E, 9}, {0x000F, 9},
{0x0010, 9}, {0x0011, 9}, {0x0012, 9}, {0x0013, 9},
{0x0014, 9}, {0x0015, 9}, {0x000B, 8}, {0x0001, 2},
{0x0001, 1}, {0x000C, 8}, {0x000D, 8}, {0x000E, 8},
{0x000F, 8}, {0x0010, 8}, {0x0011, 8}, {0x0012, 8},
{0x0013, 8}, {0x0014, 8}, {0x0015, 8}, {0x0016, 8},
{0x0017, 8}, {0x0018, 8}, {0x0019, 8}, {0x001A, 8},
{0x001B, 8}, {0x001C, 8}, {0x001D, 8}, {0x001E, 8},
{0x001F, 8}, {0x0020, 8}, {0x0021, 8}, {0x0022, 8},
{0x0023, 8}, {0x0024, 8}, {0x0025, 8}, {0x0026, 8},
{0x0027, 8}, {0x0028, 8}, {0x0029, 8}, {0x002A, 8},
{0x002B, 8}, {0x002C, 8}, {0x002D, 8}, {0x002E, 8},
{0x002F, 8}, {0x0030, 8}, {0x0031, 8}, {0x0032, 8},
{0x0033, 8}, {0x0034, 8}, {0x0035, 8}, {0x0036, 8},
{0x0037, 8}, {0x0038, 8}, {0x0039, 8}, {0x003A, 8},
{0x003B, 8}, {0x003C, 8}, {0x003D, 8}, {0x003E, 8},
{0x003F, 8},
},{//5
{0x0000, 10}, {0x0001, 10}, {0x0002, 10}, {0x0003, 10},
{0x0004, 10}, {0x0005, 10}, {0x0006, 10}, {0x0007, 10},
{0x0008, 10}, {0x0009, 10}, {0x000A, 10}, {0x000B, 10},
{0x000C, 10}, {0x000D, 10}, {0x000E, 10}, {0x000F, 10},
{0x0010, 10}, {0x0011, 10}, {0x0012, 10}, {0x0013, 10},
{0x000A, 9}, {0x000B, 9}, {0x000C, 9}, {0x0001, 1},
{0x0001, 3}, {0x000D, 9}, {0x000E, 9}, {0x0001, 2},
{0x000F, 9}, {0x0010, 9}, {0x0011, 9}, {0x0012, 9},
{0x0013, 9}, {0x0014, 9}, {0x0015, 9}, {0x0016, 9},
{0x0017, 9}, {0x0018, 9}, {0x0019, 9}, {0x001A, 9},
{0x001B, 9}, {0x001C, 9}, {0x001D, 9}, {0x001E, 9},
{0x001F, 9}, {0x0020, 9}, {0x0021, 9}, {0x0022, 9},
{0x0023, 9}, {0x0024, 9}, {0x0025, 9}, {0x0026, 9},
{0x0027, 9}, {0x0028, 9}, {0x0029, 9}, {0x002A, 9},
{0x002B, 9}, {0x002C, 9}, {0x002D, 9}, {0x002E, 9},
{0x002F, 9}, {0x0030, 9}, {0x0031, 9}, {0x0032, 9},
{0x0033, 9}, {0x0034, 9}, {0x0035, 9}, {0x0036, 9},
{0x0037, 9}, {0x0038, 9}, {0x0039, 9}, {0x003A, 9},
{0x003B, 9}, {0x003C, 9}, {0x003D, 9}, {0x003E, 9},
{0x003F, 9},
},{//6
{0x0000, 2}, {0x0004, 4}, {0x000A, 5}, {0x000B, 5},
{0x0018, 6}, {0x0019, 6}, {0x0034, 7}, {0x006A, 8},
{0x006B, 8}, {0x006C, 8}, {0x00DA, 9}, {0x00DB, 9},
{0x01B8, 10}, {0x00DD, 9}, {0x01B9, 10}, {0x3780, 15},
{0x0004, 3}, {0x000E, 5}, {0x001E, 6}, {0x001F, 6},
{0x000A, 4}, {0x0058, 7}, {0x0017, 5}, {0x0018, 5},
{0x0059, 7}, {0x005A, 7}, {0x005B, 7}, {0x00C8, 8},
{0x0065, 7}, {0x0066, 7}, {0x00C9, 8}, {0x00CE, 8},
{0x00CF, 8}, {0x00D0, 8}, {0x00D1, 8}, {0x00D2, 8},
{0x00D3, 8}, {0x00DF, 9}, {0x00D4, 8}, {0x00D5, 8},
{0x00D6, 8}, {0x01AE, 9}, {0x3781, 15}, {0x01BD, 10},
{0x035E, 10}, {0x035F, 10}, {0x3782, 15}, {0x0360, 10},
{0x0037, 6}, {0x01B1, 9}, {0x3783, 15}, {0x3784, 15},
{0x000E, 4}, {0x003C, 6}, {0x0361, 10}, {0x3785, 15},
{0x1BC3, 14}, {0x003D, 6}, {0x00D9, 8}, {0x1BC4, 14},
{0x0368, 10}, {0x1BC5, 14}, {0x1BC6, 14}, {0x1BC7, 14},
{0x1BC8, 14}, {0x00DB, 8}, {0x0369, 10}, {0x036A, 10},
{0x1BC9, 14}, {0x1BCA, 14}, {0x1BCB, 14}, {0x1BCC, 14},
{0x1BCD, 14}, {0x001F, 5}, {0x036B, 10}, {0x1BCE, 14},
{0x1BCF, 14},
},{//7
{0x0000, 3}, {0x0002, 4}, {0x0006, 5}, {0x0007, 5},
{0x0010, 6}, {0x0044, 8}, {0x0023, 7}, {0x0012, 6},
{0x0026, 7}, {0x08A0, 13}, {0x004E, 8}, {0x004F, 8},
{0x08A1, 13}, {0x08A2, 13}, {0x08A3, 13}, {0x0050, 8},
{0x0006, 4}, {0x000B, 5}, {0x0029, 7}, {0x0015, 6},
{0x001C, 6}, {0x003A, 7}, {0x001E, 6}, {0x0004, 3},
{0x0014, 5}, {0x0015, 5}, {0x000B, 4}, {0x001F, 6},
{0x0030, 6}, {0x0031, 6}, {0x0019, 5}, {0x0051, 8},
{0x0034, 6}, {0x0035, 6}, {0x0036, 6}, {0x0037, 6},
{0x0076, 8}, {0x0077, 8}, {0x0070, 7}, {0x001D, 5},
{0x0071, 7}, {0x0072, 7}, {0x08A4, 13}, {0x0073, 7},
{0x00F0, 8}, {0x08A5, 13}, {0x08A6, 13}, {0x08A7, 13},
{0x0079, 7}, {0x007A, 7}, {0x08A8, 13}, {0x08A9, 13},
{0x00F1, 8}, {0x08AA, 13}, {0x08AB, 13}, {0x08AC, 13},
{0x08AD, 13}, {0x00F6, 8}, {0x08AE, 13}, {0x007C, 7},
{0x00F7, 8}, {0x08AF, 13}, {0x08B0, 13}, {0x08B1, 13},
{0x08B2, 13}, {0x00FA, 8}, {0x08B3, 13}, {0x08B4, 13},
{0x08B5, 13}, {0x08B6, 13}, {0x08B7, 13}, {0x00FB, 8},
{0x045C, 12}, {0x003F, 6}, {0x045D, 12}, {0x045E, 12},
{0x045F, 12},
}
};
static const uint16_t x8_ac1_lowquant_table[8][77][2]={
{//0
{0x0000, 3}, {0x0002, 4}, {0x0003, 4}, {0x0008, 5},
{0x0012, 6}, {0x0026, 7}, {0x0014, 6}, {0x004E, 8},
{0x004F, 8}, {0x00A8, 9}, {0x0152, 10}, {0x00AA, 9},
{0x00AB, 9}, {0x00AC, 9}, {0x2A60, 15}, {0x02A7, 11},
{0x0006, 4}, {0x000B, 5}, {0x001C, 6}, {0x003A, 7},
{0x000F, 5}, {0x003B, 7}, {0x0010, 5}, {0x0005, 3},
{0x0009, 4}, {0x0011, 5}, {0x0018, 5}, {0x0019, 5},
{0x001A, 5}, {0x0036, 6}, {0x0037, 6}, {0x0070, 7},
{0x0057, 8}, {0x00E2, 8}, {0x00E3, 8}, {0x00E4, 8},
{0x00E5, 8}, {0x00AD, 9}, {0x0398, 10}, {0x003A, 6},
{0x0076, 7}, {0x00E7, 8}, {0x00EE, 8}, {0x00EF, 8},
{0x0732, 11}, {0x039A, 10}, {0x0733, 11}, {0x2A61, 15},
{0x0078, 7}, {0x1531, 14}, {0x1532, 14}, {0x1533, 14},
{0x003D, 6}, {0x039B, 10}, {0x1534, 14}, {0x1535, 14},
{0x1536, 14}, {0x0079, 7}, {0x1537, 14}, {0x00F8, 8},
{0x01F2, 9}, {0x07CC, 11}, {0x03E7, 10}, {0x07CD, 11},
{0x3E80, 14}, {0x00FB, 8}, {0x03E9, 10}, {0x3E81, 14},
{0x3E82, 14}, {0x3E83, 14}, {0x3E84, 14}, {0x3E85, 14},
{0x3E86, 14}, {0x003F, 6}, {0x01F5, 9}, {0x07D1, 11},
{0x3E87, 14},
},{//1
{0x0000, 2}, {0x0002, 3}, {0x0006, 4}, {0x000E, 5},
{0x001E, 6}, {0x001F, 6}, {0x0040, 7}, {0x0082, 8},
{0x0083, 8}, {0x0084, 8}, {0x010A, 9}, {0x010B, 9},
{0x0430, 11}, {0x0431, 11}, {0x0432, 11}, {0x0433, 11},
{0x0005, 3}, {0x0011, 5}, {0x0024, 6}, {0x004A, 7},
{0x000C, 4}, {0x0026, 6}, {0x000D, 4}, {0x0087, 8},
{0x010D, 9}, {0x0258, 10}, {0x012D, 9}, {0x0259, 10},
{0x025C, 10}, {0x0974, 12}, {0x025E, 10}, {0x025F, 10},
{0x0270, 10}, {0x0271, 10}, {0x04BB, 11}, {0x0975, 12},
{0x0272, 10}, {0x09CC, 12}, {0x09CD, 12}, {0x4E70, 15},
{0x4E71, 15}, {0x4E72, 15}, {0x4E73, 15}, {0x273A, 14},
{0x273B, 14}, {0x273C, 14}, {0x04E8, 11}, {0x04E9, 11},
{0x009E, 8}, {0x0275, 10}, {0x09D8, 12}, {0x273D, 14},
{0x000E, 4}, {0x003C, 6}, {0x007A, 7}, {0x009F, 8},
{0x0277, 10}, {0x003E, 6}, {0x00F6, 8}, {0x04ED, 11},
{0x03DC, 10}, {0x273E, 14}, {0x07BA, 11}, {0x09D9, 12},
{0x273F, 14}, {0x3DD8, 14}, {0x3DD9, 14}, {0x3DDA, 14},
{0x3DDB, 14}, {0x3DDC, 14}, {0x3DDD, 14}, {0x3DDE, 14},
{0x3DDF, 14}, {0x003F, 6}, {0x07BC, 11}, {0x07BD, 11},
{0x03DF, 10},
},{//2
{0x0000, 3}, {0x0002, 4}, {0x0006, 5}, {0x000E, 6},
{0x001E, 7}, {0x003E, 8}, {0x003F, 8}, {0x0040, 8},
{0x0104, 10}, {0x0083, 9}, {0x0105, 10}, {0x0108, 10},
{0x4240, 16}, {0x010A, 10}, {0x010B, 10}, {0x4241, 16},
{0x0003, 3}, {0x0009, 5}, {0x0011, 6}, {0x0043, 8},
{0x0004, 3}, {0x000A, 5}, {0x000A, 4}, {0x002C, 7},
{0x00B4, 9}, {0x00B5, 9}, {0x00B6, 9}, {0x00B7, 9},
{0x00B8, 9}, {0x0172, 10}, {0x0173, 10}, {0x0174, 10},
{0x0175, 10}, {0x0176, 10}, {0x0177, 10}, {0x00BC, 9},
{0x017A, 10}, {0x0213, 11}, {0x4242, 16}, {0x017B, 10},
{0x02F8, 11}, {0x017D, 10}, {0x02F9, 11}, {0x017E, 10},
{0x4243, 16}, {0x02FE, 11}, {0x2122, 15}, {0x2123, 15},
{0x0058, 7}, {0x0164, 9}, {0x2124, 15}, {0x2125, 15},
{0x0006, 3}, {0x000E, 4}, {0x002D, 6}, {0x002E, 6},
{0x00B3, 8}, {0x001E, 5}, {0x005E, 7}, {0x2126, 15},
{0x2127, 15}, {0x2128, 15}, {0x2129, 15}, {0x02FF, 11},
{0x212A, 15}, {0x0594, 11}, {0x0595, 11}, {0x0596, 11},
{0x212B, 15}, {0x212C, 15}, {0x212D, 15}, {0x212E, 15},
{0x212F, 15}, {0x001F, 5}, {0x0597, 11}, {0x00BE, 8},
{0x00BF, 8},
},{//3
{0x0000, 2}, {0x0002, 3}, {0x0006, 4}, {0x0007, 4},
{0x0010, 5}, {0x0011, 5}, {0x0024, 6}, {0x0025, 6},
{0x0026, 6}, {0x0027, 6}, {0x0050, 7}, {0x0051, 7},
{0x00A4, 8}, {0x00A5, 8}, {0x00A6, 8}, {0x014E, 9},
{0x000B, 4}, {0x002A, 6}, {0x0056, 7}, {0x014F, 9},
{0x0030, 6}, {0x00AE, 8}, {0x0062, 7}, {0x0032, 6},
{0x0033, 6}, {0x0034, 6}, {0x0035, 6}, {0x0036, 6},
{0x0063, 7}, {0x006E, 7}, {0x006F, 7}, {0x0070, 7},
{0x0071, 7}, {0x0072, 7}, {0x0073, 7}, {0x0074, 7},
{0x00AF, 8}, {0x00EA, 8}, {0x01D6, 9}, {0x075C, 11},
{0x03AF, 10}, {0x75D0, 15}, {0x75D1, 15}, {0x75D2, 15},
{0x75D3, 15}, {0x75D4, 15}, {0x0076, 7}, {0x00EE, 8},
{0x00EF, 8}, {0x0EBB, 12}, {0x01E0, 9}, {0x75D5, 15},
{0x0079, 7}, {0x01E1, 9}, {0x75D6, 15}, {0x75D7, 15},
{0x7880, 15}, {0x00F4, 8}, {0x0789, 11}, {0x003E, 6},
{0x007B, 7}, {0x00F5, 8}, {0x00FC, 8}, {0x007F, 7},
{0x01E3, 9}, {0x078A, 11}, {0x078B, 11}, {0x7881, 15},
{0x7882, 15}, {0x7883, 15}, {0x3C42, 14}, {0x3C43, 14},
{0x3C44, 14}, {0x00FD, 8}, {0x3C45, 14}, {0x3C46, 14},
{0x3C47, 14},
},{//4
{0x0000, 2}, {0x0004, 4}, {0x000A, 5}, {0x0016, 6},
{0x0017, 6}, {0x0030, 7}, {0x0031, 7}, {0x0064, 8},
{0x0065, 8}, {0x0066, 8}, {0x00CE, 9}, {0x00CF, 9},
{0x01A0, 10}, {0x01A1, 10}, {0x1A20, 14}, {0x0689, 12},
{0x0004, 3}, {0x000E, 5}, {0x001B, 6}, {0x0035, 7},
{0x000A, 4}, {0x001E, 6}, {0x0016, 5}, {0x0017, 5},
{0x001F, 6}, {0x0030, 6}, {0x0031, 6}, {0x0064, 7},
{0x0065, 7}, {0x0069, 8}, {0x0066, 7}, {0x00CE, 8},
{0x00CF, 8}, {0x00D0, 8}, {0x00D1, 8}, {0x00D2, 8},
{0x01A6, 9}, {0x01A3, 10}, {0x034E, 10}, {0x006A, 7},
{0x00D6, 8}, {0x01AE, 9}, {0x01AF, 9}, {0x034F, 10},
{0x0345, 11}, {0x01B0, 9}, {0x01B1, 9}, {0x0364, 10},
{0x006D, 7}, {0x00DC, 8}, {0x0D94, 12}, {0x0D95, 12},
{0x000E, 4}, {0x003C, 6}, {0x00DD, 8}, {0x00DE, 8},
{0x01B3, 9}, {0x003D, 6}, {0x00DF, 8}, {0x01F0, 9},
{0x03E2, 10}, {0x03E3, 10}, {0x06CB, 11}, {0x03E4, 10},
{0x07CA, 11}, {0x01F3, 9}, {0x01F4, 9}, {0x07CB, 11},
{0x07D4, 11}, {0x1A21, 14}, {0x1A22, 14}, {0x07D5, 11},
{0x1A23, 14}, {0x003F, 6}, {0x01F6, 9}, {0x01F7, 9},
{0x03EB, 10},
},{//5
{0x0000, 2}, {0x0002, 3}, {0x0006, 4}, {0x000E, 5},
{0x000F, 5}, {0x0020, 6}, {0x0021, 6}, {0x0044, 7},
{0x0045, 7}, {0x0046, 7}, {0x008E, 8}, {0x008F, 8},
{0x0090, 8}, {0x0122, 9}, {0x0246, 10}, {0x0124, 9},
{0x0005, 3}, {0x0013, 5}, {0x004A, 7}, {0x0093, 8},
{0x0018, 5}, {0x004B, 7}, {0x0032, 6}, {0x001A, 5},
{0x0033, 6}, {0x006C, 7}, {0x006D, 7}, {0x006E, 7},
{0x00DE, 8}, {0x00DF, 8}, {0x0070, 7}, {0x00E2, 8},
{0x00E3, 8}, {0x00E4, 8}, {0x00E5, 8}, {0x00E6, 8},
{0x00E7, 8}, {0x0125, 9}, {0x01D0, 9}, {0x048E, 11},
{0x091E, 12}, {0x091F, 12}, {0x7440, 15}, {0x1D11, 13},
{0x7441, 15}, {0x7442, 15}, {0x00E9, 8}, {0x01D4, 9},
{0x00EB, 8}, {0x03A3, 10}, {0x01D5, 9}, {0x1D12, 13},
{0x001E, 5}, {0x0076, 7}, {0x01DC, 9}, {0x01DD, 9},
{0x7443, 15}, {0x007C, 7}, {0x0745, 11}, {0x00EF, 8},
{0x00FA, 8}, {0x00FB, 8}, {0x01F8, 9}, {0x00FD, 8},
{0x07E4, 11}, {0x0FCA, 12}, {0x1D13, 13}, {0x7E58, 15},
{0x7E59, 15}, {0x7E5A, 15}, {0x7E5B, 15}, {0x7E5C, 15},
{0x7E5D, 15}, {0x007F, 7}, {0x3F2F, 14}, {0x07E6, 11},
{0x07E7, 11},
},{//6
{0x0000, 3}, {0x0002, 4}, {0x0003, 4}, {0x0008, 5},
{0x0009, 5}, {0x0014, 6}, {0x0015, 6}, {0x002C, 7},
{0x005A, 8}, {0x005B, 8}, {0x005C, 8}, {0x00BA, 9},
{0x00BB, 9}, {0x00BC, 9}, {0x02F4, 11}, {0x05EA, 12},
{0x0003, 3}, {0x0010, 5}, {0x0022, 6}, {0x0046, 7},
{0x0009, 4}, {0x0028, 6}, {0x0015, 5}, {0x000B, 4},
{0x0018, 5}, {0x0029, 6}, {0x0032, 6}, {0x0047, 7},
{0x0066, 7}, {0x0067, 7}, {0x0068, 7}, {0x0069, 7},
{0x006A, 7}, {0x005F, 8}, {0x00D6, 8}, {0x00D7, 8},
{0x01B0, 9}, {0x00D9, 8}, {0x017B, 10}, {0x006D, 7},
{0x00DC, 8}, {0x01B1, 9}, {0x06E8, 11}, {0x01BB, 9},
{0x0375, 10}, {0x05EB, 12}, {0x01BC, 9}, {0x6E90, 15},
{0x0038, 6}, {0x0072, 7}, {0x6E91, 15}, {0x6E92, 15},
{0x001D, 5}, {0x0073, 7}, {0x01BD, 9}, {0x06F8, 11},
{0x6E93, 15}, {0x003C, 6}, {0x01BF, 9}, {0x00F4, 8},
{0x01EA, 9}, {0x037D, 10}, {0x03D6, 10}, {0x06F9, 11},
{0x6E94, 15}, {0x00F6, 8}, {0x01EE, 9}, {0x6E95, 15},
{0x6E96, 15}, {0x6E97, 15}, {0x374C, 14}, {0x374D, 14},
{0x374E, 14}, {0x001F, 5}, {0x03D7, 10}, {0x01EF, 9},
{0x374F, 14},
},{//7
{0x0000, 2}, {0x0004, 4}, {0x000A, 5}, {0x0016, 6},
{0x002E, 7}, {0x002F, 7}, {0x0060, 8}, {0x0061, 8},
{0x00C4, 9}, {0x00C5, 9}, {0x00C6, 9}, {0x018E, 10},
{0x31E0, 15}, {0x31E1, 15}, {0x31E2, 15}, {0x31E3, 15},
{0x0004, 3}, {0x000D, 5}, {0x0019, 6}, {0x0038, 7},
{0x000A, 4}, {0x001D, 6}, {0x000B, 4}, {0x0072, 8},
{0x0073, 8}, {0x00F0, 9}, {0x01E2, 10}, {0x00F2, 9},
{0x01E3, 10}, {0x00F3, 9}, {0x01E8, 10}, {0x01E9, 10},
{0x31E4, 15}, {0x01EA, 10}, {0x031F, 11}, {0x03D6, 11},
{0x31E5, 15}, {0x01EC, 10}, {0x31E6, 15}, {0x00F7, 9},
{0x03D7, 11}, {0x31E7, 15}, {0x31E8, 15}, {0x03DA, 11},
{0x03DB, 11}, {0x31E9, 15}, {0x03E0, 11}, {0x31EA, 15},
{0x003F, 7}, {0x01F1, 10}, {0x31EB, 15}, {0x31EC, 15},
{0x0006, 3}, {0x001C, 5}, {0x0074, 7}, {0x0075, 7},
{0x00F9, 9}, {0x001E, 5}, {0x0076, 7}, {0x00FA, 9},
{0x03E1, 11}, {0x31ED, 15}, {0x18F7, 14}, {0x1F60, 14},
{0x1F61, 14}, {0x01DC, 9}, {0x01DD, 9}, {0x1F62, 14},
{0x1F63, 14}, {0x1F64, 14}, {0x1F65, 14}, {0x1F66, 14},
{0x1F67, 14}, {0x001F, 5}, {0x03ED, 11}, {0x00EF, 8},
{0x01F7, 10},
}
};
static const uint16_t x8_ac1_highquant_table[8][77][2]={
{//0
{0x0000, 3}, {0x0002, 4}, {0x0006, 5}, {0x0007, 5},
{0x0008, 5}, {0x0009, 5}, {0x0014, 6}, {0x002A, 7},
{0x0016, 6}, {0x002B, 7}, {0x005C, 8}, {0x002F, 7},
{0x0030, 7}, {0x005D, 8}, {0x0062, 8}, {0x00C6, 9},
{0x0007, 4}, {0x0019, 6}, {0x001A, 6}, {0x0036, 7},
{0x0010, 5}, {0x006E, 8}, {0x0022, 6}, {0x0009, 4},
{0x000A, 4}, {0x0016, 5}, {0x0023, 6}, {0x002E, 6},
{0x002F, 6}, {0x0030, 6}, {0x0062, 7}, {0x0063, 7},
{0x0064, 7}, {0x0065, 7}, {0x0066, 7}, {0x0067, 7},
{0x0068, 7}, {0x0069, 7}, {0x006A, 7}, {0x006B, 7},
{0x006C, 7}, {0x00C7, 9}, {0x00DE, 9}, {0x00DF, 9},
{0x06D0, 11}, {0x01B5, 9}, {0x0037, 6}, {0x00DB, 8},
{0x001C, 5}, {0x0074, 7}, {0x01D4, 9}, {0x01D5, 9},
{0x0076, 7}, {0x0369, 10}, {0x3688, 14}, {0x3689, 14},
{0x368A, 14}, {0x0077, 7}, {0x03AC, 10}, {0x0078, 7},
{0x00F2, 8}, {0x01D7, 9}, {0x00F3, 8}, {0x007A, 7},
{0x368B, 14}, {0x007B, 7}, {0x007C, 7}, {0x03AD, 10},
{0x03E8, 10}, {0x368C, 14}, {0x368D, 14}, {0x03E9, 10},
{0x368E, 14}, {0x003F, 6}, {0x01F5, 9}, {0x00FB, 8},
{0x368F, 14},
},{//1
{0x0000, 2}, {0x0004, 4}, {0x000A, 5}, {0x000B, 5},
{0x0018, 6}, {0x0032, 7}, {0x0033, 7}, {0x0034, 7},
{0x006A, 8}, {0x00D6, 9}, {0x00D7, 9}, {0x00D8, 9},
{0x00D9, 9}, {0x3680, 15}, {0x01B5, 10}, {0x0369, 11},
{0x0004, 3}, {0x000E, 5}, {0x001E, 6}, {0x0037, 7},
{0x000A, 4}, {0x0016, 5}, {0x000C, 4}, {0x001F, 6},
{0x005C, 7}, {0x005D, 7}, {0x00BC, 8}, {0x00BD, 8},
{0x005F, 7}, {0x00D0, 8}, {0x00DB, 9}, {0x00D1, 8},
{0x01A4, 9}, {0x01A5, 9}, {0x01A6, 9}, {0x01A7, 9},
{0x0350, 10}, {0x06A2, 11}, {0x06A3, 11}, {0x01A9, 9},
{0x01AA, 9}, {0x06AC, 11}, {0x3681, 15}, {0x0357, 10},
{0x3682, 15}, {0x3683, 15}, {0x3684, 15}, {0x3685, 15},
{0x0036, 6}, {0x00D6, 8}, {0x3686, 15}, {0x3687, 15},
{0x000E, 4}, {0x006E, 7}, {0x00D7, 8}, {0x06AD, 11},
{0x3688, 15}, {0x001E, 5}, {0x00DE, 8}, {0x06F8, 11},
{0x037D, 10}, {0x3689, 15}, {0x368A, 15}, {0x368B, 15},
{0x368C, 15}, {0x01BF, 9}, {0x368D, 15}, {0x1B47, 14},
{0x37C8, 14}, {0x37C9, 14}, {0x37CA, 14}, {0x37CB, 14},
{0x37CC, 14}, {0x001F, 5}, {0x37CD, 14}, {0x37CE, 14},
{0x37CF, 14},
},{//2
{0x0000, 3}, {0x0002, 4}, {0x0003, 4}, {0x0008, 5},
{0x0012, 6}, {0x0026, 7}, {0x0014, 6}, {0x0027, 7},
{0x00A8, 9}, {0x00A9, 9}, {0x0055, 8}, {0x2B00, 15},
{0x00AD, 9}, {0x2B01, 15}, {0x2B02, 15}, {0x2B03, 15},
{0x0003, 3}, {0x000B, 5}, {0x0040, 7}, {0x0041, 7},
{0x0009, 4}, {0x0021, 6}, {0x0011, 5}, {0x000A, 4},
{0x000B, 4}, {0x0018, 5}, {0x0032, 6}, {0x0033, 6},
{0x0034, 6}, {0x0035, 6}, {0x006C, 7}, {0x0057, 8},
{0x006D, 7}, {0x00DC, 8}, {0x0159, 10}, {0x00DD, 8},
{0x01BC, 9}, {0x037A, 10}, {0x037B, 10}, {0x0038, 6},
{0x0072, 7}, {0x01BE, 9}, {0x01BF, 9}, {0x00E6, 8},
{0x039C, 10}, {0x01CF, 9}, {0x2B04, 15}, {0x2B05, 15},
{0x0074, 7}, {0x01D4, 9}, {0x2B06, 15}, {0x2B07, 15},
{0x001E, 5}, {0x00EB, 8}, {0x1584, 14}, {0x1585, 14},
{0x1586, 14}, {0x003B, 6}, {0x01D5, 9}, {0x01F0, 9},
{0x039D, 10}, {0x03E2, 10}, {0x1587, 14}, {0x1588, 14},
{0x1589, 14}, {0x00F9, 8}, {0x158A, 14}, {0x158B, 14},
{0x03E3, 10}, {0x158C, 14}, {0x158D, 14}, {0x01F4, 9},
{0x158E, 14}, {0x003F, 6}, {0x00FB, 8}, {0x01F5, 9},
{0x158F, 14},
},{//3
{0x0000, 3}, {0x0002, 4}, {0x0006, 5}, {0x0007, 5},
{0x0010, 6}, {0x0011, 6}, {0x0024, 7}, {0x0025, 7},
{0x0013, 6}, {0x0014, 6}, {0x002A, 7}, {0x002B, 7},
{0x00B0, 9}, {0x00B1, 9}, {0x002D, 7}, {0x0059, 8},
{0x000C, 5}, {0x0017, 6}, {0x00D0, 9}, {0x0035, 7},
{0x001B, 6}, {0x0038, 7}, {0x0039, 7}, {0x0004, 3},
{0x0005, 3}, {0x000F, 5}, {0x0018, 5}, {0x001D, 6},
{0x0032, 6}, {0x0033, 6}, {0x0068, 7}, {0x0069, 7},
{0x0069, 8}, {0x00D4, 8}, {0x00D5, 8}, {0x00D6, 8},
{0x006C, 7}, {0x0037, 6}, {0x006D, 7}, {0x0070, 7},
{0x0039, 6}, {0x00D7, 8}, {0x00D1, 9}, {0x3880, 14},
{0x3881, 14}, {0x3882, 14}, {0x0074, 7}, {0x01C5, 9},
{0x0075, 7}, {0x00E3, 8}, {0x3883, 14}, {0x3884, 14},
{0x00EC, 8}, {0x3885, 14}, {0x1C43, 13}, {0x1C44, 13},
{0x1C45, 13}, {0x00ED, 8}, {0x1C46, 13}, {0x003C, 6},
{0x0077, 7}, {0x01E8, 9}, {0x003E, 6}, {0x007B, 7},
{0x1C47, 13}, {0x007E, 7}, {0x007F, 7}, {0x1C48, 13},
{0x1C49, 13}, {0x1C4A, 13}, {0x1C4B, 13}, {0x1C4C, 13},
{0x1C4D, 13}, {0x00F5, 8}, {0x1C4E, 13}, {0x01E9, 9},
{0x1C4F, 13},
},{//4
{0x0000, 2}, {0x0004, 4}, {0x000A, 5}, {0x000B, 5},
{0x0018, 6}, {0x0019, 6}, {0x0034, 7}, {0x0035, 7},
{0x0036, 7}, {0x006E, 8}, {0x00DE, 9}, {0x00DF, 9},
{0x01C0, 10}, {0x01C1, 10}, {0x01C2, 10}, {0x3860, 15},
{0x0004, 3}, {0x000F, 5}, {0x001D, 6}, {0x0039, 7},
{0x000A, 4}, {0x002C, 6}, {0x002D, 6}, {0x000C, 4},
{0x0017, 5}, {0x0034, 6}, {0x0035, 6}, {0x0036, 6},
{0x006E, 7}, {0x006F, 7}, {0x0070, 7}, {0x0071, 7},
{0x0071, 8}, {0x00E4, 8}, {0x00E5, 8}, {0x00E6, 8},
{0x00E7, 8}, {0x00E8, 8}, {0x03A4, 10}, {0x0075, 7},
{0x00EC, 8}, {0x01D3, 9}, {0x01DA, 9}, {0x03A5, 10},
{0x03B6, 10}, {0x070D, 12}, {0x03B7, 10}, {0x070E, 12},
{0x003C, 6}, {0x00EE, 8}, {0x3861, 15}, {0x3862, 15},
{0x003D, 6}, {0x01DE, 9}, {0x3863, 15}, {0x3864, 15},
{0x3865, 15}, {0x007C, 7}, {0x070F, 12}, {0x03BE, 10},
{0x03BF, 10}, {0x3866, 15}, {0x0FA0, 12}, {0x07D1, 11},
{0x3867, 15}, {0x00FB, 8}, {0x01F5, 9}, {0x7D08, 15},
{0x0FA4, 12}, {0x7D09, 15}, {0x7D0A, 15}, {0x7D0B, 15},
{0x3E86, 14}, {0x003F, 6}, {0x0FA5, 12}, {0x07D3, 11},
{0x3E87, 14},
},{//5
{0x0000, 3}, {0x0002, 4}, {0x0003, 4}, {0x0008, 5},
{0x0009, 5}, {0x0014, 6}, {0x002A, 7}, {0x0056, 8},
{0x02B8, 11}, {0x00AF, 9}, {0x02B9, 11}, {0x015D, 10},
{0x02C0, 11}, {0x2C10, 15}, {0x2C11, 15}, {0x2C12, 15},
{0x0006, 4}, {0x000E, 5}, {0x0017, 6}, {0x002D, 7},
{0x000F, 5}, {0x0040, 7}, {0x0021, 6}, {0x0005, 3},
{0x0009, 4}, {0x0011, 5}, {0x0018, 5}, {0x0019, 5},
{0x001A, 5}, {0x0036, 6}, {0x0037, 6}, {0x0041, 7},
{0x0059, 8}, {0x00E0, 8}, {0x00E1, 8}, {0x0071, 7},
{0x00E4, 8}, {0x00B1, 9}, {0x02C2, 11}, {0x001D, 5},
{0x0073, 7}, {0x00E5, 8}, {0x00F0, 8}, {0x0079, 7},
{0x03C4, 10}, {0x01E3, 9}, {0x01E8, 9}, {0x2C13, 15},
{0x007B, 7}, {0x2C14, 15}, {0x2C15, 15}, {0x2C16, 15},
{0x007C, 7}, {0x02C3, 11}, {0x2C17, 15}, {0x160C, 14},
{0x160D, 14}, {0x007D, 7}, {0x160E, 14}, {0x01E9, 9},
{0x03C5, 10}, {0x03D4, 10}, {0x01EB, 9}, {0x160F, 14},
{0x3D50, 14}, {0x00FC, 8}, {0x07AB, 11}, {0x3D51, 14},
{0x3D52, 14}, {0x3D53, 14}, {0x3D54, 14}, {0x01FA, 9},
{0x3D55, 14}, {0x007F, 7}, {0x01FB, 9}, {0x3D56, 14},
{0x3D57, 14},
},{//6
{0x0000, 3}, {0x0002, 4}, {0x0003, 4}, {0x0008, 5},
{0x0009, 5}, {0x000A, 5}, {0x000B, 5}, {0x0018, 6},
{0x0032, 7}, {0x000D, 5}, {0x0033, 7}, {0x0E00, 13},
{0x0039, 7}, {0x0E01, 13}, {0x003A, 7}, {0x0E02, 13},
{0x0008, 4}, {0x001E, 6}, {0x003B, 7}, {0x003E, 7},
{0x0012, 5}, {0x003F, 7}, {0x0013, 5}, {0x0028, 6},
{0x0029, 6}, {0x0054, 7}, {0x002B, 6}, {0x0055, 7},
{0x0058, 7}, {0x0E03, 13}, {0x0059, 7}, {0x005A, 7},
{0x0E04, 13}, {0x0E05, 13}, {0x0703, 12}, {0x005B, 7},
{0x005C, 7}, {0x0704, 12}, {0x0705, 12}, {0x005D, 7},
{0x0706, 12}, {0x0707, 12}, {0x0708, 12}, {0x0709, 12},
{0x070A, 12}, {0x070B, 12}, {0x0018, 5}, {0x002F, 6},
{0x000D, 4}, {0x0019, 5}, {0x070C, 12}, {0x0070, 7},
{0x001D, 5}, {0x070D, 12}, {0x070E, 12}, {0x070F, 12},
{0x0710, 12}, {0x0039, 6}, {0x0711, 12}, {0x003C, 6},
{0x0712, 12}, {0x0713, 12}, {0x0714, 12}, {0x0715, 12},
{0x0716, 12}, {0x003D, 6}, {0x0717, 12}, {0x0718, 12},
{0x0719, 12}, {0x071A, 12}, {0x071B, 12}, {0x071C, 12},
{0x071D, 12}, {0x001F, 5}, {0x071E, 12}, {0x0071, 7},
{0x071F, 12},
},{//7
{0x0000, 3}, {0x0002, 4}, {0x0006, 5}, {0x000E, 6},
{0x000F, 6}, {0x0040, 8}, {0x0041, 8}, {0x0042, 8},
{0x0218, 11}, {0x2190, 15}, {0x2191, 15}, {0x2192, 15},
{0x2193, 15}, {0x2194, 15}, {0x2195, 15}, {0x2196, 15},
{0x0005, 4}, {0x0011, 6}, {0x0024, 7}, {0x0087, 9},
{0x000C, 5}, {0x004A, 8}, {0x004B, 8}, {0x0002, 2},
{0x0006, 3}, {0x000D, 5}, {0x000E, 5}, {0x000F, 5},
{0x0013, 6}, {0x0038, 6}, {0x00E4, 8}, {0x00E5, 8},
{0x01CC, 9}, {0x00E7, 8}, {0x0074, 7}, {0x00EA, 8},
{0x01CD, 9}, {0x021A, 11}, {0x2197, 15}, {0x001E, 5},
{0x0076, 7}, {0x00EB, 8}, {0x01DC, 9}, {0x00EF, 8},
{0x01DD, 9}, {0x01F0, 9}, {0x2198, 15}, {0x2199, 15},
{0x00F9, 8}, {0x03E2, 10}, {0x219A, 15}, {0x219B, 15},
{0x00FA, 8}, {0x219C, 15}, {0x219D, 15}, {0x219E, 15},
{0x219F, 15}, {0x01F6, 9}, {0x21B0, 15}, {0x00FC, 8},
{0x01F7, 9}, {0x21B1, 15}, {0x21B2, 15}, {0x21B3, 15},
{0x21B4, 15}, {0x01FA, 9}, {0x21B5, 15}, {0x21B6, 15},
{0x21B7, 15}, {0x21B8, 15}, {0x21B9, 15}, {0x03E3, 10},
{0x10DD, 14}, {0x007F, 7}, {0x01FB, 9}, {0x10DE, 14},
{0x10DF, 14},
}
};
#define MAX_AC_VLC_BITS 16
#endif /* FFMPEG_INTRAX8HUF_H */