nengel@2: /* nengel@2: * DSP utils nengel@2: * Copyright (c) 2000, 2001, 2002 Fabrice Bellard nengel@2: * Copyright (c) 2002-2004 Michael Niedermayer nengel@2: * nengel@2: * This file is part of FFmpeg. nengel@2: * nengel@2: * FFmpeg is free software; you can redistribute it and/or nengel@2: * modify it under the terms of the GNU Lesser General Public nengel@2: * License as published by the Free Software Foundation; either nengel@2: * version 2.1 of the License, or (at your option) any later version. nengel@2: * nengel@2: * FFmpeg is distributed in the hope that it will be useful, nengel@2: * but WITHOUT ANY WARRANTY; without even the implied warranty of nengel@2: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU nengel@2: * Lesser General Public License for more details. nengel@2: * nengel@2: * You should have received a copy of the GNU Lesser General Public nengel@2: * License along with FFmpeg; if not, write to the Free Software nengel@2: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA nengel@2: */ nengel@2: nengel@2: /** nengel@2: * @file nengel@2: * DSP utils. nengel@2: * note, many functions in here may use MMX which trashes the FPU state, it is nengel@2: * absolutely necessary to call emms_c() between dsp & float/double code nengel@2: */ nengel@2: nengel@2: #ifndef AVCODEC_DSPUTIL_H nengel@2: #define AVCODEC_DSPUTIL_H nengel@2: nengel@2: #include "libavutil/intreadwrite.h" nengel@2: #include "avcodec.h" nengel@2: #include "h264_idct.h" nengel@2: // nengel@2: void ff_vector_fmul_window_c(float *dst, const float *src0, const float *src1, nengel@2: const float *win, float add_bias, int len); nengel@2: void ff_float_to_int16_c(int16_t *dst, const float *src, long len); nengel@2: void ff_float_to_int16_interleave_c(int16_t *dst, const float **src, long len, int channels); nengel@2: nengel@2: /* encoding scans */ nengel@2: extern const uint8_t ff_alternate_horizontal_scan[64]; nengel@2: extern const uint8_t ff_alternate_vertical_scan[64]; nengel@2: extern const uint8_t ff_zigzag_direct[64]; nengel@2: extern const uint8_t ff_zigzag248_direct[64]; nengel@2: nengel@2: /* pixel operations */ nengel@2: #define MAX_NEG_CROP 1024 nengel@2: nengel@2: /* temporary */ nengel@2: extern uint32_t ff_squareTbl[512]; nengel@2: extern uint8_t ff_cropTbl[256 + 2 * MAX_NEG_CROP]; nengel@2: nengel@2: /* VP3 DSP functions */ nengel@2: void ff_vp3_idct_c(DCTELEM *block/* align 16*/); nengel@2: void ff_vp3_idct_put_c(uint8_t *dest/*align 8*/, int line_size, DCTELEM *block/*align 16*/); nengel@2: void ff_vp3_idct_add_c(uint8_t *dest/*align 8*/, int line_size, DCTELEM *block/*align 16*/); nengel@2: void ff_vp3_idct_dc_add_c(uint8_t *dest/*align 8*/, int line_size, const DCTELEM *block/*align 16*/); nengel@2: nengel@2: void ff_vp3_v_loop_filter_c(uint8_t *src, int stride, int *bounding_values); nengel@2: void ff_vp3_h_loop_filter_c(uint8_t *src, int stride, int *bounding_values); nengel@2: nengel@2: /* VP6 DSP functions */ nengel@2: void ff_vp6_filter_diag4_c(uint8_t *dst, uint8_t *src, int stride, nengel@2: const int16_t *h_weights, const int16_t *v_weights); nengel@2: nengel@2: /* Bink functions */ nengel@2: void ff_bink_idct_c (DCTELEM *block); nengel@2: void ff_bink_idct_add_c(uint8_t *dest, int linesize, DCTELEM *block); nengel@2: void ff_bink_idct_put_c(uint8_t *dest, int linesize, DCTELEM *block); nengel@2: nengel@2: /* CAVS functions */ nengel@2: void ff_put_cavs_qpel8_mc00_c(uint8_t *dst, uint8_t *src, int stride); nengel@2: void ff_avg_cavs_qpel8_mc00_c(uint8_t *dst, uint8_t *src, int stride); nengel@2: void ff_put_cavs_qpel16_mc00_c(uint8_t *dst, uint8_t *src, int stride); nengel@2: void ff_avg_cavs_qpel16_mc00_c(uint8_t *dst, uint8_t *src, int stride); nengel@2: nengel@2: /* VC1 functions */ nengel@2: void ff_put_vc1_mspel_mc00_c(uint8_t *dst, const uint8_t *src, int stride, int rnd); nengel@2: void ff_avg_vc1_mspel_mc00_c(uint8_t *dst, const uint8_t *src, int stride, int rnd); nengel@2: nengel@2: /* EA functions */ nengel@2: void ff_ea_idct_put_c(uint8_t *dest, int linesize, DCTELEM *block); nengel@2: nengel@2: /* 1/2^n downscaling functions from imgconvert.c */ nengel@2: void ff_img_copy_plane(uint8_t *dst, int dst_wrap, const uint8_t *src, int src_wrap, int width, int height); nengel@2: void ff_shrink22(uint8_t *dst, int dst_wrap, const uint8_t *src, int src_wrap, int width, int height); nengel@2: void ff_shrink44(uint8_t *dst, int dst_wrap, const uint8_t *src, int src_wrap, int width, int height); nengel@2: void ff_shrink88(uint8_t *dst, int dst_wrap, const uint8_t *src, int src_wrap, int width, int height); nengel@2: nengel@2: void ff_gmc_c(uint8_t *dst, uint8_t *src, int stride, int h, int ox, int oy, nengel@2: int dxx, int dxy, int dyx, int dyy, int shift, int r, int width, int height); nengel@2: nengel@2: /* minimum alignment rules ;) nengel@2: If you notice errors in the align stuff, need more alignment for some ASM code nengel@2: for some CPU or need to use a function with less aligned data then send a mail nengel@2: to the ffmpeg-devel mailing list, ... nengel@2: nengel@2: !warning These alignments might not match reality, (missing attribute((align)) nengel@2: stuff somewhere possible). nengel@2: I (Michael) did not check them, these are just the alignments which I think nengel@2: could be reached easily ... nengel@2: nengel@2: !future video codecs might need functions with less strict alignment nengel@2: */ nengel@2: nengel@2: /* nengel@2: void get_pixels_c(DCTELEM *block, const uint8_t *pixels, int line_size); nengel@2: void diff_pixels_c(DCTELEM *block, const uint8_t *s1, const uint8_t *s2, int stride); nengel@2: void put_pixels_clamped_c(const DCTELEM *block, uint8_t *pixels, int line_size); nengel@2: void add_pixels_clamped_c(const DCTELEM *block, uint8_t *pixels, int line_size); nengel@2: void clear_blocks_c(DCTELEM *blocks); nengel@2: */ nengel@2: nengel@2: /* add and put pixel (decoding) */ nengel@2: // blocksizes for op_pixels_func are 8x4,8x8 16x8 16x16 nengel@2: //h for op_pixels_func is limited to {width/2, width} but never larger than 16 and never smaller then 4 nengel@2: typedef void (*op_pixels_func)(uint8_t *block/*align width (8 or 16)*/, const uint8_t *pixels/*align 1*/, int line_size, int h); nengel@2: typedef void (*tpel_mc_func)(uint8_t *block/*align width (8 or 16)*/, const uint8_t *pixels/*align 1*/, int line_size, int w, int h); nengel@2: typedef void (*qpel_mc_func)(uint8_t *dst/*align width (8 or 16)*/, uint8_t *src/*align 1*/, int stride); nengel@2: typedef void (*h264_chroma_mc_func)(uint8_t *dst/*align 8*/, uint8_t *src/*align 1*/, int srcStride, int h, int x, int y); nengel@2: nengel@2: typedef void (*op_fill_func)(uint8_t *block/*align width (8 or 16)*/, uint8_t value, int line_size, int h); nengel@2: nengel@2: #define DEF_OLD_QPEL(name)\ nengel@2: void ff_put_ ## name (uint8_t *dst/*align width (8 or 16)*/, uint8_t *src/*align 1*/, int stride);\ nengel@2: void ff_put_no_rnd_ ## name (uint8_t *dst/*align width (8 or 16)*/, uint8_t *src/*align 1*/, int stride);\ nengel@2: void ff_avg_ ## name (uint8_t *dst/*align width (8 or 16)*/, uint8_t *src/*align 1*/, int stride); nengel@2: nengel@2: DEF_OLD_QPEL(qpel16_mc11_old_c) nengel@2: DEF_OLD_QPEL(qpel16_mc31_old_c) nengel@2: DEF_OLD_QPEL(qpel16_mc12_old_c) nengel@2: DEF_OLD_QPEL(qpel16_mc32_old_c) nengel@2: DEF_OLD_QPEL(qpel16_mc13_old_c) nengel@2: DEF_OLD_QPEL(qpel16_mc33_old_c) nengel@2: DEF_OLD_QPEL(qpel8_mc11_old_c) nengel@2: DEF_OLD_QPEL(qpel8_mc31_old_c) nengel@2: DEF_OLD_QPEL(qpel8_mc12_old_c) nengel@2: DEF_OLD_QPEL(qpel8_mc32_old_c) nengel@2: DEF_OLD_QPEL(qpel8_mc13_old_c) nengel@2: DEF_OLD_QPEL(qpel8_mc33_old_c) nengel@2: nengel@2: #define CALL_2X_PIXELS(a, b, n)\ nengel@2: static void a(uint8_t *block, const uint8_t *pixels, int line_size, int h){\ nengel@2: b(block , pixels , line_size, h);\ nengel@2: b(block+n, pixels+n, line_size, h);\ nengel@2: } nengel@2: nengel@2: /* motion estimation */ nengel@2: // h is limited to {width/2, width, 2*width} but never larger than 16 and never smaller then 2 nengel@2: // although currently h<4 is not used as functions with width <8 are neither used nor implemented nengel@2: typedef int (*me_cmp_func)(void /*MpegEncContext*/ *s, uint8_t *blk1/*align width (8 or 16)*/, uint8_t *blk2/*align 1*/, int line_size, int h)/* __attribute__ ((const))*/; nengel@2: nengel@2: /** nengel@2: * Scantable. nengel@2: */ nengel@2: typedef struct ScanTable{ nengel@2: const uint8_t *scantable; nengel@2: uint8_t permutated[64]; nengel@2: uint8_t raster_end[64]; nengel@2: #if ARCH_PPC nengel@2: /** Used by dct_quantize_altivec to find last-non-zero */ nengel@2: DECLARE_ALIGNED(16, uint8_t, inverse)[64]; nengel@2: #endif nengel@2: } ScanTable; nengel@2: nengel@2: void ff_init_scantable(uint8_t *, ScanTable *st, const uint8_t *src_scantable); nengel@2: nengel@2: void ff_emulated_edge_mc(uint8_t *buf, uint8_t *src, int linesize, nengel@2: int block_w, int block_h, nengel@2: int src_x, int src_y, int w, int h); nengel@2: nengel@2: nengel@2: /** nengel@2: * DSPContext. nengel@2: */ nengel@2: typedef struct DSPContext { nengel@2: /* pixel ops : interface with DCT */ nengel@2: void (*get_pixels)(DCTELEM *block/*align 16*/, const uint8_t *pixels/*align 8*/, int line_size); nengel@2: void (*diff_pixels)(DCTELEM *block/*align 16*/, const uint8_t *s1/*align 8*/, const uint8_t *s2/*align 8*/, int stride); nengel@2: void (*put_pixels_clamped)(const DCTELEM *block/*align 16*/, uint8_t *pixels/*align 8*/, int line_size); nengel@2: void (*put_signed_pixels_clamped)(const DCTELEM *block/*align 16*/, uint8_t *pixels/*align 8*/, int line_size); nengel@2: void (*put_pixels_nonclamped)(const DCTELEM *block/*align 16*/, uint8_t *pixels/*align 8*/, int line_size); nengel@2: void (*add_pixels_clamped)(const DCTELEM *block/*align 16*/, uint8_t *pixels/*align 8*/, int line_size); nengel@2: void (*add_pixels8)(uint8_t *pixels, DCTELEM *block, int line_size); nengel@2: void (*add_pixels4)(uint8_t *pixels, DCTELEM *block, int line_size); nengel@2: nengel@2: void (*clear_block)(DCTELEM *block/*align 16*/); nengel@2: void (*clear_blocks)(DCTELEM *blocks/*align 16*/); nengel@2: nengel@2: nengel@2: /** nengel@2: * Halfpel motion compensation with rounding (a+b+1)>>1. nengel@2: * this is an array[4][4] of motion compensation functions for 4 nengel@2: * horizontal blocksizes (8,16) and the 4 halfpel positions
nengel@2: * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] nengel@2: * @param block destination where the result is stored nengel@2: * @param pixels source nengel@2: * @param line_size number of bytes in a horizontal line of block nengel@2: * @param h height nengel@2: */ nengel@2: op_pixels_func put_pixels_tab[4][4]; nengel@2: nengel@2: /** nengel@2: * Halfpel motion compensation with rounding (a+b+1)>>1. nengel@2: * This is an array[4][4] of motion compensation functions for 4 nengel@2: * horizontal blocksizes (8,16) and the 4 halfpel positions
nengel@2: * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] nengel@2: * @param block destination into which the result is averaged (a+b+1)>>1 nengel@2: * @param pixels source nengel@2: * @param line_size number of bytes in a horizontal line of block nengel@2: * @param h height nengel@2: */ nengel@2: op_pixels_func avg_pixels_tab[4][4]; nengel@2: nengel@2: /** nengel@2: * Halfpel motion compensation with no rounding (a+b)>>1. nengel@2: * this is an array[2][4] of motion compensation functions for 2 nengel@2: * horizontal blocksizes (8,16) and the 4 halfpel positions
nengel@2: * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] nengel@2: * @param block destination where the result is stored nengel@2: * @param pixels source nengel@2: * @param line_size number of bytes in a horizontal line of block nengel@2: * @param h height nengel@2: */ nengel@2: op_pixels_func put_no_rnd_pixels_tab[4][4]; nengel@2: nengel@2: /** nengel@2: * Halfpel motion compensation with no rounding (a+b)>>1. nengel@2: * this is an array[2][4] of motion compensation functions for 2 nengel@2: * horizontal blocksizes (8,16) and the 4 halfpel positions
nengel@2: * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] nengel@2: * @param block destination into which the result is averaged (a+b)>>1 nengel@2: * @param pixels source nengel@2: * @param line_size number of bytes in a horizontal line of block nengel@2: * @param h height nengel@2: */ nengel@2: op_pixels_func avg_no_rnd_pixels_tab[4][4]; nengel@2: nengel@2: void (*put_no_rnd_pixels_l2[2])(uint8_t *block/*align width (8 or 16)*/, const uint8_t *a/*align 1*/, const uint8_t *b/*align 1*/, int line_size, int h); nengel@2: nengel@2: nengel@2: qpel_mc_func put_qpel_pixels_tab[2][16]; nengel@2: qpel_mc_func avg_qpel_pixels_tab[2][16]; nengel@2: qpel_mc_func put_no_rnd_qpel_pixels_tab[2][16]; nengel@2: qpel_mc_func avg_no_rnd_qpel_pixels_tab[2][16]; nengel@2: qpel_mc_func put_mspel_pixels_tab[8]; nengel@2: nengel@2: /** nengel@2: * h264 Chroma MC nengel@2: */ nengel@2: h264_chroma_mc_func put_h264_chroma_pixels_tab[3]; nengel@2: h264_chroma_mc_func avg_h264_chroma_pixels_tab[3]; nengel@2: /* This is really one func used in VC-1 decoding */ nengel@2: h264_chroma_mc_func put_no_rnd_vc1_chroma_pixels_tab[3]; nengel@2: h264_chroma_mc_func avg_no_rnd_vc1_chroma_pixels_tab[3]; nengel@2: nengel@2: qpel_mc_func put_h264_qpel_pixels_tab[4][16]; nengel@2: qpel_mc_func avg_h264_qpel_pixels_tab[4][16]; nengel@2: nengel@2: qpel_mc_func put_2tap_qpel_pixels_tab[4][16]; nengel@2: qpel_mc_func avg_2tap_qpel_pixels_tab[4][16]; nengel@2: nengel@2: nengel@2: /* (I)DCT */ nengel@2: void (*fdct)(DCTELEM *block/* align 16*/); nengel@2: void (*fdct248)(DCTELEM *block/* align 16*/); nengel@2: nengel@2: /* IDCT really*/ nengel@2: void (*idct)(DCTELEM *block/* align 16*/); nengel@2: nengel@2: /** nengel@2: * block -> idct -> clip to unsigned 8 bit -> dest. nengel@2: * (-1392, 0, 0, ...) -> idct -> (-174, -174, ...) -> put -> (0, 0, ...) nengel@2: * @param line_size size in bytes of a horizontal line of dest nengel@2: */ nengel@2: void (*idct_put)(uint8_t *dest/*align 8*/, int line_size, DCTELEM *block/*align 16*/); nengel@2: nengel@2: /** nengel@2: * block -> idct -> add dest -> clip to unsigned 8 bit -> dest. nengel@2: * @param line_size size in bytes of a horizontal line of dest nengel@2: */ nengel@2: void (*idct_add)(uint8_t *dest/*align 8*/, int line_size, DCTELEM *block/*align 16*/); nengel@2: nengel@2: void (*draw_edges)(uint8_t *buf, int wrap, int width, int height, int w); nengel@2: #define EDGE_WIDTH 32 nengel@2: nengel@2: void (*prefetch)(void *mem, int stride, int h); nengel@2: nengel@2: } DSPContext; nengel@2: nengel@2: void dsputil_static_init(void); nengel@2: void dsputil_init(DSPContext* p); nengel@2: nengel@2: int ff_check_alignment(void); nengel@2: nengel@2: /** nengel@2: * permute block according to permuatation. nengel@2: * @param last last non zero element in scantable order nengel@2: */ nengel@2: void ff_block_permute(DCTELEM *block, uint8_t *permutation, const uint8_t *scantable, int last); nengel@2: nengel@2: void ff_set_cmp(DSPContext* c, me_cmp_func *cmp, int type); nengel@2: nengel@2: #define BYTE_VEC32(c) ((c)*0x01010101UL) nengel@2: nengel@2: static inline uint32_t rnd_avg32(uint32_t a, uint32_t b) nengel@2: { nengel@2: return (a | b) - (((a ^ b) & ~BYTE_VEC32(0x01)) >> 1); nengel@2: } nengel@2: nengel@2: static inline uint32_t no_rnd_avg32(uint32_t a, uint32_t b) nengel@2: { nengel@2: return (a & b) + (((a ^ b) & ~BYTE_VEC32(0x01)) >> 1); nengel@2: } nengel@2: nengel@2: nengel@2: /** nengel@2: * Empty mmx state. nengel@2: * this must be called between any dsp function and float/double code. nengel@2: * for example sin(); dsp->idct_put(); emms_c(); cos() nengel@2: */ nengel@2: #define emms_c() nengel@2: nengel@2: /* should be defined by architectures supporting nengel@2: one or more MultiMedia extension */ nengel@2: int mm_support(void); nengel@2: extern int mm_flags; nengel@2: nengel@2: void dsputil_init_arm(DSPContext* c); nengel@2: void dsputil_init_mmx(DSPContext* c); nengel@2: void dsputil_init_ppc(DSPContext* c); nengel@2: nengel@2: void ff_dsputil_init_dwt(DSPContext *c); nengel@2: nengel@2: #if HAVE_MMX nengel@2: nengel@2: #undef emms_c nengel@2: nengel@2: static inline void emms(void) nengel@2: { nengel@2: __asm__ volatile ("emms;":::"memory"); nengel@2: } nengel@2: nengel@2: nengel@2: #define emms_c() \ nengel@2: {\ nengel@2: if (mm_flags & FF_MM_MMX)\ nengel@2: emms();\ nengel@2: } nengel@2: nengel@2: #elif ARCH_ARM nengel@2: nengel@2: #if HAVE_NEON nengel@2: # define STRIDE_ALIGN 16 nengel@2: #endif nengel@2: nengel@2: #elif ARCH_PPC || ARCH_PPC64 || ARCH_CELL nengel@2: nengel@2: #define STRIDE_ALIGN 16 nengel@2: nengel@2: #endif nengel@2: nengel@2: #ifndef STRIDE_ALIGN nengel@2: # define STRIDE_ALIGN 8 nengel@2: #endif nengel@2: nengel@2: #define WRAPPER8_16(name8, name16)\ nengel@2: static int name16(void /*MpegEncContext*/ *s, uint8_t *dst, uint8_t *src, int stride, int h){\ nengel@2: return name8(s, dst , src , stride, h)\ nengel@2: +name8(s, dst+8 , src+8 , stride, h);\ nengel@2: } nengel@2: nengel@2: #define WRAPPER8_16_SQ(name8, name16)\ nengel@2: static int name16(void /*MpegEncContext*/ *s, uint8_t *dst, uint8_t *src, int stride, int h){\ nengel@2: int score=0;\ nengel@2: score +=name8(s, dst , src , stride, 8);\ nengel@2: score +=name8(s, dst+8 , src+8 , stride, 8);\ nengel@2: if(h==16){\ nengel@2: dst += 8*stride;\ nengel@2: src += 8*stride;\ nengel@2: score +=name8(s, dst , src , stride, 8);\ nengel@2: score +=name8(s, dst+8 , src+8 , stride, 8);\ nengel@2: }\ nengel@2: return score;\ nengel@2: } nengel@2: nengel@2: static inline void copy_block2(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h) nengel@2: { nengel@2: int i; nengel@2: for(i=0; i