From 159a7ec14f3aae0814ec57e3d61eb4458078c6a2 Mon Sep 17 00:00:00 2001 From: giongto35 Date: Thu, 12 Sep 2019 04:06:26 +0800 Subject: [PATCH] Add C vendor --- .../x264/common/aarch64/asm-offsets.c | 42 + .../x264/common/aarch64/asm-offsets.h | 39 + .../x264c/external/x264/common/aarch64/dct.h | 67 + .../x264c/external/x264/common/aarch64/mc-c.c | 281 ++ .../x264c/external/x264/common/aarch64/mc.h | 31 + .../external/x264/common/aarch64/pixel.h | 79 + .../external/x264/common/aarch64/predict-c.c | 139 + .../external/x264/common/aarch64/predict.h | 58 + .../external/x264/common/aarch64/quant.h | 59 + .../x264c/external/x264/common/arm/dct.h | 53 + .../x264c/external/x264/common/arm/mc-c.c | 310 ++ .../x264c/external/x264/common/arm/mc.h | 31 + .../x264c/external/x264/common/arm/pixel.h | 81 + .../external/x264/common/arm/predict-c.c | 108 + .../x264c/external/x264/common/arm/predict.h | 70 + .../x264c/external/x264/common/arm/quant.h | 53 + .../x264c/external/x264/common/bitstream.c | 176 + .../x264c/external/x264/common/bitstream.h | 312 ++ .../x264c/external/x264/common/cabac.c | 1485 ++++++ .../x264c/external/x264/common/cabac.h | 118 + .../x264c/external/x264/common/common.c | 1446 ++++++ .../x264c/external/x264/common/common.h | 1022 ++++ .../x264-go/x264c/external/x264/common/cpu.c | 490 ++ .../x264-go/x264c/external/x264/common/cpu.h | 73 + .../x264-go/x264c/external/x264/common/dct.c | 1155 +++++ .../x264-go/x264c/external/x264/common/dct.h | 80 + .../x264c/external/x264/common/deblock.c | 908 ++++ .../x264c/external/x264/common/frame.c | 899 ++++ .../x264c/external/x264/common/frame.h | 262 + .../x264c/external/x264/common/macroblock.c | 1914 +++++++ .../x264c/external/x264/common/macroblock.h | 444 ++ .../x264-go/x264c/external/x264/common/mc.c | 779 +++ .../x264-go/x264c/external/x264/common/mc.h | 340 ++ .../x264c/external/x264/common/mvpred.c | 607 +++ .../x264c/external/x264/common/opencl.c | 719 +++ .../x264c/external/x264/common/opencl.h | 804 +++ .../x264c/external/x264/common/osdep.c | 206 + .../x264c/external/x264/common/osdep.h | 414 ++ .../x264c/external/x264/common/pixel.c | 1522 ++++++ .../x264c/external/x264/common/pixel.h | 155 + .../x264c/external/x264/common/predict.c | 1054 ++++ .../x264c/external/x264/common/predict.h | 138 + .../x264c/external/x264/common/quant.c | 830 +++ .../x264c/external/x264/common/quant.h | 74 + .../x264c/external/x264/common/rectangle.c | 58 + .../x264c/external/x264/common/rectangle.h | 157 + .../x264-go/x264c/external/x264/common/set.c | 379 ++ .../x264-go/x264c/external/x264/common/set.h | 347 ++ .../x264c/external/x264/common/threadpool.c | 164 + .../x264c/external/x264/common/threadpool.h | 44 + .../x264-go/x264c/external/x264/common/vlc.c | 869 ++++ .../x264c/external/x264/common/win32thread.c | 357 ++ .../x264c/external/x264/common/win32thread.h | 81 + .../x264c/external/x264/common/x86/dct.h | 144 + .../x264c/external/x264/common/x86/mc-c.c | 911 ++++ .../x264c/external/x264/common/x86/mc.h | 32 + .../x264c/external/x264/common/x86/pixel.h | 220 + .../external/x264/common/x86/predict-c.c | 609 +++ .../x264c/external/x264/common/x86/predict.h | 144 + .../x264c/external/x264/common/x86/quant.h | 156 + .../x264c/external/x264/common/x86/util.h | 254 + .../x264c/external/x264/encoder/analyse.c | 4009 +++++++++++++++ .../x264c/external/x264/encoder/analyse.h | 44 + .../x264c/external/x264/encoder/cabac.c | 1284 +++++ .../x264c/external/x264/encoder/cavlc.c | 722 +++ .../x264c/external/x264/encoder/encoder.c | 4429 +++++++++++++++++ .../x264c/external/x264/encoder/lookahead.c | 244 + .../x264c/external/x264/encoder/macroblock.c | 1419 ++++++ .../x264c/external/x264/encoder/macroblock.h | 198 + .../x264-go/x264c/external/x264/encoder/me.c | 1350 +++++ .../x264-go/x264c/external/x264/encoder/me.h | 104 + .../x264c/external/x264/encoder/ratecontrol.c | 3104 ++++++++++++ .../x264c/external/x264/encoder/ratecontrol.h | 66 + .../x264-go/x264c/external/x264/encoder/rdo.c | 1165 +++++ .../x264-go/x264c/external/x264/encoder/set.c | 853 ++++ .../x264-go/x264c/external/x264/encoder/set.h | 47 + .../external/x264/encoder/slicetype-cl.c | 780 +++ .../x264c/external/x264/encoder/slicetype.c | 2033 ++++++++ .../x264-go/x264c/external/x264/x264.h | 964 ++++ vendor/golang.org/x/sys/windows/svc/go12.c | 24 + 80 files changed, 47692 insertions(+) create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/asm-offsets.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/asm-offsets.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/dct.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/mc-c.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/mc.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/pixel.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/predict-c.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/predict.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/quant.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/dct.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/mc-c.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/mc.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/pixel.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/predict-c.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/predict.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/quant.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/bitstream.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/bitstream.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cabac.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cabac.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/common.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/common.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cpu.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cpu.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/dct.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/dct.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/deblock.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/frame.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/frame.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/macroblock.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/macroblock.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mc.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mc.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mvpred.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/opencl.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/opencl.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/osdep.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/osdep.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/pixel.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/pixel.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/predict.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/predict.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/quant.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/quant.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/rectangle.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/rectangle.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/set.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/set.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/threadpool.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/threadpool.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/vlc.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/win32thread.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/win32thread.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/dct.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/mc-c.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/mc.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/pixel.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/predict-c.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/predict.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/quant.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/util.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/analyse.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/analyse.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/cabac.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/cavlc.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/encoder.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/lookahead.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/macroblock.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/macroblock.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/me.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/me.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/ratecontrol.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/ratecontrol.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/rdo.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/set.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/set.h create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/slicetype-cl.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/slicetype.c create mode 100644 vendor/github.com/gen2brain/x264-go/x264c/external/x264/x264.h create mode 100644 vendor/golang.org/x/sys/windows/svc/go12.c diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/asm-offsets.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/asm-offsets.c new file mode 100644 index 00000000..c52db98a --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/asm-offsets.c @@ -0,0 +1,42 @@ +/***************************************************************************** + * asm-offsets.c: check asm offsets for aarch64 + ***************************************************************************** + * Copyright (C) 2014-2017 x264 project + * + * Authors: Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "asm-offsets.h" + +#define X264_CHECK_OFFSET(s, m, o) struct check_##s##_##m \ +{ \ + int m_##m[2 * (offsetof(s, m) == o) - 1]; \ +} + +X264_CHECK_OFFSET(x264_cabac_t, i_low, CABAC_I_LOW); +X264_CHECK_OFFSET(x264_cabac_t, i_range, CABAC_I_RANGE); +X264_CHECK_OFFSET(x264_cabac_t, i_queue, CABAC_I_QUEUE); +X264_CHECK_OFFSET(x264_cabac_t, i_bytes_outstanding, CABAC_I_BYTES_OUTSTANDING); +X264_CHECK_OFFSET(x264_cabac_t, p_start, CABAC_P_START); +X264_CHECK_OFFSET(x264_cabac_t, p, CABAC_P); +X264_CHECK_OFFSET(x264_cabac_t, p_end, CABAC_P_END); +X264_CHECK_OFFSET(x264_cabac_t, f8_bits_encoded, CABAC_F8_BITS_ENCODED); +X264_CHECK_OFFSET(x264_cabac_t, state, CABAC_STATE); diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/asm-offsets.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/asm-offsets.h new file mode 100644 index 00000000..3b02f9ef --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/asm-offsets.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * asm-offsets.h: asm offsets for aarch64 + ***************************************************************************** + * Copyright (C) 2014-2017 x264 project + * + * Authors: Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_AARCH64_ASM_OFFSETS_H +#define X264_AARCH64_ASM_OFFSETS_H + +#define CABAC_I_LOW 0x00 +#define CABAC_I_RANGE 0x04 +#define CABAC_I_QUEUE 0x08 +#define CABAC_I_BYTES_OUTSTANDING 0x0c +#define CABAC_P_START 0x10 +#define CABAC_P 0x18 +#define CABAC_P_END 0x20 +#define CABAC_F8_BITS_ENCODED 0x30 +#define CABAC_STATE 0x34 + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/dct.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/dct.h new file mode 100644 index 00000000..095f4ab5 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/dct.h @@ -0,0 +1,67 @@ +/***************************************************************************** + * dct.h: aarch64 transform and zigzag + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_AARCH64_DCT_H +#define X264_AARCH64_DCT_H + +void x264_dct4x4dc_neon( int16_t d[16] ); +void x264_idct4x4dc_neon( int16_t d[16] ); + +void x264_sub4x4_dct_neon( int16_t dct[16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_neon( int16_t dct[4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct_neon( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); + +void x264_add4x4_idct_neon( uint8_t *p_dst, int16_t dct[16] ); +void x264_add8x8_idct_neon( uint8_t *p_dst, int16_t dct[4][16] ); +void x264_add16x16_idct_neon( uint8_t *p_dst, int16_t dct[16][16] ); + +void x264_add8x8_idct_dc_neon( uint8_t *p_dst, int16_t dct[4] ); +void x264_add16x16_idct_dc_neon( uint8_t *p_dst, int16_t dct[16] ); +void x264_sub8x8_dct_dc_neon( int16_t dct[4], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x16_dct_dc_neon( int16_t dct[8], uint8_t *pix1, uint8_t *pix2 ); + +void x264_sub8x8_dct8_neon( int16_t dct[64], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct8_neon( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix2 ); + +void x264_add8x8_idct8_neon( uint8_t *p_dst, int16_t dct[64] ); +void x264_add16x16_idct8_neon( uint8_t *p_dst, int16_t dct[4][64] ); + +void x264_zigzag_scan_4x4_frame_neon( int16_t level[16], int16_t dct[16] ); +void x264_zigzag_scan_4x4_field_neon( int16_t level[16], int16_t dct[16] ); +void x264_zigzag_scan_8x8_frame_neon( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_field_neon( int16_t level[64], int16_t dct[64] ); + +int x264_zigzag_sub_4x4_field_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst ); +int x264_zigzag_sub_4x4ac_field_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst, dctcoef *dc ); +int x264_zigzag_sub_4x4_frame_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst ); +int x264_zigzag_sub_4x4ac_frame_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst, dctcoef *dc ); + +int x264_zigzag_sub_8x8_field_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst ); +int x264_zigzag_sub_8x8_frame_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst ); + +void x264_zigzag_interleave_8x8_cavlc_neon( dctcoef *dst, dctcoef *src, uint8_t *nnz ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/mc-c.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/mc-c.c new file mode 100644 index 00000000..f94aa5e5 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/mc-c.c @@ -0,0 +1,281 @@ +/***************************************************************************** + * mc-c.c: aarch64 motion compensation + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "mc.h" + +void x264_prefetch_ref_aarch64( uint8_t *, intptr_t, int ); +void x264_prefetch_fenc_420_aarch64( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_prefetch_fenc_422_aarch64( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); + +void *x264_memcpy_aligned_neon( void *dst, const void *src, size_t n ); +void x264_memzero_aligned_neon( void *dst, size_t n ); + +void x264_pixel_avg_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_16x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_8x16_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_8x4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_4x16_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_4x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_4x4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_4x2_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); + +void x264_pixel_avg2_w4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ); +void x264_pixel_avg2_w8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ); +void x264_pixel_avg2_w16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ); +void x264_pixel_avg2_w20_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ); + +void x264_plane_copy_core_neon( pixel *dst, intptr_t i_dst, + pixel *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_swap_core_neon( pixel *dst, intptr_t i_dst, + pixel *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_neon( pixel *dstu, intptr_t i_dstu, + pixel *dstv, intptr_t i_dstv, + pixel *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_rgb_neon( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, + pixel *dstc, intptr_t i_dstc, + pixel *src, intptr_t i_src, int pw, int w, int h ); +void x264_plane_copy_interleave_core_neon( pixel *dst, intptr_t i_dst, + pixel *srcu, intptr_t i_srcu, + pixel *srcv, intptr_t i_srcv, int w, int h ); + +void x264_store_interleave_chroma_neon( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); +void x264_load_deinterleave_chroma_fdec_neon( pixel *dst, pixel *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fenc_neon( pixel *dst, pixel *src, intptr_t i_src, int height ); + +#define MC_WEIGHT(func)\ +void x264_mc_weight_w20##func##_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\ +void x264_mc_weight_w16##func##_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\ +void x264_mc_weight_w8##func##_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\ +void x264_mc_weight_w4##func##_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\ +\ +static void (* x264_mc##func##_wtab_neon[6])( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int ) =\ +{\ + x264_mc_weight_w4##func##_neon,\ + x264_mc_weight_w4##func##_neon,\ + x264_mc_weight_w8##func##_neon,\ + x264_mc_weight_w16##func##_neon,\ + x264_mc_weight_w16##func##_neon,\ + x264_mc_weight_w20##func##_neon,\ +}; + +MC_WEIGHT() +MC_WEIGHT(_nodenom) +MC_WEIGHT(_offsetadd) +MC_WEIGHT(_offsetsub) + +void x264_mc_copy_w4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_mc_copy_w8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_mc_copy_w16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); + +void x264_mc_chroma_neon( uint8_t *, uint8_t *, intptr_t, uint8_t *, intptr_t, int, int, int, int ); +void x264_integral_init4h_neon( uint16_t *, uint8_t *, intptr_t ); +void x264_integral_init4v_neon( uint16_t *, uint16_t *, intptr_t ); +void x264_integral_init8h_neon( uint16_t *, uint8_t *, intptr_t ); +void x264_integral_init8v_neon( uint16_t *, intptr_t ); +void x264_frame_init_lowres_core_neon( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, intptr_t, int, int ); + +void x264_mbtree_propagate_cost_neon( int16_t *, uint16_t *, uint16_t *, uint16_t *, uint16_t *, float *, int ); + +void x264_mbtree_fix8_pack_neon( uint16_t *dst, float *src, int count ); +void x264_mbtree_fix8_unpack_neon( float *dst, uint16_t *src, int count ); + +#if !HIGH_BIT_DEPTH +static void x264_weight_cache_neon( x264_t *h, x264_weight_t *w ) +{ + if( w->i_scale == 1<i_denom ) + { + if( w->i_offset < 0 ) + { + w->weightfn = x264_mc_offsetsub_wtab_neon; + w->cachea[0] = -w->i_offset; + } + else + { + w->weightfn = x264_mc_offsetadd_wtab_neon; + w->cachea[0] = w->i_offset; + } + } + else if( !w->i_denom ) + w->weightfn = x264_mc_nodenom_wtab_neon; + else + w->weightfn = x264_mc_wtab_neon; +} + +static void (* const x264_pixel_avg_wtab_neon[6])( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ) = +{ + NULL, + x264_pixel_avg2_w4_neon, + x264_pixel_avg2_w8_neon, + x264_pixel_avg2_w16_neon, // no slower than w12, so no point in a separate function + x264_pixel_avg2_w16_neon, + x264_pixel_avg2_w20_neon, +}; + +static void (* const x264_mc_copy_wtab_neon[5])( uint8_t *, intptr_t, uint8_t *, intptr_t, int ) = +{ + NULL, + x264_mc_copy_w4_neon, + x264_mc_copy_w8_neon, + NULL, + x264_mc_copy_w16_neon, +}; + +static void mc_luma_neon( uint8_t *dst, intptr_t i_dst_stride, + uint8_t *src[4], intptr_t i_src_stride, + int mvx, int mvy, + int i_width, int i_height, const x264_weight_t *weight ) +{ + int qpel_idx = ((mvy&3)<<2) + (mvx&3); + intptr_t offset = (mvy>>2)*i_src_stride + (mvx>>2); + uint8_t *src1 = src[x264_hpel_ref0[qpel_idx]] + offset; + if( (mvy&3) == 3 ) // explict if() to force conditional add + src1 += i_src_stride; + + if( qpel_idx & 5 ) /* qpel interpolation needed */ + { + uint8_t *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3); + x264_pixel_avg_wtab_neon[i_width>>2]( + dst, i_dst_stride, src1, i_src_stride, + src2, i_height ); + if( weight->weightfn ) + weight->weightfn[i_width>>2]( dst, i_dst_stride, dst, i_dst_stride, weight, i_height ); + } + else if( weight->weightfn ) + weight->weightfn[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, weight, i_height ); + else + x264_mc_copy_wtab_neon[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, i_height ); +} + +static uint8_t *get_ref_neon( uint8_t *dst, intptr_t *i_dst_stride, + uint8_t *src[4], intptr_t i_src_stride, + int mvx, int mvy, + int i_width, int i_height, const x264_weight_t *weight ) +{ + int qpel_idx = ((mvy&3)<<2) + (mvx&3); + intptr_t offset = (mvy>>2)*i_src_stride + (mvx>>2); + uint8_t *src1 = src[x264_hpel_ref0[qpel_idx]] + offset; + if( (mvy&3) == 3 ) // explict if() to force conditional add + src1 += i_src_stride; + + if( qpel_idx & 5 ) /* qpel interpolation needed */ + { + uint8_t *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3); + x264_pixel_avg_wtab_neon[i_width>>2]( + dst, *i_dst_stride, src1, i_src_stride, + src2, i_height ); + if( weight->weightfn ) + weight->weightfn[i_width>>2]( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_height ); + return dst; + } + else if( weight->weightfn ) + { + weight->weightfn[i_width>>2]( dst, *i_dst_stride, src1, i_src_stride, weight, i_height ); + return dst; + } + else + { + *i_dst_stride = i_src_stride; + return src1; + } +} + +void x264_hpel_filter_neon( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, + uint8_t *src, intptr_t stride, int width, + int height, int16_t *buf ); + +PLANE_COPY(16, neon) +PLANE_COPY_SWAP(16, neon) +PLANE_INTERLEAVE(neon) +#endif // !HIGH_BIT_DEPTH + +PROPAGATE_LIST(neon) + +void x264_mc_init_aarch64( int cpu, x264_mc_functions_t *pf ) +{ +#if !HIGH_BIT_DEPTH + if( cpu&X264_CPU_ARMV8 ) + { + pf->prefetch_fenc_420 = x264_prefetch_fenc_420_aarch64; + pf->prefetch_fenc_422 = x264_prefetch_fenc_422_aarch64; + pf->prefetch_ref = x264_prefetch_ref_aarch64; + } + + if( !(cpu&X264_CPU_NEON) ) + return; + + pf->copy_16x16_unaligned = x264_mc_copy_w16_neon; + pf->copy[PIXEL_16x16] = x264_mc_copy_w16_neon; + pf->copy[PIXEL_8x8] = x264_mc_copy_w8_neon; + pf->copy[PIXEL_4x4] = x264_mc_copy_w4_neon; + + pf->plane_copy = x264_plane_copy_neon; + pf->plane_copy_swap = x264_plane_copy_swap_neon; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_neon; + pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_neon; + pf->plane_copy_interleave = x264_plane_copy_interleave_neon; + + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_neon; + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_neon; + pf->store_interleave_chroma = x264_store_interleave_chroma_neon; + + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_neon; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_neon; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_neon; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_neon; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_neon; + pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_neon; + pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_neon; + pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_neon; + pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_neon; + + pf->weight = x264_mc_wtab_neon; + pf->offsetadd = x264_mc_offsetadd_wtab_neon; + pf->offsetsub = x264_mc_offsetsub_wtab_neon; + pf->weight_cache = x264_weight_cache_neon; + + pf->mc_chroma = x264_mc_chroma_neon; + pf->mc_luma = mc_luma_neon; + pf->get_ref = get_ref_neon; + pf->hpel_filter = x264_hpel_filter_neon; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_neon; + + pf->integral_init4h = x264_integral_init4h_neon; + pf->integral_init8h = x264_integral_init8h_neon; + pf->integral_init4v = x264_integral_init4v_neon; + pf->integral_init8v = x264_integral_init8v_neon; + + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_neon; + pf->mbtree_propagate_list = x264_mbtree_propagate_list_neon; + pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_neon; + pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_neon; + + pf->memcpy_aligned = x264_memcpy_aligned_neon; + pf->memzero_aligned = x264_memzero_aligned_neon; +#endif // !HIGH_BIT_DEPTH +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/mc.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/mc.h new file mode 100644 index 00000000..33c311e9 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/mc.h @@ -0,0 +1,31 @@ +/***************************************************************************** + * mc.h: aarch64 motion compensation + ***************************************************************************** + * Copyright (C) 2014-2017 x264 project + * + * Authors: Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_AARCH64_MC_H +#define X264_AARCH64_MC_H + +void x264_mc_init_aarch64( int cpu, x264_mc_functions_t *pf ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/pixel.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/pixel.h new file mode 100644 index 00000000..5206a0c7 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/pixel.h @@ -0,0 +1,79 @@ +/***************************************************************************** + * pixel.h: aarch64 pixel metrics + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_AARCH64_PIXEL_H +#define X264_AARCH64_PIXEL_H + +#define DECL_PIXELS( ret, name, suffix, args ) \ + ret x264_pixel_##name##_16x16_##suffix args;\ + ret x264_pixel_##name##_16x8_##suffix args;\ + ret x264_pixel_##name##_8x16_##suffix args;\ + ret x264_pixel_##name##_8x8_##suffix args;\ + ret x264_pixel_##name##_8x4_##suffix args;\ + ret x264_pixel_##name##_4x16_##suffix args;\ + ret x264_pixel_##name##_4x8_##suffix args;\ + ret x264_pixel_##name##_4x4_##suffix args;\ + +#define DECL_X1( name, suffix ) \ + DECL_PIXELS( int, name, suffix, ( uint8_t *, intptr_t, uint8_t *, intptr_t ) ) + +#define DECL_X4( name, suffix ) \ + DECL_PIXELS( void, name##_x3, suffix, ( uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, int * ) )\ + DECL_PIXELS( void, name##_x4, suffix, ( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, int * ) ) + +DECL_X1( sad, neon ) +DECL_X4( sad, neon ) +DECL_X1( satd, neon ) +DECL_X1( ssd, neon ) + + +void x264_pixel_ssd_nv12_core_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int, int, uint64_t *, uint64_t * ); + +int x264_pixel_vsad_neon( uint8_t *, intptr_t, int ); + +int x264_pixel_sa8d_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t ); +int x264_pixel_sa8d_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t ); +uint64_t x264_pixel_sa8d_satd_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t ); + +uint64_t x264_pixel_var_8x8_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_var_8x16_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_var_16x16_neon( uint8_t *, intptr_t ); +int x264_pixel_var2_8x8_neon ( uint8_t *, uint8_t *, int * ); +int x264_pixel_var2_8x16_neon( uint8_t *, uint8_t *, int * ); + +uint64_t x264_pixel_hadamard_ac_8x8_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_hadamard_ac_8x16_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_hadamard_ac_16x8_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_hadamard_ac_16x16_neon( uint8_t *, intptr_t ); + +void x264_pixel_ssim_4x4x2_core_neon( const uint8_t *, intptr_t, + const uint8_t *, intptr_t, + int sums[2][4] ); +float x264_pixel_ssim_end4_neon( int sum0[5][4], int sum1[5][4], int width ); + +int x264_pixel_asd8_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/predict-c.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/predict-c.c new file mode 100644 index 00000000..34b81ebb --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/predict-c.c @@ -0,0 +1,139 @@ +/***************************************************************************** + * predict.c: aarch64 intra prediction + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "predict.h" +#include "pixel.h" + +void x264_predict_4x4_dc_top_neon( uint8_t *src ); +void x264_predict_4x4_ddr_neon( uint8_t *src ); +void x264_predict_4x4_ddl_neon( uint8_t *src ); + +void x264_predict_8x8c_dc_top_neon( uint8_t *src ); +void x264_predict_8x8c_dc_left_neon( uint8_t *src ); +void x264_predict_8x8c_p_neon( uint8_t *src ); + +void x264_predict_8x16c_dc_left_neon( uint8_t *src ); +void x264_predict_8x16c_dc_top_neon( uint8_t *src ); +void x264_predict_8x16c_p_neon( uint8_t *src ); + +void x264_predict_8x8_ddl_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_ddr_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_vl_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_vr_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_hd_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_hu_neon( uint8_t *src, uint8_t edge[36] ); + +void x264_predict_16x16_dc_top_neon( uint8_t *src ); +void x264_predict_16x16_dc_left_neon( uint8_t *src ); +void x264_predict_16x16_p_neon( uint8_t *src ); + +void x264_predict_4x4_init_aarch64( int cpu, x264_predict_t pf[12] ) +{ +#if !HIGH_BIT_DEPTH + if( cpu&X264_CPU_ARMV8 ) + { + pf[I_PRED_4x4_H] = x264_predict_4x4_h_aarch64; + pf[I_PRED_4x4_V] = x264_predict_4x4_v_aarch64; + } + + if( cpu&X264_CPU_NEON ) + { + pf[I_PRED_4x4_DC] = x264_predict_4x4_dc_neon; + pf[I_PRED_4x4_DC_TOP] = x264_predict_4x4_dc_top_neon; + pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_neon; + pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_neon; + } +#endif // !HIGH_BIT_DEPTH +} + +void x264_predict_8x8c_init_aarch64( int cpu, x264_predict_t pf[7] ) +{ +#if !HIGH_BIT_DEPTH + if( cpu&X264_CPU_ARMV8 ) + { + pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_aarch64; + } + + if( !(cpu&X264_CPU_NEON) ) + return; + + pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_neon; + pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_neon; + pf[I_PRED_CHROMA_DC_LEFT] = x264_predict_8x8c_dc_left_neon; + pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_neon; + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_neon; +#endif // !HIGH_BIT_DEPTH +} + + +void x264_predict_8x16c_init_aarch64( int cpu, x264_predict_t pf[7] ) +{ + if( !(cpu&X264_CPU_NEON) ) + return; + +#if !HIGH_BIT_DEPTH + pf[I_PRED_CHROMA_V ] = x264_predict_8x16c_v_neon; + pf[I_PRED_CHROMA_H ] = x264_predict_8x16c_h_neon; + pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_neon; + pf[I_PRED_CHROMA_P ] = x264_predict_8x16c_p_neon; + pf[I_PRED_CHROMA_DC_LEFT]= x264_predict_8x16c_dc_left_neon; + pf[I_PRED_CHROMA_DC_TOP ]= x264_predict_8x16c_dc_top_neon; +#endif // !HIGH_BIT_DEPTH +} + +void x264_predict_8x8_init_aarch64( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter ) +{ + if( !(cpu&X264_CPU_NEON) ) + return; + +#if !HIGH_BIT_DEPTH + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_neon; + pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_neon; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_neon; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_neon; + pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_neon; + pf[I_PRED_8x8_H] = x264_predict_8x8_h_neon; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_neon; + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_neon; + pf[I_PRED_8x8_V] = x264_predict_8x8_v_neon; +#endif // !HIGH_BIT_DEPTH +} + +void x264_predict_16x16_init_aarch64( int cpu, x264_predict_t pf[7] ) +{ + if( !(cpu&X264_CPU_NEON) ) + return; + +#if !HIGH_BIT_DEPTH + pf[I_PRED_16x16_DC ] = x264_predict_16x16_dc_neon; + pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_neon; + pf[I_PRED_16x16_DC_LEFT]= x264_predict_16x16_dc_left_neon; + pf[I_PRED_16x16_H ] = x264_predict_16x16_h_neon; + pf[I_PRED_16x16_V ] = x264_predict_16x16_v_neon; + pf[I_PRED_16x16_P ] = x264_predict_16x16_p_neon; +#endif // !HIGH_BIT_DEPTH +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/predict.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/predict.h new file mode 100644 index 00000000..a8beada0 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/predict.h @@ -0,0 +1,58 @@ +/***************************************************************************** + * predict.h: aarch64 intra prediction + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_AARCH64_PREDICT_H +#define X264_AARCH64_PREDICT_H + +void x264_predict_4x4_h_aarch64( uint8_t *src ); +void x264_predict_4x4_v_aarch64( uint8_t *src ); +void x264_predict_8x8c_v_aarch64( uint8_t *src ); + +// for the merged 4x4 intra sad/satd which expects unified suffix +#define x264_predict_4x4_h_neon x264_predict_4x4_h_aarch64 +#define x264_predict_4x4_v_neon x264_predict_4x4_v_aarch64 +#define x264_predict_8x8c_v_neon x264_predict_8x8c_v_aarch64 + +void x264_predict_4x4_dc_neon( uint8_t *src ); +void x264_predict_8x8_v_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_h_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_dc_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8c_dc_neon( uint8_t *src ); +void x264_predict_8x8c_h_neon( uint8_t *src ); +void x264_predict_8x16c_v_neon( uint8_t *src ); +void x264_predict_8x16c_h_neon( uint8_t *src ); +void x264_predict_8x16c_dc_neon( uint8_t *src ); +void x264_predict_16x16_v_neon( uint8_t *src ); +void x264_predict_16x16_h_neon( uint8_t *src ); +void x264_predict_16x16_dc_neon( uint8_t *src ); + +void x264_predict_4x4_init_aarch64( int cpu, x264_predict_t pf[12] ); +void x264_predict_8x8_init_aarch64( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter ); +void x264_predict_8x8c_init_aarch64( int cpu, x264_predict_t pf[7] ); +void x264_predict_8x16c_init_aarch64( int cpu, x264_predict_t pf[7] ); +void x264_predict_16x16_init_aarch64( int cpu, x264_predict_t pf[7] ); + +#endif /* X264_AARCH64_PREDICT_H */ diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/quant.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/quant.h new file mode 100644 index 00000000..e0133e75 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/aarch64/quant.h @@ -0,0 +1,59 @@ +/***************************************************************************** + * quant.h: arm quantization and level-run + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: David Conrad + * Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_AARCH64_QUANT_H +#define X264_AARCH64_QUANT_H + +int x264_quant_2x2_dc_aarch64( int16_t dct[4], int mf, int bias ); + +int x264_quant_2x2_dc_neon( int16_t dct[4], int mf, int bias ); +int x264_quant_4x4_dc_neon( int16_t dct[16], int mf, int bias ); +int x264_quant_4x4_neon( int16_t dct[16], uint16_t mf[16], uint16_t bias[16] ); +int x264_quant_4x4x4_neon( int16_t dct[4][16], uint16_t mf[16], uint16_t bias[16] ); +int x264_quant_8x8_neon( int16_t dct[64], uint16_t mf[64], uint16_t bias[64] ); + +void x264_dequant_4x4_dc_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_4x4_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_neon( int16_t dct[64], int dequant_mf[6][64], int i_qp ); + +int x264_decimate_score15_neon( int16_t * ); +int x264_decimate_score16_neon( int16_t * ); +int x264_decimate_score64_neon( int16_t * ); + +int x264_coeff_last4_aarch64( int16_t * ); +int x264_coeff_last8_aarch64( int16_t * ); +int x264_coeff_last15_neon( int16_t * ); +int x264_coeff_last16_neon( int16_t * ); +int x264_coeff_last64_neon( int16_t * ); + +int x264_coeff_level_run4_aarch64( int16_t *, x264_run_level_t * ); +int x264_coeff_level_run8_neon( int16_t *, x264_run_level_t * ); +int x264_coeff_level_run15_neon( int16_t *, x264_run_level_t * ); +int x264_coeff_level_run16_neon( int16_t *, x264_run_level_t * ); + +void x264_denoise_dct_neon( dctcoef *, uint32_t *, udctcoef *, int ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/dct.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/dct.h new file mode 100644 index 00000000..2b4210ab --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/dct.h @@ -0,0 +1,53 @@ +/***************************************************************************** + * dct.h: arm transform and zigzag + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ARM_DCT_H +#define X264_ARM_DCT_H + +void x264_dct4x4dc_neon( int16_t d[16] ); +void x264_idct4x4dc_neon( int16_t d[16] ); + +void x264_sub4x4_dct_neon( int16_t dct[16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_neon( int16_t dct[4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct_neon( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); + +void x264_add4x4_idct_neon( uint8_t *p_dst, int16_t dct[16] ); +void x264_add8x8_idct_neon( uint8_t *p_dst, int16_t dct[4][16] ); +void x264_add16x16_idct_neon( uint8_t *p_dst, int16_t dct[16][16] ); + +void x264_add8x8_idct_dc_neon( uint8_t *p_dst, int16_t dct[4] ); +void x264_add16x16_idct_dc_neon( uint8_t *p_dst, int16_t dct[16] ); +void x264_sub8x8_dct_dc_neon( int16_t dct[4], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x16_dct_dc_neon( int16_t dct[8], uint8_t *pix1, uint8_t *pix2 ); + +void x264_sub8x8_dct8_neon( int16_t dct[64], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct8_neon( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix2 ); + +void x264_add8x8_idct8_neon( uint8_t *p_dst, int16_t dct[64] ); +void x264_add16x16_idct8_neon( uint8_t *p_dst, int16_t dct[4][64] ); + +void x264_zigzag_scan_4x4_frame_neon( int16_t level[16], int16_t dct[16] ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/mc-c.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/mc-c.c new file mode 100644 index 00000000..ab472291 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/mc-c.c @@ -0,0 +1,310 @@ +/***************************************************************************** + * mc-c.c: arm motion compensation + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * Janne Grunau + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "mc.h" + +void x264_prefetch_ref_arm( uint8_t *, intptr_t, int ); +void x264_prefetch_fenc_arm( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); + +void *x264_memcpy_aligned_neon( void *dst, const void *src, size_t n ); +void x264_memzero_aligned_neon( void *dst, size_t n ); + +void x264_pixel_avg_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_16x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_8x16_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_8x4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_4x16_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_4x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_4x4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_pixel_avg_4x2_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int ); + +void x264_pixel_avg2_w4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ); +void x264_pixel_avg2_w8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ); +void x264_pixel_avg2_w16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ); +void x264_pixel_avg2_w20_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ); + +void x264_plane_copy_core_neon( pixel *dst, intptr_t i_dst, + pixel *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_neon( pixel *dstu, intptr_t i_dstu, + pixel *dstv, intptr_t i_dstv, + pixel *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_rgb_neon( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, + pixel *dstc, intptr_t i_dstc, + pixel *src, intptr_t i_src, int pw, int w, int h ); +void x264_plane_copy_interleave_core_neon( pixel *dst, intptr_t i_dst, + pixel *srcu, intptr_t i_srcu, + pixel *srcv, intptr_t i_srcv, int w, int h ); +void x264_plane_copy_swap_core_neon( pixel *dst, intptr_t i_dst, + pixel *src, intptr_t i_src, int w, int h ); + +void x264_store_interleave_chroma_neon( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); +void x264_load_deinterleave_chroma_fdec_neon( pixel *dst, pixel *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fenc_neon( pixel *dst, pixel *src, intptr_t i_src, int height ); + +#if !HIGH_BIT_DEPTH +#define MC_WEIGHT(func)\ +void x264_mc_weight_w20##func##_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\ +void x264_mc_weight_w16##func##_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\ +void x264_mc_weight_w8##func##_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\ +void x264_mc_weight_w4##func##_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\ +\ +static weight_fn_t x264_mc##func##_wtab_neon[6] =\ +{\ + x264_mc_weight_w4##func##_neon,\ + x264_mc_weight_w4##func##_neon,\ + x264_mc_weight_w8##func##_neon,\ + x264_mc_weight_w16##func##_neon,\ + x264_mc_weight_w16##func##_neon,\ + x264_mc_weight_w20##func##_neon,\ +}; + +MC_WEIGHT() +MC_WEIGHT(_nodenom) +MC_WEIGHT(_offsetadd) +MC_WEIGHT(_offsetsub) +#endif + +void x264_mc_copy_w4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_mc_copy_w8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_mc_copy_w16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); +void x264_mc_copy_w16_aligned_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); + +void x264_mc_chroma_neon( uint8_t *, uint8_t *, intptr_t, uint8_t *, intptr_t, int, int, int, int ); +void x264_frame_init_lowres_core_neon( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, intptr_t, int, int ); + +void x264_hpel_filter_v_neon( uint8_t *, uint8_t *, int16_t *, intptr_t, int ); +void x264_hpel_filter_c_neon( uint8_t *, int16_t *, int ); +void x264_hpel_filter_h_neon( uint8_t *, uint8_t *, int ); + +void x264_integral_init4h_neon( uint16_t *, uint8_t *, intptr_t ); +void x264_integral_init4v_neon( uint16_t *, uint16_t *, intptr_t ); +void x264_integral_init8h_neon( uint16_t *, uint8_t *, intptr_t ); +void x264_integral_init8v_neon( uint16_t *, intptr_t ); + +void x264_mbtree_propagate_cost_neon( int16_t *, uint16_t *, uint16_t *, uint16_t *, uint16_t *, float *, int ); + +void x264_mbtree_fix8_pack_neon( uint16_t *dst, float *src, int count ); +void x264_mbtree_fix8_unpack_neon( float *dst, uint16_t *src, int count ); + +#if !HIGH_BIT_DEPTH +static void x264_weight_cache_neon( x264_t *h, x264_weight_t *w ) +{ + if( w->i_scale == 1<i_denom ) + { + if( w->i_offset < 0 ) + { + w->weightfn = x264_mc_offsetsub_wtab_neon; + w->cachea[0] = -w->i_offset; + } + else + { + w->weightfn = x264_mc_offsetadd_wtab_neon; + w->cachea[0] = w->i_offset; + } + } + else if( !w->i_denom ) + w->weightfn = x264_mc_nodenom_wtab_neon; + else + w->weightfn = x264_mc_wtab_neon; +} + +static void (* const x264_pixel_avg_wtab_neon[6])( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ) = +{ + NULL, + x264_pixel_avg2_w4_neon, + x264_pixel_avg2_w8_neon, + x264_pixel_avg2_w16_neon, // no slower than w12, so no point in a separate function + x264_pixel_avg2_w16_neon, + x264_pixel_avg2_w20_neon, +}; + +static void (* const x264_mc_copy_wtab_neon[5])( uint8_t *, intptr_t, uint8_t *, intptr_t, int ) = +{ + NULL, + x264_mc_copy_w4_neon, + x264_mc_copy_w8_neon, + NULL, + x264_mc_copy_w16_neon, +}; + +static void mc_luma_neon( uint8_t *dst, intptr_t i_dst_stride, + uint8_t *src[4], intptr_t i_src_stride, + int mvx, int mvy, + int i_width, int i_height, const x264_weight_t *weight ) +{ + int qpel_idx = ((mvy&3)<<2) + (mvx&3); + intptr_t offset = (mvy>>2)*i_src_stride + (mvx>>2); + uint8_t *src1 = src[x264_hpel_ref0[qpel_idx]] + offset; + if( (mvy&3) == 3 ) // explict if() to force conditional add + src1 += i_src_stride; + + if( qpel_idx & 5 ) /* qpel interpolation needed */ + { + uint8_t *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3); + x264_pixel_avg_wtab_neon[i_width>>2]( + dst, i_dst_stride, src1, i_src_stride, + src2, i_height ); + if( weight->weightfn ) + weight->weightfn[i_width>>2]( dst, i_dst_stride, dst, i_dst_stride, weight, i_height ); + } + else if( weight->weightfn ) + weight->weightfn[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, weight, i_height ); + else + x264_mc_copy_wtab_neon[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, i_height ); +} + +static uint8_t *get_ref_neon( uint8_t *dst, intptr_t *i_dst_stride, + uint8_t *src[4], intptr_t i_src_stride, + int mvx, int mvy, + int i_width, int i_height, const x264_weight_t *weight ) +{ + int qpel_idx = ((mvy&3)<<2) + (mvx&3); + intptr_t offset = (mvy>>2)*i_src_stride + (mvx>>2); + uint8_t *src1 = src[x264_hpel_ref0[qpel_idx]] + offset; + if( (mvy&3) == 3 ) // explict if() to force conditional add + src1 += i_src_stride; + + if( qpel_idx & 5 ) /* qpel interpolation needed */ + { + uint8_t *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3); + x264_pixel_avg_wtab_neon[i_width>>2]( + dst, *i_dst_stride, src1, i_src_stride, + src2, i_height ); + if( weight->weightfn ) + weight->weightfn[i_width>>2]( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_height ); + return dst; + } + else if( weight->weightfn ) + { + weight->weightfn[i_width>>2]( dst, *i_dst_stride, src1, i_src_stride, weight, i_height ); + return dst; + } + else + { + *i_dst_stride = i_src_stride; + return src1; + } +} + +static void hpel_filter_neon( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, + intptr_t stride, int width, int height, int16_t *buf ) +{ + intptr_t realign = (intptr_t)src & 15; + src -= realign; + dstv -= realign; + dstc -= realign; + dsth -= realign; + width += realign; + while( height-- ) + { + x264_hpel_filter_v_neon( dstv, src, buf+8, stride, width ); + x264_hpel_filter_c_neon( dstc, buf+8, width ); + x264_hpel_filter_h_neon( dsth, src, width ); + dsth += stride; + dstv += stride; + dstc += stride; + src += stride; + } +} + +PLANE_COPY(16, neon) +PLANE_COPY_SWAP(16, neon) +PLANE_INTERLEAVE(neon) +#endif // !HIGH_BIT_DEPTH + +PROPAGATE_LIST(neon) + +void x264_mc_init_arm( int cpu, x264_mc_functions_t *pf ) +{ + if( !(cpu&X264_CPU_ARMV6) ) + return; + +#if !HIGH_BIT_DEPTH + pf->prefetch_fenc_420 = x264_prefetch_fenc_arm; + pf->prefetch_fenc_422 = x264_prefetch_fenc_arm; /* FIXME */ + pf->prefetch_ref = x264_prefetch_ref_arm; +#endif // !HIGH_BIT_DEPTH + + if( !(cpu&X264_CPU_NEON) ) + return; + +#if !HIGH_BIT_DEPTH + pf->copy_16x16_unaligned = x264_mc_copy_w16_neon; + pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_neon; + pf->copy[PIXEL_8x8] = x264_mc_copy_w8_neon; + pf->copy[PIXEL_4x4] = x264_mc_copy_w4_neon; + + pf->plane_copy = x264_plane_copy_neon; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_neon; + pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_neon; + pf->plane_copy_interleave = x264_plane_copy_interleave_neon; + pf->plane_copy_swap = x264_plane_copy_swap_neon; + + pf->store_interleave_chroma = x264_store_interleave_chroma_neon; + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_neon; + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_neon; + + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_neon; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_neon; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_neon; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_neon; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_neon; + pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_neon; + pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_neon; + pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_neon; + pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_neon; + + pf->weight = x264_mc_wtab_neon; + pf->offsetadd = x264_mc_offsetadd_wtab_neon; + pf->offsetsub = x264_mc_offsetsub_wtab_neon; + pf->weight_cache = x264_weight_cache_neon; + + pf->mc_chroma = x264_mc_chroma_neon; + pf->mc_luma = mc_luma_neon; + pf->get_ref = get_ref_neon; + pf->hpel_filter = hpel_filter_neon; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_neon; + + pf->integral_init4h = x264_integral_init4h_neon; + pf->integral_init8h = x264_integral_init8h_neon; + pf->integral_init4v = x264_integral_init4v_neon; + pf->integral_init8v = x264_integral_init8v_neon; + + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_neon; + pf->mbtree_propagate_list = x264_mbtree_propagate_list_neon; + pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_neon; + pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_neon; +#endif // !HIGH_BIT_DEPTH + +// Apple's gcc stupidly cannot align stack variables, and ALIGNED_ARRAY can't work on structs +#ifndef SYS_MACOSX + pf->memcpy_aligned = x264_memcpy_aligned_neon; +#endif + pf->memzero_aligned = x264_memzero_aligned_neon; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/mc.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/mc.h new file mode 100644 index 00000000..fc8802f7 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/mc.h @@ -0,0 +1,31 @@ +/***************************************************************************** + * mc.h: arm motion compensation + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ARM_MC_H +#define X264_ARM_MC_H + +void x264_mc_init_arm( int cpu, x264_mc_functions_t *pf ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/pixel.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/pixel.h new file mode 100644 index 00000000..d9b02c4c --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/pixel.h @@ -0,0 +1,81 @@ +/***************************************************************************** + * pixel.h: arm pixel metrics + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ARM_PIXEL_H +#define X264_ARM_PIXEL_H + +#define DECL_PIXELS( ret, name, suffix, args ) \ + ret x264_pixel_##name##_16x16_##suffix args;\ + ret x264_pixel_##name##_16x8_##suffix args;\ + ret x264_pixel_##name##_8x16_##suffix args;\ + ret x264_pixel_##name##_8x8_##suffix args;\ + ret x264_pixel_##name##_8x4_##suffix args;\ + ret x264_pixel_##name##_4x8_##suffix args;\ + ret x264_pixel_##name##_4x4_##suffix args;\ + +#define DECL_X1( name, suffix ) \ + DECL_PIXELS( int, name, suffix, ( uint8_t *, int, uint8_t *, int ) ) + +#define DECL_X4( name, suffix ) \ + DECL_PIXELS( void, name##_x3, suffix, ( uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, int * ) )\ + DECL_PIXELS( void, name##_x4, suffix, ( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, int * ) ) + +int x264_pixel_sad_4x4_armv6( uint8_t *, intptr_t, uint8_t *, intptr_t ); +int x264_pixel_sad_4x8_armv6( uint8_t *, intptr_t, uint8_t *, intptr_t ); + +DECL_X1( sad, neon ) +DECL_X1( sad_aligned, neon ) +DECL_X1( sad_aligned, neon_dual ) +DECL_X4( sad, neon ) +DECL_X1( satd, neon ) +DECL_X1( ssd, neon ) + +void x264_pixel_ssd_nv12_core_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int, int, uint64_t *, uint64_t * ); + +int x264_pixel_vsad_neon( uint8_t *, intptr_t, int ); + +int x264_pixel_sa8d_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t ); +int x264_pixel_sa8d_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t ); +uint64_t x264_pixel_sa8d_satd_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t ); + +uint64_t x264_pixel_var_8x8_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_var_8x16_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_var_16x16_neon( uint8_t *, intptr_t ); +int x264_pixel_var2_8x8_neon ( uint8_t *, uint8_t *, int * ); +int x264_pixel_var2_8x16_neon( uint8_t *, uint8_t *, int * ); + +uint64_t x264_pixel_hadamard_ac_8x8_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_hadamard_ac_8x16_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_hadamard_ac_16x8_neon ( uint8_t *, intptr_t ); +uint64_t x264_pixel_hadamard_ac_16x16_neon( uint8_t *, intptr_t ); + +void x264_pixel_ssim_4x4x2_core_neon( const uint8_t *, intptr_t, + const uint8_t *, intptr_t, + int sums[2][4] ); +float x264_pixel_ssim_end4_neon( int sum0[5][4], int sum1[5][4], int width ); + +int x264_pixel_asd8_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/predict-c.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/predict-c.c new file mode 100644 index 00000000..1c8f9164 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/predict-c.c @@ -0,0 +1,108 @@ +/***************************************************************************** + * predict.c: arm intra prediction + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "predict.h" +#include "pixel.h" + +void x264_predict_4x4_init_arm( int cpu, x264_predict_t pf[12] ) +{ + if( !(cpu&X264_CPU_ARMV6) ) + return; + +#if !HIGH_BIT_DEPTH + pf[I_PRED_4x4_H] = x264_predict_4x4_h_armv6; + pf[I_PRED_4x4_V] = x264_predict_4x4_v_armv6; + pf[I_PRED_4x4_DC] = x264_predict_4x4_dc_armv6; + pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_armv6; + + if( !(cpu&X264_CPU_NEON) ) + return; + + pf[I_PRED_4x4_DC_TOP] = x264_predict_4x4_dc_top_neon; + pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_neon; +#endif // !HIGH_BIT_DEPTH +} + +void x264_predict_8x8c_init_arm( int cpu, x264_predict_t pf[7] ) +{ + if( !(cpu&X264_CPU_NEON) ) + return; + +#if !HIGH_BIT_DEPTH + pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_neon; + pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_neon; + pf[I_PRED_CHROMA_DC_LEFT] = x264_predict_8x8c_dc_left_neon; + pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_neon; + pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_neon; + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_neon; +#endif // !HIGH_BIT_DEPTH +} + +void x264_predict_8x16c_init_arm( int cpu, x264_predict_t pf[7] ) +{ + if( !(cpu&X264_CPU_NEON) ) + return; + +#if !HIGH_BIT_DEPTH + /* The other functions weren't faster than C (gcc 4.7.3) on Cortex A8 and A9. */ + pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x16c_dc_top_neon; + pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_neon; + pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_neon; +#endif // !HIGH_BIT_DEPTH +} + +void x264_predict_8x8_init_arm( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter ) +{ + if( !(cpu&X264_CPU_NEON) ) + return; + +#if !HIGH_BIT_DEPTH + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_neon; + pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_neon; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_neon; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_neon; + pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_neon; + pf[I_PRED_8x8_H] = x264_predict_8x8_h_neon; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_neon; + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_neon; + pf[I_PRED_8x8_V] = x264_predict_8x8_v_neon; +#endif // !HIGH_BIT_DEPTH +} + +void x264_predict_16x16_init_arm( int cpu, x264_predict_t pf[7] ) +{ + if( !(cpu&X264_CPU_NEON) ) + return; + +#if !HIGH_BIT_DEPTH + pf[I_PRED_16x16_DC ] = x264_predict_16x16_dc_neon; + pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_neon; + pf[I_PRED_16x16_DC_LEFT]= x264_predict_16x16_dc_left_neon; + pf[I_PRED_16x16_H ] = x264_predict_16x16_h_neon; + pf[I_PRED_16x16_V ] = x264_predict_16x16_v_neon; + pf[I_PRED_16x16_P ] = x264_predict_16x16_p_neon; +#endif // !HIGH_BIT_DEPTH +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/predict.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/predict.h new file mode 100644 index 00000000..35aeaaf3 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/predict.h @@ -0,0 +1,70 @@ +/***************************************************************************** + * predict.h: arm intra prediction + ***************************************************************************** + * Copyright (C) 2009-2017 x264 project + * + * Authors: David Conrad + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ARM_PREDICT_H +#define X264_ARM_PREDICT_H + +void x264_predict_4x4_dc_armv6( uint8_t *src ); +void x264_predict_4x4_dc_top_neon( uint8_t *src ); +void x264_predict_4x4_v_armv6( uint8_t *src ); +void x264_predict_4x4_h_armv6( uint8_t *src ); +void x264_predict_4x4_ddr_armv6( uint8_t *src ); +void x264_predict_4x4_ddl_neon( uint8_t *src ); + +void x264_predict_8x8c_dc_neon( uint8_t *src ); +void x264_predict_8x8c_dc_top_neon( uint8_t *src ); +void x264_predict_8x8c_dc_left_neon( uint8_t *src ); +void x264_predict_8x8c_h_neon( uint8_t *src ); +void x264_predict_8x8c_v_neon( uint8_t *src ); +void x264_predict_8x8c_p_neon( uint8_t *src ); + +void x264_predict_8x16c_h_neon( uint8_t *src ); +void x264_predict_8x16c_dc_top_neon( uint8_t *src ); +void x264_predict_8x16c_p_neon( uint8_t *src ); + +void x264_predict_8x8_dc_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_ddl_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_ddr_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_vl_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_vr_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_v_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_h_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_hd_neon( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_hu_neon( uint8_t *src, uint8_t edge[36] ); + +void x264_predict_16x16_dc_neon( uint8_t *src ); +void x264_predict_16x16_dc_top_neon( uint8_t *src ); +void x264_predict_16x16_dc_left_neon( uint8_t *src ); +void x264_predict_16x16_h_neon( uint8_t *src ); +void x264_predict_16x16_v_neon( uint8_t *src ); +void x264_predict_16x16_p_neon( uint8_t *src ); + +void x264_predict_4x4_init_arm( int cpu, x264_predict_t pf[12] ); +void x264_predict_8x8_init_arm( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter ); +void x264_predict_8x8c_init_arm( int cpu, x264_predict_t pf[7] ); +void x264_predict_8x16c_init_arm( int cpu, x264_predict_t pf[7] ); +void x264_predict_16x16_init_arm( int cpu, x264_predict_t pf[7] ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/quant.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/quant.h new file mode 100644 index 00000000..2c71577f --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/arm/quant.h @@ -0,0 +1,53 @@ +/***************************************************************************** + * quant.h: arm quantization and level-run + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: David Conrad + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ARM_QUANT_H +#define X264_ARM_QUANT_H + +int x264_quant_2x2_dc_armv6( int16_t dct[4], int mf, int bias ); + +int x264_quant_2x2_dc_neon( int16_t dct[4], int mf, int bias ); +int x264_quant_4x4_dc_neon( int16_t dct[16], int mf, int bias ); +int x264_quant_4x4_neon( int16_t dct[16], uint16_t mf[16], uint16_t bias[16] ); +int x264_quant_4x4x4_neon( int16_t dct[4][16], uint16_t mf[16], uint16_t bias[16] ); +int x264_quant_8x8_neon( int16_t dct[64], uint16_t mf[64], uint16_t bias[64] ); + +void x264_dequant_4x4_dc_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_4x4_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_neon( int16_t dct[64], int dequant_mf[6][64], int i_qp ); + +int x264_decimate_score15_neon( int16_t * ); +int x264_decimate_score16_neon( int16_t * ); +int x264_decimate_score64_neon( int16_t * ); + +int x264_coeff_last4_arm( int16_t * ); +int x264_coeff_last8_arm( int16_t * ); +int x264_coeff_last15_neon( int16_t * ); +int x264_coeff_last16_neon( int16_t * ); +int x264_coeff_last64_neon( int16_t * ); + +void x264_denoise_dct_neon( dctcoef *, uint32_t *, udctcoef *, int ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/bitstream.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/bitstream.c new file mode 100644 index 00000000..cc763000 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/bitstream.c @@ -0,0 +1,176 @@ +/***************************************************************************** + * bitstream.c: bitstream writing + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +static uint8_t *x264_nal_escape_c( uint8_t *dst, uint8_t *src, uint8_t *end ) +{ + if( src < end ) *dst++ = *src++; + if( src < end ) *dst++ = *src++; + while( src < end ) + { + if( src[0] <= 0x03 && !dst[-2] && !dst[-1] ) + *dst++ = 0x03; + *dst++ = *src++; + } + return dst; +} + +uint8_t *x264_nal_escape_mmx2( uint8_t *dst, uint8_t *src, uint8_t *end ); +uint8_t *x264_nal_escape_sse2( uint8_t *dst, uint8_t *src, uint8_t *end ); +uint8_t *x264_nal_escape_avx2( uint8_t *dst, uint8_t *src, uint8_t *end ); +void x264_cabac_block_residual_rd_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_rd_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_rd_internal_ssse3 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_rd_internal_ssse3_lzcnt( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_rd_internal_avx512 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_8x8_rd_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_8x8_rd_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_8x8_rd_internal_ssse3 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_8x8_rd_internal_ssse3_lzcnt( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_8x8_rd_internal_avx512 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_internal_avx2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); +void x264_cabac_block_residual_internal_avx512( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb ); + +uint8_t *x264_nal_escape_neon( uint8_t *dst, uint8_t *src, uint8_t *end ); + +/**************************************************************************** + * x264_nal_encode: + ****************************************************************************/ +void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal ) +{ + uint8_t *src = nal->p_payload; + uint8_t *end = nal->p_payload + nal->i_payload; + uint8_t *orig_dst = dst; + + if( h->param.b_annexb ) + { + if( nal->b_long_startcode ) + *dst++ = 0x00; + *dst++ = 0x00; + *dst++ = 0x00; + *dst++ = 0x01; + } + else /* save room for size later */ + dst += 4; + + /* nal header */ + *dst++ = ( 0x00 << 7 ) | ( nal->i_ref_idc << 5 ) | nal->i_type; + + dst = h->bsf.nal_escape( dst, src, end ); + int size = dst - orig_dst; + + /* Apply AVC-Intra padding */ + if( h->param.i_avcintra_class ) + { + int padding = nal->i_payload + nal->i_padding + NALU_OVERHEAD - size; + if( padding > 0 ) + { + memset( dst, 0, padding ); + size += padding; + } + nal->i_padding = X264_MAX( padding, 0 ); + } + + /* Write the size header for mp4/etc */ + if( !h->param.b_annexb ) + { + /* Size doesn't include the size of the header we're writing now. */ + int chunk_size = size - 4; + orig_dst[0] = chunk_size >> 24; + orig_dst[1] = chunk_size >> 16; + orig_dst[2] = chunk_size >> 8; + orig_dst[3] = chunk_size >> 0; + } + + nal->i_payload = size; + nal->p_payload = orig_dst; + x264_emms(); +} + +void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf ) +{ + memset( pf, 0, sizeof(*pf) ); + + pf->nal_escape = x264_nal_escape_c; +#if HAVE_MMX +#if ARCH_X86_64 && !defined( __MACH__ ) + pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_sse2; + pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_sse2; + pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_sse2; +#endif + + if( cpu&X264_CPU_MMX2 ) + pf->nal_escape = x264_nal_escape_mmx2; + if( cpu&X264_CPU_SSE2 ) + { + if( cpu&X264_CPU_SSE2_IS_FAST ) + pf->nal_escape = x264_nal_escape_sse2; + } +#if ARCH_X86_64 && !defined( __MACH__ ) + if( cpu&X264_CPU_LZCNT ) + { + pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_lzcnt; + pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_lzcnt; + pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_lzcnt; + } + + if( cpu&X264_CPU_SSSE3 ) + { + pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_ssse3; + pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_ssse3; + if( cpu&X264_CPU_LZCNT ) + { + pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_ssse3_lzcnt; + pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_ssse3_lzcnt; + } + } + + if( cpu&X264_CPU_AVX2 ) + { + pf->nal_escape = x264_nal_escape_avx2; + pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_avx2; + } + + if( cpu&X264_CPU_AVX512 ) + { + pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_avx512; + pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_avx512; + pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_avx512; + } +#endif +#endif +#if HAVE_ARMV6 + if( cpu&X264_CPU_NEON ) + pf->nal_escape = x264_nal_escape_neon; +#endif +#if ARCH_AARCH64 + if( cpu&X264_CPU_NEON ) + pf->nal_escape = x264_nal_escape_neon; +#endif +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/bitstream.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/bitstream.h new file mode 100644 index 00000000..2816ef33 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/bitstream.h @@ -0,0 +1,312 @@ +/***************************************************************************** + * bitstream.h: bitstream writing + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Fiona Glaser + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_BS_H +#define X264_BS_H + +typedef struct +{ + uint8_t i_bits; + uint8_t i_size; +} vlc_t; + +typedef struct +{ + uint16_t i_bits; + uint8_t i_size; + /* Next level table to use */ + uint8_t i_next; +} vlc_large_t; + +typedef struct bs_s +{ + uint8_t *p_start; + uint8_t *p; + uint8_t *p_end; + + uintptr_t cur_bits; + int i_left; /* i_count number of available bits */ + int i_bits_encoded; /* RD only */ +} bs_t; + +typedef struct +{ + int32_t last; + int32_t mask; + ALIGNED_16( dctcoef level[18] ); +} x264_run_level_t; + +extern const vlc_t x264_coeff0_token[6]; +extern const vlc_t x264_coeff_token[6][16][4]; +extern const vlc_t x264_total_zeros[15][16]; +extern const vlc_t x264_total_zeros_2x2_dc[3][4]; +extern const vlc_t x264_total_zeros_2x4_dc[7][8]; + +typedef struct +{ + uint8_t *(*nal_escape)( uint8_t *dst, uint8_t *src, uint8_t *end ); + void (*cabac_block_residual_internal)( dctcoef *l, int b_interlaced, + intptr_t ctx_block_cat, x264_cabac_t *cb ); + void (*cabac_block_residual_rd_internal)( dctcoef *l, int b_interlaced, + intptr_t ctx_block_cat, x264_cabac_t *cb ); + void (*cabac_block_residual_8x8_rd_internal)( dctcoef *l, int b_interlaced, + intptr_t ctx_block_cat, x264_cabac_t *cb ); +} x264_bitstream_function_t; + +void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf ); + +/* A larger level table size theoretically could help a bit at extremely + * high bitrates, but the cost in cache is usually too high for it to be + * useful. + * This size appears to be optimal for QP18 encoding on a Nehalem CPU. + * FIXME: Do further testing? */ +#define LEVEL_TABLE_SIZE 128 +extern vlc_large_t x264_level_token[7][LEVEL_TABLE_SIZE]; + +/* The longest possible set of zero run codes sums to 25 bits. This leaves + * plenty of room for both the code (25 bits) and size (5 bits) in a uint32_t. */ + +extern uint32_t x264_run_before[1<<16]; + +static inline void bs_init( bs_t *s, void *p_data, int i_data ) +{ + int offset = ((intptr_t)p_data & 3); + s->p = s->p_start = (uint8_t*)p_data - offset; + s->p_end = (uint8_t*)p_data + i_data; + s->i_left = (WORD_SIZE - offset)*8; + s->cur_bits = endian_fix32( M32(s->p) ); + s->cur_bits >>= (4-offset)*8; +} +static inline int bs_pos( bs_t *s ) +{ + return( 8 * (s->p - s->p_start) + (WORD_SIZE*8) - s->i_left ); +} + +/* Write the rest of cur_bits to the bitstream; results in a bitstream no longer 32-bit aligned. */ +static inline void bs_flush( bs_t *s ) +{ + M32( s->p ) = endian_fix32( s->cur_bits << (s->i_left&31) ); + s->p += WORD_SIZE - (s->i_left >> 3); + s->i_left = WORD_SIZE*8; +} +/* The inverse of bs_flush: prepare the bitstream to be written to again. */ +static inline void bs_realign( bs_t *s ) +{ + int offset = ((intptr_t)s->p & 3); + if( offset ) + { + s->p = (uint8_t*)s->p - offset; + s->i_left = (WORD_SIZE - offset)*8; + s->cur_bits = endian_fix32( M32(s->p) ); + s->cur_bits >>= (4-offset)*8; + } +} + +static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits ) +{ + if( WORD_SIZE == 8 ) + { + s->cur_bits = (s->cur_bits << i_count) | i_bits; + s->i_left -= i_count; + if( s->i_left <= 32 ) + { +#if WORDS_BIGENDIAN + M32( s->p ) = s->cur_bits >> (32 - s->i_left); +#else + M32( s->p ) = endian_fix( s->cur_bits << s->i_left ); +#endif + s->i_left += 32; + s->p += 4; + } + } + else + { + if( i_count < s->i_left ) + { + s->cur_bits = (s->cur_bits << i_count) | i_bits; + s->i_left -= i_count; + } + else + { + i_count -= s->i_left; + s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count); + M32( s->p ) = endian_fix( s->cur_bits ); + s->p += 4; + s->cur_bits = i_bits; + s->i_left = 32 - i_count; + } + } +} + +/* Special case to eliminate branch in normal bs_write. */ +/* Golomb never writes an even-size code, so this is only used in slice headers. */ +static inline void bs_write32( bs_t *s, uint32_t i_bits ) +{ + bs_write( s, 16, i_bits >> 16 ); + bs_write( s, 16, i_bits ); +} + +static inline void bs_write1( bs_t *s, uint32_t i_bit ) +{ + s->cur_bits <<= 1; + s->cur_bits |= i_bit; + s->i_left--; + if( s->i_left == WORD_SIZE*8-32 ) + { + M32( s->p ) = endian_fix32( s->cur_bits ); + s->p += 4; + s->i_left = WORD_SIZE*8; + } +} + +static inline void bs_align_0( bs_t *s ) +{ + bs_write( s, s->i_left&7, 0 ); + bs_flush( s ); +} +static inline void bs_align_1( bs_t *s ) +{ + bs_write( s, s->i_left&7, (1 << (s->i_left&7)) - 1 ); + bs_flush( s ); +} +static inline void bs_align_10( bs_t *s ) +{ + if( s->i_left&7 ) + bs_write( s, s->i_left&7, 1 << ( (s->i_left&7) - 1 ) ); +} + +/* golomb functions */ + +static const uint8_t x264_ue_size_tab[256] = +{ + 1, 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +}; + +static inline void bs_write_ue_big( bs_t *s, unsigned int val ) +{ + int size = 0; + int tmp = ++val; + if( tmp >= 0x10000 ) + { + size = 32; + tmp >>= 16; + } + if( tmp >= 0x100 ) + { + size += 16; + tmp >>= 8; + } + size += x264_ue_size_tab[tmp]; + bs_write( s, size>>1, 0 ); + bs_write( s, (size>>1)+1, val ); +} + +/* Only works on values under 255. */ +static inline void bs_write_ue( bs_t *s, int val ) +{ + bs_write( s, x264_ue_size_tab[val+1], val+1 ); +} + +static inline void bs_write_se( bs_t *s, int val ) +{ + int size = 0; + /* Faster than (val <= 0 ? -val*2+1 : val*2) */ + /* 4 instructions on x86, 3 on ARM */ + int tmp = 1 - val*2; + if( tmp < 0 ) tmp = val*2; + val = tmp; + + if( tmp >= 0x100 ) + { + size = 16; + tmp >>= 8; + } + size += x264_ue_size_tab[tmp]; + bs_write( s, size, val ); +} + +static inline void bs_write_te( bs_t *s, int x, int val ) +{ + if( x == 1 ) + bs_write1( s, 1^val ); + else //if( x > 1 ) + bs_write_ue( s, val ); +} + +static inline void bs_rbsp_trailing( bs_t *s ) +{ + bs_write1( s, 1 ); + bs_write( s, s->i_left&7, 0 ); +} + +static ALWAYS_INLINE int bs_size_ue( unsigned int val ) +{ + return x264_ue_size_tab[val+1]; +} + +static ALWAYS_INLINE int bs_size_ue_big( unsigned int val ) +{ + if( val < 255 ) + return x264_ue_size_tab[val+1]; + else + return x264_ue_size_tab[(val+1)>>8] + 16; +} + +static ALWAYS_INLINE int bs_size_se( int val ) +{ + int tmp = 1 - val*2; + if( tmp < 0 ) tmp = val*2; + if( tmp < 256 ) + return x264_ue_size_tab[tmp]; + else + return x264_ue_size_tab[tmp>>8]+16; +} + +static ALWAYS_INLINE int bs_size_te( int x, int val ) +{ + if( x == 1 ) + return 1; + else //if( x > 1 ) + return x264_ue_size_tab[val+1]; +} + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cabac.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cabac.c new file mode 100644 index 00000000..14db0cd3 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cabac.c @@ -0,0 +1,1485 @@ +/***************************************************************************** + * cabac.c: arithmetic coder + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + + +static const int8_t x264_cabac_context_init_I[1024][2] = +{ + /* 0 - 10 */ + { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, + { 2, 54 }, { 3, 74 }, { -28,127 }, { -23, 104 }, + { -6, 53 }, { -1, 54 }, { 7, 51 }, + + /* 11 - 23 unused for I */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, + + /* 24- 39 */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + + /* 40 - 53 */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, + + /* 54 - 59 */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, + + /* 60 - 69 */ + { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, + { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, + { 13, 41 }, { 3, 62 }, + + /* 70 -> 87 */ + { 0, 11 }, { 1, 55 }, { 0, 69 }, { -17, 127 }, + { -13, 102 },{ 0, 82 }, { -7, 74 }, { -21, 107 }, + { -27, 127 },{ -31, 127 },{ -24, 127 }, { -18, 95 }, + { -27, 127 },{ -21, 114 },{ -30, 127 }, { -17, 123 }, + { -12, 115 },{ -16, 122 }, + + /* 88 -> 104 */ + { -11, 115 },{ -12, 63 }, { -2, 68 }, { -15, 84 }, + { -13, 104 },{ -3, 70 }, { -8, 93 }, { -10, 90 }, + { -30, 127 },{ -1, 74 }, { -6, 97 }, { -7, 91 }, + { -20, 127 },{ -4, 56 }, { -5, 82 }, { -7, 76 }, + { -22, 125 }, + + /* 105 -> 135 */ + { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, + { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, + { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, + { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, + { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, + { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, + { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, + { 14, 62 }, { -13, 108 },{ -15, 100 }, + + /* 136 -> 165 */ + { -13, 101 },{ -13, 91 }, { -12, 94 }, { -10, 88 }, + { -16, 84 }, { -10, 86 }, { -7, 83 }, { -13, 87 }, + { -19, 94 }, { 1, 70 }, { 0, 72 }, { -5, 74 }, + { 18, 59 }, { -8, 102 }, { -15, 100 }, { 0, 95 }, + { -4, 75 }, { 2, 72 }, { -11, 75 }, { -3, 71 }, + { 15, 46 }, { -13, 69 }, { 0, 62 }, { 0, 65 }, + { 21, 37 }, { -15, 72 }, { 9, 57 }, { 16, 54 }, + { 0, 62 }, { 12, 72 }, + + /* 166 -> 196 */ + { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, + { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, + { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, + { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, + { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, + { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, + { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, + { 0, 89 }, { 26, -19 }, { 22, -17 }, + + /* 197 -> 226 */ + { 26, -17 }, { 30, -25 }, { 28, -20 }, { 33, -23 }, + { 37, -27 }, { 33, -23 }, { 40, -28 }, { 38, -17 }, + { 33, -11 }, { 40, -15 }, { 41, -6 }, { 38, 1 }, + { 41, 17 }, { 30, -6 }, { 27, 3 }, { 26, 22 }, + { 37, -16 }, { 35, -4 }, { 38, -8 }, { 38, -3 }, + { 37, 3 }, { 38, 5 }, { 42, 0 }, { 35, 16 }, + { 39, 22 }, { 14, 48 }, { 27, 37 }, { 21, 60 }, + { 12, 68 }, { 2, 97 }, + + /* 227 -> 251 */ + { -3, 71 }, { -6, 42 }, { -5, 50 }, { -3, 54 }, + { -2, 62 }, { 0, 58 }, { 1, 63 }, { -2, 72 }, + { -1, 74 }, { -9, 91 }, { -5, 67 }, { -5, 27 }, + { -3, 39 }, { -2, 44 }, { 0, 46 }, { -16, 64 }, + { -8, 68 }, { -10, 78 }, { -6, 77 }, { -10, 86 }, + { -12, 92 }, { -15, 55 }, { -10, 60 }, { -6, 62 }, + { -4, 65 }, + + /* 252 -> 275 */ + { -12, 73 }, { -8, 76 }, { -7, 80 }, { -9, 88 }, + { -17, 110 },{ -11, 97 }, { -20, 84 }, { -11, 79 }, + { -6, 73 }, { -4, 74 }, { -13, 86 }, { -13, 96 }, + { -11, 97 }, { -19, 117 },{ -8, 78 }, { -5, 33 }, + { -4, 48 }, { -2, 53 }, { -3, 62 }, { -13, 71 }, + { -10, 79 }, { -12, 86 }, { -13, 90 }, { -14, 97 }, + + /* 276 a bit special (not used, x264_cabac_encode_bypass is used instead) */ + { 0, 0 }, + + /* 277 -> 307 */ + { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, + { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, + { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, + { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, + { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, + { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, + { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, + { 9, 64 }, { -12, 104 },{ -11, 97 }, + + /* 308 -> 337 */ + { -16, 96 }, { -7, 88 }, { -8, 85 }, { -7, 85 }, + { -9, 85 }, { -13, 88 }, { 4, 66 }, { -3, 77 }, + { -3, 76 }, { -6, 76 }, { 10, 58 }, { -1, 76 }, + { -1, 83 }, { -7, 99 }, { -14, 95 }, { 2, 95 }, + { 0, 76 }, { -5, 74 }, { 0, 70 }, { -11, 75 }, + { 1, 68 }, { 0, 65 }, { -14, 73 }, { 3, 62 }, + { 4, 62 }, { -1, 68 }, { -13, 75 }, { 11, 55 }, + { 5, 64 }, { 12, 70 }, + + /* 338 -> 368 */ + { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, + { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, + { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, + { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, + { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, + { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, + { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, + { -12, 109 },{ 36, -35 }, { 36, -34 }, + + /* 369 -> 398 */ + { 32, -26 }, { 37, -30 }, { 44, -32 }, { 34, -18 }, + { 34, -15 }, { 40, -15 }, { 33, -7 }, { 35, -5 }, + { 33, 0 }, { 38, 2 }, { 33, 13 }, { 23, 35 }, + { 13, 58 }, { 29, -3 }, { 26, 0 }, { 22, 30 }, + { 31, -7 }, { 35, -15 }, { 34, -3 }, { 34, 3 }, + { 36, -1 }, { 34, 5 }, { 32, 11 }, { 35, 5 }, + { 34, 12 }, { 39, 11 }, { 30, 29 }, { 34, 26 }, + { 29, 39 }, { 19, 66 }, + + /* 399 -> 435 */ + { 31, 21 }, { 31, 31 }, { 25, 50 }, + { -17, 120 }, { -20, 112 }, { -18, 114 }, { -11, 85 }, + { -15, 92 }, { -14, 89 }, { -26, 71 }, { -15, 81 }, + { -14, 80 }, { 0, 68 }, { -14, 70 }, { -24, 56 }, + { -23, 68 }, { -24, 50 }, { -11, 74 }, { 23, -13 }, + { 26, -13 }, { 40, -15 }, { 49, -14 }, { 44, 3 }, + { 45, 6 }, { 44, 34 }, { 33, 54 }, { 19, 82 }, + { -3, 75 }, { -1, 23 }, { 1, 34 }, { 1, 43 }, + { 0, 54 }, { -2, 55 }, { 0, 61 }, { 1, 64 }, + { 0, 68 }, { -9, 92 }, + + /* 436 -> 459 */ + { -14, 106 }, { -13, 97 }, { -15, 90 }, { -12, 90 }, + { -18, 88 }, { -10, 73 }, { -9, 79 }, { -14, 86 }, + { -10, 73 }, { -10, 70 }, { -10, 69 }, { -5, 66 }, + { -9, 64 }, { -5, 58 }, { 2, 59 }, { 21, -10 }, + { 24, -11 }, { 28, -8 }, { 28, -1 }, { 29, 3 }, + { 29, 9 }, { 35, 20 }, { 29, 36 }, { 14, 67 }, + + /* 460 -> 1024 */ + { -17, 123 }, { -12, 115 }, { -16, 122 }, { -11, 115 }, + { -12, 63 }, { -2, 68 }, { -15, 84 }, { -13, 104 }, + { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, + { -17, 123 }, { -12, 115 }, { -16, 122 }, { -11, 115 }, + { -12, 63 }, { -2, 68 }, { -15, 84 }, { -13, 104 }, + { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, + { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, + { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, + { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, + { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, + { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, + { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, + { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, + { 14, 62 }, { -13, 108 }, { -15, 100 }, { -13, 101 }, + { -13, 91 }, { -12, 94 }, { -10, 88 }, { -16, 84 }, + { -10, 86 }, { -7, 83 }, { -13, 87 }, { -19, 94 }, + { 1, 70 }, { 0, 72 }, { -5, 74 }, { 18, 59 }, + { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, + { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, + { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, + { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, + { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, + { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, + { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, + { 14, 62 }, { -13, 108 }, { -15, 100 }, { -13, 101 }, + { -13, 91 }, { -12, 94 }, { -10, 88 }, { -16, 84 }, + { -10, 86 }, { -7, 83 }, { -13, 87 }, { -19, 94 }, + { 1, 70 }, { 0, 72 }, { -5, 74 }, { 18, 59 }, + { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, + { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, + { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, + { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, + { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, + { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, + { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, + { 0, 89 }, { 26, -19 }, { 22, -17 }, { 26, -17 }, + { 30, -25 }, { 28, -20 }, { 33, -23 }, { 37, -27 }, + { 33, -23 }, { 40, -28 }, { 38, -17 }, { 33, -11 }, + { 40, -15 }, { 41, -6 }, { 38, 1 }, { 41, 17 }, + { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, + { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, + { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, + { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, + { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, + { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, + { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, + { 0, 89 }, { 26, -19 }, { 22, -17 }, { 26, -17 }, + { 30, -25 }, { 28, -20 }, { 33, -23 }, { 37, -27 }, + { 33, -23 }, { 40, -28 }, { 38, -17 }, { 33, -11 }, + { 40, -15 }, { 41, -6 }, { 38, 1 }, { 41, 17 }, + { -17, 120 }, { -20, 112 }, { -18, 114 }, { -11, 85 }, + { -15, 92 }, { -14, 89 }, { -26, 71 }, { -15, 81 }, + { -14, 80 }, { 0, 68 }, { -14, 70 }, { -24, 56 }, + { -23, 68 }, { -24, 50 }, { -11, 74 }, { -14, 106 }, + { -13, 97 }, { -15, 90 }, { -12, 90 }, { -18, 88 }, + { -10, 73 }, { -9, 79 }, { -14, 86 }, { -10, 73 }, + { -10, 70 }, { -10, 69 }, { -5, 66 }, { -9, 64 }, + { -5, 58 }, { 2, 59 }, { 23, -13 }, { 26, -13 }, + { 40, -15 }, { 49, -14 }, { 44, 3 }, { 45, 6 }, + { 44, 34 }, { 33, 54 }, { 19, 82 }, { 21, -10 }, + { 24, -11 }, { 28, -8 }, { 28, -1 }, { 29, 3 }, + { 29, 9 }, { 35, 20 }, { 29, 36 }, { 14, 67 }, + { -3, 75 }, { -1, 23 }, { 1, 34 }, { 1, 43 }, + { 0, 54 }, { -2, 55 }, { 0, 61 }, { 1, 64 }, + { 0, 68 }, { -9, 92 }, { -17, 120 }, { -20, 112 }, + { -18, 114 }, { -11, 85 }, { -15, 92 }, { -14, 89 }, + { -26, 71 }, { -15, 81 }, { -14, 80 }, { 0, 68 }, + { -14, 70 }, { -24, 56 }, { -23, 68 }, { -24, 50 }, + { -11, 74 }, { -14, 106 }, { -13, 97 }, { -15, 90 }, + { -12, 90 }, { -18, 88 }, { -10, 73 }, { -9, 79 }, + { -14, 86 }, { -10, 73 }, { -10, 70 }, { -10, 69 }, + { -5, 66 }, { -9, 64 }, { -5, 58 }, { 2, 59 }, + { 23, -13 }, { 26, -13 }, { 40, -15 }, { 49, -14 }, + { 44, 3 }, { 45, 6 }, { 44, 34 }, { 33, 54 }, + { 19, 82 }, { 21, -10 }, { 24, -11 }, { 28, -8 }, + { 28, -1 }, { 29, 3 }, { 29, 9 }, { 35, 20 }, + { 29, 36 }, { 14, 67 }, { -3, 75 }, { -1, 23 }, + { 1, 34 }, { 1, 43 }, { 0, 54 }, { -2, 55 }, + { 0, 61 }, { 1, 64 }, { 0, 68 }, { -9, 92 }, + { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, + { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, + { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, + { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, + { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, + { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, + { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, + { 9, 64 }, { -12, 104 }, { -11, 97 }, { -16, 96 }, + { -7, 88 }, { -8, 85 }, { -7, 85 }, { -9, 85 }, + { -13, 88 }, { 4, 66 }, { -3, 77 }, { -3, 76 }, + { -6, 76 }, { 10, 58 }, { -1, 76 }, { -1, 83 }, + { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, + { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, + { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, + { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, + { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, + { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, + { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, + { 9, 64 }, { -12, 104 }, { -11, 97 }, { -16, 96 }, + { -7, 88 }, { -8, 85 }, { -7, 85 }, { -9, 85 }, + { -13, 88 }, { 4, 66 }, { -3, 77 }, { -3, 76 }, + { -6, 76 }, { 10, 58 }, { -1, 76 }, { -1, 83 }, + { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, + { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, + { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, + { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, + { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, + { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, + { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, + { -12, 109 }, { 36, -35 }, { 36, -34 }, { 32, -26 }, + { 37, -30 }, { 44, -32 }, { 34, -18 }, { 34, -15 }, + { 40, -15 }, { 33, -7 }, { 35, -5 }, { 33, 0 }, + { 38, 2 }, { 33, 13 }, { 23, 35 }, { 13, 58 }, + { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, + { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, + { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, + { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, + { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, + { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, + { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, + { -12, 109 }, { 36, -35 }, { 36, -34 }, { 32, -26 }, + { 37, -30 }, { 44, -32 }, { 34, -18 }, { 34, -15 }, + { 40, -15 }, { 33, -7 }, { 35, -5 }, { 33, 0 }, + { 38, 2 }, { 33, 13 }, { 23, 35 }, { 13, 58 }, + { -3, 71 }, { -6, 42 }, { -5, 50 }, { -3, 54 }, + { -2, 62 }, { 0, 58 }, { 1, 63 }, { -2, 72 }, + { -1, 74 }, { -9, 91 }, { -5, 67 }, { -5, 27 }, + { -3, 39 }, { -2, 44 }, { 0, 46 }, { -16, 64 }, + { -8, 68 }, { -10, 78 }, { -6, 77 }, { -10, 86 }, + { -12, 92 }, { -15, 55 }, { -10, 60 }, { -6, 62 }, + { -4, 65 }, { -12, 73 }, { -8, 76 }, { -7, 80 }, + { -9, 88 }, { -17, 110 }, { -3, 71 }, { -6, 42 }, + { -5, 50 }, { -3, 54 }, { -2, 62 }, { 0, 58 }, + { 1, 63 }, { -2, 72 }, { -1, 74 }, { -9, 91 }, + { -5, 67 }, { -5, 27 }, { -3, 39 }, { -2, 44 }, + { 0, 46 }, { -16, 64 }, { -8, 68 }, { -10, 78 }, + { -6, 77 }, { -10, 86 }, { -12, 92 }, { -15, 55 }, + { -10, 60 }, { -6, 62 }, { -4, 65 }, { -12, 73 }, + { -8, 76 }, { -7, 80 }, { -9, 88 }, { -17, 110 }, + { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, + { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, + { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 } +}; + +static const int8_t x264_cabac_context_init_PB[3][1024][2] = +{ + /* i_cabac_init_idc == 0 */ + { + /* 0 - 10 */ + { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, + { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, + { -6, 53 }, { -1, 54 }, { 7, 51 }, + + /* 11 - 23 */ + { 23, 33 }, { 23, 2 }, { 21, 0 }, { 1, 9 }, + { 0, 49 }, { -37, 118 }, { 5, 57 }, { -13, 78 }, + { -11, 65 }, { 1, 62 }, { 12, 49 }, { -4, 73 }, + { 17, 50 }, + + /* 24 - 39 */ + { 18, 64 }, { 9, 43 }, { 29, 0 }, { 26, 67 }, + { 16, 90 }, { 9, 104 }, { -46, 127 }, { -20, 104 }, + { 1, 67 }, { -13, 78 }, { -11, 65 }, { 1, 62 }, + { -6, 86 }, { -17, 95 }, { -6, 61 }, { 9, 45 }, + + /* 40 - 53 */ + { -3, 69 }, { -6, 81 }, { -11, 96 }, { 6, 55 }, + { 7, 67 }, { -5, 86 }, { 2, 88 }, { 0, 58 }, + { -3, 76 }, { -10, 94 }, { 5, 54 }, { 4, 69 }, + { -3, 81 }, { 0, 88 }, + + /* 54 - 59 */ + { -7, 67 }, { -5, 74 }, { -4, 74 }, { -5, 80 }, + { -7, 72 }, { 1, 58 }, + + /* 60 - 69 */ + { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, + { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, + { 13, 41 }, { 3, 62 }, + + /* 70 - 87 */ + { 0, 45 }, { -4, 78 }, { -3, 96 }, { -27, 126 }, + { -28, 98 }, { -25, 101 }, { -23, 67 }, { -28, 82 }, + { -20, 94 }, { -16, 83 }, { -22, 110 }, { -21, 91 }, + { -18, 102 }, { -13, 93 }, { -29, 127 }, { -7, 92 }, + { -5, 89 }, { -7, 96 }, { -13, 108 }, { -3, 46 }, + { -1, 65 }, { -1, 57 }, { -9, 93 }, { -3, 74 }, + { -9, 92 }, { -8, 87 }, { -23, 126 }, { 5, 54 }, + { 6, 60 }, { 6, 59 }, { 6, 69 }, { -1, 48 }, + { 0, 68 }, { -4, 69 }, { -8, 88 }, + + /* 105 -> 165 */ + { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, + { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, + { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, + { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, + { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, + { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, + { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, + { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, + { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, + { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, + { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, + { 3, 64 }, { 1, 61 }, { 9, 63 }, { 7, 50 }, + { 16, 39 }, { 5, 44 }, { 4, 52 }, { 11, 48 }, + { -5, 60 }, { -1, 59 }, { 0, 59 }, { 22, 33 }, + { 5, 44 }, { 14, 43 }, { -1, 78 }, { 0, 60 }, + { 9, 69 }, + + /* 166 - 226 */ + { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, + { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, + { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, + { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, + { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, + { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, + { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, + { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, + { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, + { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, + { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, + { 1, 67 }, { 5, 59 }, { 9, 67 }, { 16, 30 }, + { 18, 32 }, { 18, 35 }, { 22, 29 }, { 24, 31 }, + { 23, 38 }, { 18, 43 }, { 20, 41 }, { 11, 63 }, + { 9, 59 }, { 9, 64 }, { -1, 94 }, { -2, 89 }, + { -9, 108 }, + + /* 227 - 275 */ + { -6, 76 }, { -2, 44 }, { 0, 45 }, { 0, 52 }, + { -3, 64 }, { -2, 59 }, { -4, 70 }, { -4, 75 }, + { -8, 82 }, { -17, 102 }, { -9, 77 }, { 3, 24 }, + { 0, 42 }, { 0, 48 }, { 0, 55 }, { -6, 59 }, + { -7, 71 }, { -12, 83 }, { -11, 87 }, { -30, 119 }, + { 1, 58 }, { -3, 29 }, { -1, 36 }, { 1, 38 }, + { 2, 43 }, { -6, 55 }, { 0, 58 }, { 0, 64 }, + { -3, 74 }, { -10, 90 }, { 0, 70 }, { -4, 29 }, + { 5, 31 }, { 7, 42 }, { 1, 59 }, { -2, 58 }, + { -3, 72 }, { -3, 81 }, { -11, 97 }, { 0, 58 }, + { 8, 5 }, { 10, 14 }, { 14, 18 }, { 13, 27 }, + { 2, 40 }, { 0, 58 }, { -3, 70 }, { -6, 79 }, + { -8, 85 }, + + /* 276 a bit special (not used, x264_cabac_encode_bypass is used instead) */ + { 0, 0 }, + + /* 277 - 337 */ + { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, + { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, + { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, + { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, + { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, + { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, + { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, + { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, + { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, + { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, + { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, + { -2, 69 }, { -2, 59 }, { 6, 70 }, { 10, 44 }, + { 9, 31 }, { 12, 43 }, { 3, 53 }, { 14, 34 }, + { 10, 38 }, { -3, 52 }, { 13, 40 }, { 17, 32 }, + { 7, 44 }, { 7, 38 }, { 13, 50 }, { 10, 57 }, + { 26, 43 }, + + /* 338 - 398 */ + { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, + { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, + { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, + { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, + { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, + { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, + { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, + { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, + { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, + { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, + { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, + { 8, 60 }, { 6, 63 }, { 17, 65 }, { 21, 24 }, + { 23, 20 }, { 26, 23 }, { 27, 32 }, { 28, 23 }, + { 28, 24 }, { 23, 40 }, { 24, 32 }, { 28, 29 }, + { 23, 42 }, { 19, 57 }, { 22, 53 }, { 22, 61 }, + { 11, 86 }, + + /* 399 -> 435 */ + { 12, 40 }, { 11, 51 }, { 14, 59 }, + { -4, 79 }, { -7, 71 }, { -5, 69 }, { -9, 70 }, + { -8, 66 }, { -10, 68 }, { -19, 73 }, { -12, 69 }, + { -16, 70 }, { -15, 67 }, { -20, 62 }, { -19, 70 }, + { -16, 66 }, { -22, 65 }, { -20, 63 }, { 9, -2 }, + { 26, -9 }, { 33, -9 }, { 39, -7 }, { 41, -2 }, + { 45, 3 }, { 49, 9 }, { 45, 27 }, { 36, 59 }, + { -6, 66 }, { -7, 35 }, { -7, 42 }, { -8, 45 }, + { -5, 48 }, { -12, 56 }, { -6, 60 }, { -5, 62 }, + { -8, 66 }, { -8, 76 }, + + /* 436 -> 459 */ + { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, + { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, + { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, + { -14, 66 }, { 0, 59 }, { 2, 59 }, { 21, -13 }, + { 33, -14 }, { 39, -7 }, { 46, -2 }, { 51, 2 }, + { 60, 6 }, { 61, 17 }, { 55, 34 }, { 42, 62 }, + + /* 460 - 1024 */ + { -7, 92 }, { -5, 89 }, { -7, 96 }, { -13, 108 }, + { -3, 46 }, { -1, 65 }, { -1, 57 }, { -9, 93 }, + { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, + { -7, 92 }, { -5, 89 }, { -7, 96 }, { -13, 108 }, + { -3, 46 }, { -1, 65 }, { -1, 57 }, { -9, 93 }, + { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, + { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, + { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, + { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, + { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, + { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, + { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, + { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, + { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, + { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, + { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, + { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, + { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, + { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, + { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, + { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, + { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, + { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, + { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, + { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, + { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, + { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, + { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, + { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, + { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, + { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, + { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, + { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, + { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, + { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, + { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, + { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, + { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, + { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, + { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, + { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, + { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, + { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, + { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, + { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, + { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, + { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, + { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, + { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, + { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, + { -4, 79 }, { -7, 71 }, { -5, 69 }, { -9, 70 }, + { -8, 66 }, { -10, 68 }, { -19, 73 }, { -12, 69 }, + { -16, 70 }, { -15, 67 }, { -20, 62 }, { -19, 70 }, + { -16, 66 }, { -22, 65 }, { -20, 63 }, { -5, 85 }, + { -6, 81 }, { -10, 77 }, { -7, 81 }, { -17, 80 }, + { -18, 73 }, { -4, 74 }, { -10, 83 }, { -9, 71 }, + { -9, 67 }, { -1, 61 }, { -8, 66 }, { -14, 66 }, + { 0, 59 }, { 2, 59 }, { 9, -2 }, { 26, -9 }, + { 33, -9 }, { 39, -7 }, { 41, -2 }, { 45, 3 }, + { 49, 9 }, { 45, 27 }, { 36, 59 }, { 21, -13 }, + { 33, -14 }, { 39, -7 }, { 46, -2 }, { 51, 2 }, + { 60, 6 }, { 61, 17 }, { 55, 34 }, { 42, 62 }, + { -6, 66 }, { -7, 35 }, { -7, 42 }, { -8, 45 }, + { -5, 48 }, { -12, 56 }, { -6, 60 }, { -5, 62 }, + { -8, 66 }, { -8, 76 }, { -4, 79 }, { -7, 71 }, + { -5, 69 }, { -9, 70 }, { -8, 66 }, { -10, 68 }, + { -19, 73 }, { -12, 69 }, { -16, 70 }, { -15, 67 }, + { -20, 62 }, { -19, 70 }, { -16, 66 }, { -22, 65 }, + { -20, 63 }, { -5, 85 }, { -6, 81 }, { -10, 77 }, + { -7, 81 }, { -17, 80 }, { -18, 73 }, { -4, 74 }, + { -10, 83 }, { -9, 71 }, { -9, 67 }, { -1, 61 }, + { -8, 66 }, { -14, 66 }, { 0, 59 }, { 2, 59 }, + { 9, -2 }, { 26, -9 }, { 33, -9 }, { 39, -7 }, + { 41, -2 }, { 45, 3 }, { 49, 9 }, { 45, 27 }, + { 36, 59 }, { 21, -13 }, { 33, -14 }, { 39, -7 }, + { 46, -2 }, { 51, 2 }, { 60, 6 }, { 61, 17 }, + { 55, 34 }, { 42, 62 }, { -6, 66 }, { -7, 35 }, + { -7, 42 }, { -8, 45 }, { -5, 48 }, { -12, 56 }, + { -6, 60 }, { -5, 62 }, { -8, 66 }, { -8, 76 }, + { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, + { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, + { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, + { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, + { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, + { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, + { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, + { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, + { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, + { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, + { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, + { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, + { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, + { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, + { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, + { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, + { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, + { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, + { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, + { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, + { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, + { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, + { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, + { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, + { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, + { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, + { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, + { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, + { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, + { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, + { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, + { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, + { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, + { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, + { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, + { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, + { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, + { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, + { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, + { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, + { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, + { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, + { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, + { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, + { -6, 76 }, { -2, 44 }, { 0, 45 }, { 0, 52 }, + { -3, 64 }, { -2, 59 }, { -4, 70 }, { -4, 75 }, + { -8, 82 }, { -17, 102 }, { -9, 77 }, { 3, 24 }, + { 0, 42 }, { 0, 48 }, { 0, 55 }, { -6, 59 }, + { -7, 71 }, { -12, 83 }, { -11, 87 }, { -30, 119 }, + { 1, 58 }, { -3, 29 }, { -1, 36 }, { 1, 38 }, + { 2, 43 }, { -6, 55 }, { 0, 58 }, { 0, 64 }, + { -3, 74 }, { -10, 90 }, { -6, 76 }, { -2, 44 }, + { 0, 45 }, { 0, 52 }, { -3, 64 }, { -2, 59 }, + { -4, 70 }, { -4, 75 }, { -8, 82 }, { -17, 102 }, + { -9, 77 }, { 3, 24 }, { 0, 42 }, { 0, 48 }, + { 0, 55 }, { -6, 59 }, { -7, 71 }, { -12, 83 }, + { -11, 87 }, { -30, 119 }, { 1, 58 }, { -3, 29 }, + { -1, 36 }, { 1, 38 }, { 2, 43 }, { -6, 55 }, + { 0, 58 }, { 0, 64 }, { -3, 74 }, { -10, 90 }, + { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, + { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, + { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 } + }, + + /* i_cabac_init_idc == 1 */ + { + /* 0 - 10 */ + { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, + { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, + { -6, 53 }, { -1, 54 }, { 7, 51 }, + + /* 11 - 23 */ + { 22, 25 }, { 34, 0 }, { 16, 0 }, { -2, 9 }, + { 4, 41 }, { -29, 118 }, { 2, 65 }, { -6, 71 }, + { -13, 79 }, { 5, 52 }, { 9, 50 }, { -3, 70 }, + { 10, 54 }, + + /* 24 - 39 */ + { 26, 34 }, { 19, 22 }, { 40, 0 }, { 57, 2 }, + { 41, 36 }, { 26, 69 }, { -45, 127 }, { -15, 101 }, + { -4, 76 }, { -6, 71 }, { -13, 79 }, { 5, 52 }, + { 6, 69 }, { -13, 90 }, { 0, 52 }, { 8, 43 }, + + /* 40 - 53 */ + { -2, 69 },{ -5, 82 },{ -10, 96 },{ 2, 59 }, + { 2, 75 },{ -3, 87 },{ -3, 100 },{ 1, 56 }, + { -3, 74 },{ -6, 85 },{ 0, 59 },{ -3, 81 }, + { -7, 86 },{ -5, 95 }, + + /* 54 - 59 */ + { -1, 66 },{ -1, 77 },{ 1, 70 },{ -2, 86 }, + { -5, 72 },{ 0, 61 }, + + /* 60 - 69 */ + { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, + { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, + { 13, 41 }, { 3, 62 }, + + /* 70 - 104 */ + { 13, 15 }, { 7, 51 }, { 2, 80 }, { -39, 127 }, + { -18, 91 }, { -17, 96 }, { -26, 81 }, { -35, 98 }, + { -24, 102 }, { -23, 97 }, { -27, 119 }, { -24, 99 }, + { -21, 110 }, { -18, 102 }, { -36, 127 }, { 0, 80 }, + { -5, 89 }, { -7, 94 }, { -4, 92 }, { 0, 39 }, + { 0, 65 }, { -15, 84 }, { -35, 127 }, { -2, 73 }, + { -12, 104 }, { -9, 91 }, { -31, 127 }, { 3, 55 }, + { 7, 56 }, { 7, 55 }, { 8, 61 }, { -3, 53 }, + { 0, 68 }, { -7, 74 }, { -9, 88 }, + + /* 105 -> 165 */ + { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, + { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, + { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, + { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, + { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, + { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, + { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, + { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, + { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, + { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, + { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, + { -4, 71 }, { 0, 58 }, { 7, 61 }, { 9, 41 }, + { 18, 25 }, { 9, 32 }, { 5, 43 }, { 9, 47 }, + { 0, 44 }, { 0, 51 }, { 2, 46 }, { 19, 38 }, + { -4, 66 }, { 15, 38 }, { 12, 42 }, { 9, 34 }, + { 0, 89 }, + + /* 166 - 226 */ + { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, + { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, + { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, + { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, + { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, + { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, + { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, + { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, + { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, + { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, + { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, + { 0, 75 }, { 2, 72 }, { 8, 77 }, { 14, 35 }, + { 18, 31 }, { 17, 35 }, { 21, 30 }, { 17, 45 }, + { 20, 42 }, { 18, 45 }, { 27, 26 }, { 16, 54 }, + { 7, 66 }, { 16, 56 }, { 11, 73 }, { 10, 67 }, + { -10, 116 }, + + /* 227 - 275 */ + { -23, 112 }, { -15, 71 }, { -7, 61 }, { 0, 53 }, + { -5, 66 }, { -11, 77 }, { -9, 80 }, { -9, 84 }, + { -10, 87 }, { -34, 127 }, { -21, 101 }, { -3, 39 }, + { -5, 53 }, { -7, 61 }, { -11, 75 }, { -15, 77 }, + { -17, 91 }, { -25, 107 }, { -25, 111 }, { -28, 122 }, + { -11, 76 }, { -10, 44 }, { -10, 52 }, { -10, 57 }, + { -9, 58 }, { -16, 72 }, { -7, 69 }, { -4, 69 }, + { -5, 74 }, { -9, 86 }, { 2, 66 }, { -9, 34 }, + { 1, 32 }, { 11, 31 }, { 5, 52 }, { -2, 55 }, + { -2, 67 }, { 0, 73 }, { -8, 89 }, { 3, 52 }, + { 7, 4 }, { 10, 8 }, { 17, 8 }, { 16, 19 }, + { 3, 37 }, { -1, 61 }, { -5, 73 }, { -1, 70 }, + { -4, 78 }, + + /* 276 a bit special (not used, x264_cabac_encode_bypass is used instead) */ + { 0, 0 }, + + /* 277 - 337 */ + { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, + { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, + { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, + { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, + { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, + { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, + { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, + { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, + { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, + { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, + { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, + { -1, 70 }, { -9, 72 }, { 14, 60 }, { 16, 37 }, + { 0, 47 }, { 18, 35 }, { 11, 37 }, { 12, 41 }, + { 10, 41 }, { 2, 48 }, { 12, 41 }, { 13, 41 }, + { 0, 59 }, { 3, 50 }, { 19, 40 }, { 3, 66 }, + { 18, 50 }, + + /* 338 - 398 */ + { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, + { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, + { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, + { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, + { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, + { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, + { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, + { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, + { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, + { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, + { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, + { 12, 48 }, { 11, 49 }, { 26, 45 }, { 22, 22 }, + { 23, 22 }, { 27, 21 }, { 33, 20 }, { 26, 28 }, + { 30, 24 }, { 27, 34 }, { 18, 42 }, { 25, 39 }, + { 18, 50 }, { 12, 70 }, { 21, 54 }, { 14, 71 }, + { 11, 83 }, + + /* 399 -> 435 */ + { 25, 32 }, { 21, 49 }, { 21, 54 }, + { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, + { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, + { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, + { -14, 66 }, { 0, 59 }, { 2, 59 }, { 17, -10 }, + { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, + { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, + { -5, 71 }, { 0, 24 }, { -1, 36 }, { -2, 42 }, + { -2, 52 }, { -9, 57 }, { -6, 63 }, { -4, 65 }, + { -4, 67 }, { -7, 82 }, + + /* 436 -> 459 */ + { -3, 81 }, { -3, 76 }, { -7, 72 }, { -6, 78 }, + { -12, 72 }, { -14, 68 }, { -3, 70 }, { -6, 76 }, + { -5, 66 }, { -5, 62 }, { 0, 57 }, { -4, 61 }, + { -9, 60 }, { 1, 54 }, { 2, 58 }, { 17, -10 }, + { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, + { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, + + /* 460 - 1024 */ + { 0, 80 }, { -5, 89 }, { -7, 94 }, { -4, 92 }, + { 0, 39 }, { 0, 65 }, { -15, 84 }, { -35, 127 }, + { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, + { 0, 80 }, { -5, 89 }, { -7, 94 }, { -4, 92 }, + { 0, 39 }, { 0, 65 }, { -15, 84 }, { -35, 127 }, + { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, + { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, + { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, + { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, + { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, + { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, + { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, + { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, + { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, + { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, + { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, + { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, + { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, + { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, + { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, + { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, + { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, + { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, + { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, + { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, + { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, + { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, + { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, + { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, + { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, + { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, + { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, + { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, + { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, + { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, + { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, + { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, + { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, + { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, + { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, + { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, + { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, + { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, + { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, + { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, + { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, + { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, + { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, + { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, + { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, + { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, + { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, + { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, + { -14, 66 }, { 0, 59 }, { 2, 59 }, { -3, 81 }, + { -3, 76 }, { -7, 72 }, { -6, 78 }, { -12, 72 }, + { -14, 68 }, { -3, 70 }, { -6, 76 }, { -5, 66 }, + { -5, 62 }, { 0, 57 }, { -4, 61 }, { -9, 60 }, + { 1, 54 }, { 2, 58 }, { 17, -10 }, { 32, -13 }, + { 42, -9 }, { 49, -5 }, { 53, 0 }, { 64, 3 }, + { 68, 10 }, { 66, 27 }, { 47, 57 }, { 17, -10 }, + { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, + { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, + { -5, 71 }, { 0, 24 }, { -1, 36 }, { -2, 42 }, + { -2, 52 }, { -9, 57 }, { -6, 63 }, { -4, 65 }, + { -4, 67 }, { -7, 82 }, { -5, 85 }, { -6, 81 }, + { -10, 77 }, { -7, 81 }, { -17, 80 }, { -18, 73 }, + { -4, 74 }, { -10, 83 }, { -9, 71 }, { -9, 67 }, + { -1, 61 }, { -8, 66 }, { -14, 66 }, { 0, 59 }, + { 2, 59 }, { -3, 81 }, { -3, 76 }, { -7, 72 }, + { -6, 78 }, { -12, 72 }, { -14, 68 }, { -3, 70 }, + { -6, 76 }, { -5, 66 }, { -5, 62 }, { 0, 57 }, + { -4, 61 }, { -9, 60 }, { 1, 54 }, { 2, 58 }, + { 17, -10 }, { 32, -13 }, { 42, -9 }, { 49, -5 }, + { 53, 0 }, { 64, 3 }, { 68, 10 }, { 66, 27 }, + { 47, 57 }, { 17, -10 }, { 32, -13 }, { 42, -9 }, + { 49, -5 }, { 53, 0 }, { 64, 3 }, { 68, 10 }, + { 66, 27 }, { 47, 57 }, { -5, 71 }, { 0, 24 }, + { -1, 36 }, { -2, 42 }, { -2, 52 }, { -9, 57 }, + { -6, 63 }, { -4, 65 }, { -4, 67 }, { -7, 82 }, + { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, + { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, + { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, + { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, + { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, + { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, + { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, + { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, + { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, + { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, + { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, + { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, + { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, + { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, + { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, + { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, + { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, + { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, + { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, + { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, + { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, + { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, + { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, + { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, + { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, + { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, + { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, + { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, + { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, + { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, + { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, + { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, + { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, + { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, + { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, + { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, + { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, + { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, + { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, + { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, + { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, + { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, + { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, + { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, + { -23, 112 }, { -15, 71 }, { -7, 61 }, { 0, 53 }, + { -5, 66 }, { -11, 77 }, { -9, 80 }, { -9, 84 }, + { -10, 87 }, { -34, 127 }, { -21, 101 }, { -3, 39 }, + { -5, 53 }, { -7, 61 }, { -11, 75 }, { -15, 77 }, + { -17, 91 }, { -25, 107 }, { -25, 111 }, { -28, 122 }, + { -11, 76 }, { -10, 44 }, { -10, 52 }, { -10, 57 }, + { -9, 58 }, { -16, 72 }, { -7, 69 }, { -4, 69 }, + { -5, 74 }, { -9, 86 }, { -23, 112 }, { -15, 71 }, + { -7, 61 }, { 0, 53 }, { -5, 66 }, { -11, 77 }, + { -9, 80 }, { -9, 84 }, { -10, 87 }, { -34, 127 }, + { -21, 101 }, { -3, 39 }, { -5, 53 }, { -7, 61 }, + { -11, 75 }, { -15, 77 }, { -17, 91 }, { -25, 107 }, + { -25, 111 }, { -28, 122 }, { -11, 76 }, { -10, 44 }, + { -10, 52 }, { -10, 57 }, { -9, 58 }, { -16, 72 }, + { -7, 69 }, { -4, 69 }, { -5, 74 }, { -9, 86 }, + { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, + { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, + { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 } + }, + + /* i_cabac_init_idc == 2 */ + { + /* 0 - 10 */ + { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, + { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, + { -6, 53 }, { -1, 54 }, { 7, 51 }, + + /* 11 - 23 */ + { 29, 16 }, { 25, 0 }, { 14, 0 }, { -10, 51 }, + { -3, 62 }, { -27, 99 }, { 26, 16 }, { -4, 85 }, + { -24, 102 }, { 5, 57 }, { 6, 57 }, { -17, 73 }, + { 14, 57 }, + + /* 24 - 39 */ + { 20, 40 }, { 20, 10 }, { 29, 0 }, { 54, 0 }, + { 37, 42 }, { 12, 97 }, { -32, 127 }, { -22, 117 }, + { -2, 74 }, { -4, 85 }, { -24, 102 }, { 5, 57 }, + { -6, 93 }, { -14, 88 }, { -6, 44 }, { 4, 55 }, + + /* 40 - 53 */ + { -11, 89 },{ -15, 103 },{ -21, 116 },{ 19, 57 }, + { 20, 58 },{ 4, 84 },{ 6, 96 },{ 1, 63 }, + { -5, 85 },{ -13, 106 },{ 5, 63 },{ 6, 75 }, + { -3, 90 },{ -1, 101 }, + + /* 54 - 59 */ + { 3, 55 },{ -4, 79 },{ -2, 75 },{ -12, 97 }, + { -7, 50 },{ 1, 60 }, + + /* 60 - 69 */ + { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, + { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, + { 13, 41 }, { 3, 62 }, + + /* 70 - 104 */ + { 7, 34 }, { -9, 88 }, { -20, 127 }, { -36, 127 }, + { -17, 91 }, { -14, 95 }, { -25, 84 }, { -25, 86 }, + { -12, 89 }, { -17, 91 }, { -31, 127 }, { -14, 76 }, + { -18, 103 }, { -13, 90 }, { -37, 127 }, { 11, 80 }, + { 5, 76 }, { 2, 84 }, { 5, 78 }, { -6, 55 }, + { 4, 61 }, { -14, 83 }, { -37, 127 }, { -5, 79 }, + { -11, 104 }, { -11, 91 }, { -30, 127 }, { 0, 65 }, + { -2, 79 }, { 0, 72 }, { -4, 92 }, { -6, 56 }, + { 3, 68 }, { -8, 71 }, { -13, 98 }, + + /* 105 -> 165 */ + { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, + { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, + { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, + { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, + { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, + { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, + { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, + { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, + { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, + { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, + { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, + { 3, 65 }, { -7, 69 }, { 8, 77 }, { -10, 66 }, + { 3, 62 }, { -3, 68 }, { -20, 81 }, { 0, 30 }, + { 1, 7 }, { -3, 23 }, { -21, 74 }, { 16, 66 }, + { -23, 124 }, { 17, 37 }, { 44, -18 }, { 50, -34 }, + { -22, 127 }, + + /* 166 - 226 */ + { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, + { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, + { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, + { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, + { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, + { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, + { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, + { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, + { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, + { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, + { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, + { 20, 34 }, { 19, 31 }, { 27, 44 }, { 19, 16 }, + { 15, 36 }, { 15, 36 }, { 21, 28 }, { 25, 21 }, + { 30, 20 }, { 31, 12 }, { 27, 16 }, { 24, 42 }, + { 0, 93 }, { 14, 56 }, { 15, 57 }, { 26, 38 }, + { -24, 127 }, + + /* 227 - 275 */ + { -24, 115 }, { -22, 82 }, { -9, 62 }, { 0, 53 }, + { 0, 59 }, { -14, 85 }, { -13, 89 }, { -13, 94 }, + { -11, 92 }, { -29, 127 }, { -21, 100 }, { -14, 57 }, + { -12, 67 }, { -11, 71 }, { -10, 77 }, { -21, 85 }, + { -16, 88 }, { -23, 104 }, { -15, 98 }, { -37, 127 }, + { -10, 82 }, { -8, 48 }, { -8, 61 }, { -8, 66 }, + { -7, 70 }, { -14, 75 }, { -10, 79 }, { -9, 83 }, + { -12, 92 }, { -18, 108 }, { -4, 79 }, { -22, 69 }, + { -16, 75 }, { -2, 58 }, { 1, 58 }, { -13, 78 }, + { -9, 83 }, { -4, 81 }, { -13, 99 }, { -13, 81 }, + { -6, 38 }, { -13, 62 }, { -6, 58 }, { -2, 59 }, + { -16, 73 }, { -10, 76 }, { -13, 86 }, { -9, 83 }, + { -10, 87 }, + + /* 276 a bit special (not used, x264_cabac_encode_bypass is used instead) */ + { 0, 0 }, + + /* 277 - 337 */ + { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, + { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, + { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, + { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, + { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, + { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, + { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, + { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, + { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, + { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, + { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, + { -2, 76 }, { -18, 86 }, { 12, 70 }, { 5, 64 }, + { -12, 70 }, { 11, 55 }, { 5, 56 }, { 0, 69 }, + { 2, 65 }, { -6, 74 }, { 5, 54 }, { 7, 54 }, + { -6, 76 }, { -11, 82 }, { -2, 77 }, { -2, 77 }, + { 25, 42 }, + + /* 338 - 398 */ + { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, + { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, + { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, + { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, + { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, + { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, + { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, + { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, + { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, + { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, + { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, + { 18, 31 }, { 19, 26 }, { 36, 24 }, { 24, 23 }, + { 27, 16 }, { 24, 30 }, { 31, 29 }, { 22, 41 }, + { 22, 42 }, { 16, 60 }, { 15, 52 }, { 14, 60 }, + { 3, 78 }, { -16, 123 }, { 21, 53 }, { 22, 56 }, + { 25, 61 }, + + /* 399 -> 435 */ + { 21, 33 }, { 19, 50 }, { 17, 61 }, + { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, + { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, + { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, + { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, + { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, + { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, + { -9, 71 }, { -7, 37 }, { -8, 44 }, { -11, 49 }, + { -10, 56 }, { -12, 59 }, { -8, 63 }, { -9, 67 }, + { -6, 68 }, { -10, 79 }, + + /* 436 -> 459 */ + { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, + { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, + { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, + { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, + { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, + { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, + + /* 460 - 1024 */ + { 11, 80 }, { 5, 76 }, { 2, 84 }, { 5, 78 }, + { -6, 55 }, { 4, 61 }, { -14, 83 }, { -37, 127 }, + { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, + { 11, 80 }, { 5, 76 }, { 2, 84 }, { 5, 78 }, + { -6, 55 }, { 4, 61 }, { -14, 83 }, { -37, 127 }, + { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, + { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, + { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, + { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, + { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, + { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, + { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, + { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, + { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, + { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, + { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, + { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, + { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, + { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, + { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, + { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, + { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, + { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, + { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, + { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, + { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, + { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, + { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, + { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, + { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, + { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, + { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, + { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, + { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, + { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, + { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, + { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, + { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, + { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, + { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, + { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, + { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, + { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, + { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, + { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, + { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, + { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, + { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, + { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, + { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, + { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, + { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, + { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, + { -14, 59 }, { -9, 52 }, { -11, 68 }, { -3, 78 }, + { -8, 74 }, { -9, 72 }, { -10, 72 }, { -18, 75 }, + { -12, 71 }, { -11, 63 }, { -5, 70 }, { -17, 75 }, + { -14, 72 }, { -16, 67 }, { -8, 53 }, { -14, 59 }, + { -9, 52 }, { -11, 68 }, { 9, -2 }, { 30, -10 }, + { 31, -4 }, { 33, -1 }, { 33, 7 }, { 31, 12 }, + { 37, 23 }, { 31, 38 }, { 20, 64 }, { 9, -2 }, + { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, + { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, + { -9, 71 }, { -7, 37 }, { -8, 44 }, { -11, 49 }, + { -10, 56 }, { -12, 59 }, { -8, 63 }, { -9, 67 }, + { -6, 68 }, { -10, 79 }, { -3, 78 }, { -8, 74 }, + { -9, 72 }, { -10, 72 }, { -18, 75 }, { -12, 71 }, + { -11, 63 }, { -5, 70 }, { -17, 75 }, { -14, 72 }, + { -16, 67 }, { -8, 53 }, { -14, 59 }, { -9, 52 }, + { -11, 68 }, { -3, 78 }, { -8, 74 }, { -9, 72 }, + { -10, 72 }, { -18, 75 }, { -12, 71 }, { -11, 63 }, + { -5, 70 }, { -17, 75 }, { -14, 72 }, { -16, 67 }, + { -8, 53 }, { -14, 59 }, { -9, 52 }, { -11, 68 }, + { 9, -2 }, { 30, -10 }, { 31, -4 }, { 33, -1 }, + { 33, 7 }, { 31, 12 }, { 37, 23 }, { 31, 38 }, + { 20, 64 }, { 9, -2 }, { 30, -10 }, { 31, -4 }, + { 33, -1 }, { 33, 7 }, { 31, 12 }, { 37, 23 }, + { 31, 38 }, { 20, 64 }, { -9, 71 }, { -7, 37 }, + { -8, 44 }, { -11, 49 }, { -10, 56 }, { -12, 59 }, + { -8, 63 }, { -9, 67 }, { -6, 68 }, { -10, 79 }, + { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, + { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, + { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, + { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, + { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, + { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, + { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, + { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, + { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, + { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, + { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, + { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, + { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, + { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, + { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, + { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, + { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, + { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, + { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, + { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, + { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, + { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, + { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, + { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, + { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, + { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, + { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, + { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, + { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, + { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, + { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, + { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, + { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, + { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, + { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, + { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, + { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, + { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, + { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, + { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, + { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, + { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, + { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, + { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, + { -24, 115 }, { -22, 82 }, { -9, 62 }, { 0, 53 }, + { 0, 59 }, { -14, 85 }, { -13, 89 }, { -13, 94 }, + { -11, 92 }, { -29, 127 }, { -21, 100 }, { -14, 57 }, + { -12, 67 }, { -11, 71 }, { -10, 77 }, { -21, 85 }, + { -16, 88 }, { -23, 104 }, { -15, 98 }, { -37, 127 }, + { -10, 82 }, { -8, 48 }, { -8, 61 }, { -8, 66 }, + { -7, 70 }, { -14, 75 }, { -10, 79 }, { -9, 83 }, + { -12, 92 }, { -18, 108 }, { -24, 115 }, { -22, 82 }, + { -9, 62 }, { 0, 53 }, { 0, 59 }, { -14, 85 }, + { -13, 89 }, { -13, 94 }, { -11, 92 }, { -29, 127 }, + { -21, 100 }, { -14, 57 }, { -12, 67 }, { -11, 71 }, + { -10, 77 }, { -21, 85 }, { -16, 88 }, { -23, 104 }, + { -15, 98 }, { -37, 127 }, { -10, 82 }, { -8, 48 }, + { -8, 61 }, { -8, 66 }, { -7, 70 }, { -14, 75 }, + { -10, 79 }, { -9, 83 }, { -12, 92 }, { -18, 108 }, + { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, + { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, + { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 } + } +}; + +const uint8_t x264_cabac_range_lps[64][4] = +{ + { 2, 2, 2, 2}, { 6, 7, 8, 9}, { 6, 7, 9, 10}, { 6, 8, 9, 11}, + { 7, 8, 10, 11}, { 7, 9, 10, 12}, { 7, 9, 11, 12}, { 8, 9, 11, 13}, + { 8, 10, 12, 14}, { 9, 11, 12, 14}, { 9, 11, 13, 15}, { 10, 12, 14, 16}, + { 10, 12, 15, 17}, { 11, 13, 15, 18}, { 11, 14, 16, 19}, { 12, 14, 17, 20}, + { 12, 15, 18, 21}, { 13, 16, 19, 22}, { 14, 17, 20, 23}, { 14, 18, 21, 24}, + { 15, 19, 22, 25}, { 16, 20, 23, 27}, { 17, 21, 25, 28}, { 18, 22, 26, 30}, + { 19, 23, 27, 31}, { 20, 24, 29, 33}, { 21, 26, 30, 35}, { 22, 27, 32, 37}, + { 23, 28, 33, 39}, { 24, 30, 35, 41}, { 26, 31, 37, 43}, { 27, 33, 39, 45}, + { 29, 35, 41, 48}, { 30, 37, 43, 50}, { 32, 39, 46, 53}, { 33, 41, 48, 56}, + { 35, 43, 51, 59}, { 37, 45, 54, 62}, { 39, 48, 56, 65}, { 41, 50, 59, 69}, + { 43, 53, 63, 72}, { 46, 56, 66, 76}, { 48, 59, 69, 80}, { 51, 62, 73, 85}, + { 53, 65, 77, 89}, { 56, 69, 81, 94}, { 59, 72, 86, 99}, { 62, 76, 90, 104}, + { 66, 80, 95, 110}, { 69, 85, 100, 116}, { 73, 89, 105, 122}, { 77, 94, 111, 128}, + { 81, 99, 117, 135}, { 85, 104, 123, 142}, { 90, 110, 130, 150}, { 95, 116, 137, 158}, + {100, 122, 144, 166}, {105, 128, 152, 175}, {111, 135, 160, 185}, {116, 142, 169, 195}, + {123, 150, 178, 205}, {128, 158, 187, 216}, {128, 167, 197, 227}, {128, 176, 208, 240} +}; + +const uint8_t x264_cabac_transition[128][2] = +{ + { 0, 0}, { 1, 1}, { 2, 50}, { 51, 3}, { 2, 50}, { 51, 3}, { 4, 52}, { 53, 5}, + { 6, 52}, { 53, 7}, { 8, 52}, { 53, 9}, { 10, 54}, { 55, 11}, { 12, 54}, { 55, 13}, + { 14, 54}, { 55, 15}, { 16, 56}, { 57, 17}, { 18, 56}, { 57, 19}, { 20, 56}, { 57, 21}, + { 22, 58}, { 59, 23}, { 24, 58}, { 59, 25}, { 26, 60}, { 61, 27}, { 28, 60}, { 61, 29}, + { 30, 60}, { 61, 31}, { 32, 62}, { 63, 33}, { 34, 62}, { 63, 35}, { 36, 64}, { 65, 37}, + { 38, 66}, { 67, 39}, { 40, 66}, { 67, 41}, { 42, 66}, { 67, 43}, { 44, 68}, { 69, 45}, + { 46, 68}, { 69, 47}, { 48, 70}, { 71, 49}, { 50, 72}, { 73, 51}, { 52, 72}, { 73, 53}, + { 54, 74}, { 75, 55}, { 56, 74}, { 75, 57}, { 58, 76}, { 77, 59}, { 60, 78}, { 79, 61}, + { 62, 78}, { 79, 63}, { 64, 80}, { 81, 65}, { 66, 82}, { 83, 67}, { 68, 82}, { 83, 69}, + { 70, 84}, { 85, 71}, { 72, 84}, { 85, 73}, { 74, 88}, { 89, 75}, { 76, 88}, { 89, 77}, + { 78, 90}, { 91, 79}, { 80, 90}, { 91, 81}, { 82, 94}, { 95, 83}, { 84, 94}, { 95, 85}, + { 86, 96}, { 97, 87}, { 88, 96}, { 97, 89}, { 90, 100}, {101, 91}, { 92, 100}, {101, 93}, + { 94, 102}, {103, 95}, { 96, 104}, {105, 97}, { 98, 104}, {105, 99}, {100, 108}, {109, 101}, + {102, 108}, {109, 103}, {104, 110}, {111, 105}, {106, 112}, {113, 107}, {108, 114}, {115, 109}, + {110, 116}, {117, 111}, {112, 118}, {119, 113}, {114, 118}, {119, 115}, {116, 122}, {123, 117}, + {118, 122}, {123, 119}, {120, 124}, {125, 121}, {122, 126}, {127, 123}, {124, 127}, {126, 125} +}; + +const uint8_t x264_cabac_renorm_shift[64] = +{ + 6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +/* -ln2(probability) */ +const uint16_t x264_cabac_entropy[128] = +{ + FIX8(0.0273), FIX8(5.7370), FIX8(0.0288), FIX8(5.6618), + FIX8(0.0303), FIX8(5.5866), FIX8(0.0320), FIX8(5.5114), + FIX8(0.0337), FIX8(5.4362), FIX8(0.0355), FIX8(5.3610), + FIX8(0.0375), FIX8(5.2859), FIX8(0.0395), FIX8(5.2106), + FIX8(0.0416), FIX8(5.1354), FIX8(0.0439), FIX8(5.0602), + FIX8(0.0463), FIX8(4.9851), FIX8(0.0488), FIX8(4.9099), + FIX8(0.0515), FIX8(4.8347), FIX8(0.0543), FIX8(4.7595), + FIX8(0.0572), FIX8(4.6843), FIX8(0.0604), FIX8(4.6091), + FIX8(0.0637), FIX8(4.5339), FIX8(0.0671), FIX8(4.4588), + FIX8(0.0708), FIX8(4.3836), FIX8(0.0747), FIX8(4.3083), + FIX8(0.0788), FIX8(4.2332), FIX8(0.0832), FIX8(4.1580), + FIX8(0.0878), FIX8(4.0828), FIX8(0.0926), FIX8(4.0076), + FIX8(0.0977), FIX8(3.9324), FIX8(0.1032), FIX8(3.8572), + FIX8(0.1089), FIX8(3.7820), FIX8(0.1149), FIX8(3.7068), + FIX8(0.1214), FIX8(3.6316), FIX8(0.1282), FIX8(3.5565), + FIX8(0.1353), FIX8(3.4813), FIX8(0.1429), FIX8(3.4061), + FIX8(0.1510), FIX8(3.3309), FIX8(0.1596), FIX8(3.2557), + FIX8(0.1686), FIX8(3.1805), FIX8(0.1782), FIX8(3.1053), + FIX8(0.1884), FIX8(3.0301), FIX8(0.1992), FIX8(2.9549), + FIX8(0.2107), FIX8(2.8797), FIX8(0.2229), FIX8(2.8046), + FIX8(0.2358), FIX8(2.7294), FIX8(0.2496), FIX8(2.6542), + FIX8(0.2642), FIX8(2.5790), FIX8(0.2798), FIX8(2.5038), + FIX8(0.2964), FIX8(2.4286), FIX8(0.3142), FIX8(2.3534), + FIX8(0.3331), FIX8(2.2782), FIX8(0.3532), FIX8(2.2030), + FIX8(0.3748), FIX8(2.1278), FIX8(0.3979), FIX8(2.0527), + FIX8(0.4226), FIX8(1.9775), FIX8(0.4491), FIX8(1.9023), + FIX8(0.4776), FIX8(1.8271), FIX8(0.5082), FIX8(1.7519), + FIX8(0.5412), FIX8(1.6767), FIX8(0.5768), FIX8(1.6015), + FIX8(0.6152), FIX8(1.5263), FIX8(0.6568), FIX8(1.4511), + FIX8(0.7020), FIX8(1.3759), FIX8(0.7513), FIX8(1.3008), + FIX8(0.8050), FIX8(1.2256), FIX8(0.8638), FIX8(1.1504), + FIX8(0.9285), FIX8(1.0752), FIX8(1.0000), FIX8(1.0000) +}; + +uint8_t x264_cabac_contexts[4][QP_MAX_SPEC+1][1024]; + +void x264_cabac_init( x264_t *h ) +{ + int ctx_count = CHROMA444 ? 1024 : 460; + for( int i = 0; i < 4; i++ ) + { + const int8_t (*cabac_context_init)[1024][2] = i == 0 ? &x264_cabac_context_init_I + : &x264_cabac_context_init_PB[i-1]; + for( int qp = 0; qp <= QP_MAX_SPEC; qp++ ) + for( int j = 0; j < ctx_count; j++ ) + { + int state = x264_clip3( (((*cabac_context_init)[j][0] * qp) >> 4) + (*cabac_context_init)[j][1], 1, 126 ); + x264_cabac_contexts[i][qp][j] = (X264_MIN( state, 127-state ) << 1) | (state >> 6); + } + } +} + +/***************************************************************************** + * + *****************************************************************************/ +void x264_cabac_context_init( x264_t *h, x264_cabac_t *cb, int i_slice_type, int i_qp, int i_model ) +{ + memcpy( cb->state, x264_cabac_contexts[i_slice_type == SLICE_TYPE_I ? 0 : i_model + 1][i_qp], CHROMA444 ? 1024 : 460 ); +} + +void x264_cabac_encode_init_core( x264_cabac_t *cb ) +{ + cb->i_low = 0; + cb->i_range = 0x01FE; + cb->i_queue = -9; // the first bit will be shifted away and not written + cb->i_bytes_outstanding = 0; +} + +void x264_cabac_encode_init( x264_cabac_t *cb, uint8_t *p_data, uint8_t *p_end ) +{ + x264_cabac_encode_init_core( cb ); + cb->p_start = p_data; + cb->p = p_data; + cb->p_end = p_end; +} + +static inline void x264_cabac_putbyte( x264_cabac_t *cb ) +{ + if( cb->i_queue >= 0 ) + { + int out = cb->i_low >> (cb->i_queue+10); + cb->i_low &= (0x400<i_queue)-1; + cb->i_queue -= 8; + + if( (out & 0xff) == 0xff ) + cb->i_bytes_outstanding++; + else + { + int carry = out >> 8; + int bytes_outstanding = cb->i_bytes_outstanding; + // this can't modify before the beginning of the stream because + // that would correspond to a probability > 1. + // it will write before the beginning of the stream, which is ok + // because a slice header always comes before cabac data. + // this can't carry beyond the one byte, because any 0xff bytes + // are in bytes_outstanding and thus not written yet. + cb->p[-1] += carry; + while( bytes_outstanding > 0 ) + { + *(cb->p++) = carry-1; + bytes_outstanding--; + } + *(cb->p++) = out; + cb->i_bytes_outstanding = 0; + } + } +} + +static inline void x264_cabac_encode_renorm( x264_cabac_t *cb ) +{ + int shift = x264_cabac_renorm_shift[cb->i_range>>3]; + cb->i_range <<= shift; + cb->i_low <<= shift; + cb->i_queue += shift; + x264_cabac_putbyte( cb ); +} + +/* Making custom versions of this function, even in asm, for the cases where + * b is known to be 0 or 1, proved to be somewhat useful on x86_32 with GCC 3.4 + * but nearly useless with GCC 4.3 and worse than useless on x86_64. */ +void x264_cabac_encode_decision_c( x264_cabac_t *cb, int i_ctx, int b ) +{ + int i_state = cb->state[i_ctx]; + int i_range_lps = x264_cabac_range_lps[i_state>>1][(cb->i_range>>6)-4]; + cb->i_range -= i_range_lps; + if( b != (i_state & 1) ) + { + cb->i_low += cb->i_range; + cb->i_range = i_range_lps; + } + cb->state[i_ctx] = x264_cabac_transition[i_state][b]; + x264_cabac_encode_renorm( cb ); +} + +/* Note: b is negated for this function */ +void x264_cabac_encode_bypass_c( x264_cabac_t *cb, int b ) +{ + cb->i_low <<= 1; + cb->i_low += b & cb->i_range; + cb->i_queue += 1; + x264_cabac_putbyte( cb ); +} + +static const int bypass_lut[16] = +{ + -1, 0x2, 0x14, 0x68, 0x1d0, 0x7a0, 0x1f40, 0x7e80, + 0x1fd00, 0x7fa00, 0x1ff400, 0x7fe800, 0x1ffd000, 0x7ffa000, 0x1fff4000, 0x7ffe8000 +}; + +void x264_cabac_encode_ue_bypass( x264_cabac_t *cb, int exp_bits, int val ) +{ + uint32_t v = val + (1<i_low <<= i; + cb->i_low += ((x>>k)&0xff) * cb->i_range; + cb->i_queue += i; + x264_cabac_putbyte( cb ); + i = 8; + } while( k > 0 ); +} + +void x264_cabac_encode_terminal_c( x264_cabac_t *cb ) +{ + cb->i_range -= 2; + x264_cabac_encode_renorm( cb ); +} + +void x264_cabac_encode_flush( x264_t *h, x264_cabac_t *cb ) +{ + cb->i_low += cb->i_range - 2; + cb->i_low |= 1; + cb->i_low <<= 9; + cb->i_queue += 9; + x264_cabac_putbyte( cb ); + x264_cabac_putbyte( cb ); + cb->i_low <<= -cb->i_queue; + cb->i_low |= (0x35a4e4f5 >> (h->i_frame & 31) & 1) << 10; + cb->i_queue = 0; + x264_cabac_putbyte( cb ); + + while( cb->i_bytes_outstanding > 0 ) + { + *(cb->p++) = 0xff; + cb->i_bytes_outstanding--; + } +} + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cabac.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cabac.h new file mode 100644 index 00000000..13788342 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cabac.h @@ -0,0 +1,118 @@ +/***************************************************************************** + * cabac.h: arithmetic coder + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_CABAC_H +#define X264_CABAC_H + +typedef struct +{ + /* state */ + int i_low; + int i_range; + + /* bit stream */ + int i_queue; //stored with an offset of -8 for faster asm + int i_bytes_outstanding; + + uint8_t *p_start; + uint8_t *p; + uint8_t *p_end; + + /* aligned for memcpy_aligned starting here */ + ALIGNED_64( int f8_bits_encoded ); // only if using x264_cabac_size_decision() + + /* context */ + uint8_t state[1024]; + + /* for 16-byte alignment */ + uint8_t padding[12]; +} x264_cabac_t; + +extern const uint8_t x264_cabac_transition[128][2]; +extern const uint16_t x264_cabac_entropy[128]; + +/* init the contexts given i_slice_type, the quantif and the model */ +void x264_cabac_context_init( x264_t *h, x264_cabac_t *cb, int i_slice_type, int i_qp, int i_model ); + +void x264_cabac_encode_init_core( x264_cabac_t *cb ); +void x264_cabac_encode_init( x264_cabac_t *cb, uint8_t *p_data, uint8_t *p_end ); +void x264_cabac_encode_decision_c( x264_cabac_t *cb, int i_ctx, int b ); +void x264_cabac_encode_decision_asm( x264_cabac_t *cb, int i_ctx, int b ); +void x264_cabac_encode_bypass_c( x264_cabac_t *cb, int b ); +void x264_cabac_encode_bypass_asm( x264_cabac_t *cb, int b ); +void x264_cabac_encode_terminal_c( x264_cabac_t *cb ); +void x264_cabac_encode_terminal_asm( x264_cabac_t *cb ); +void x264_cabac_encode_ue_bypass( x264_cabac_t *cb, int exp_bits, int val ); +void x264_cabac_encode_flush( x264_t *h, x264_cabac_t *cb ); + +#if HAVE_MMX +#define x264_cabac_encode_decision x264_cabac_encode_decision_asm +#define x264_cabac_encode_bypass x264_cabac_encode_bypass_asm +#define x264_cabac_encode_terminal x264_cabac_encode_terminal_asm +#elif defined(ARCH_AARCH64) +#define x264_cabac_encode_decision x264_cabac_encode_decision_asm +#define x264_cabac_encode_bypass x264_cabac_encode_bypass_asm +#define x264_cabac_encode_terminal x264_cabac_encode_terminal_asm +#else +#define x264_cabac_encode_decision x264_cabac_encode_decision_c +#define x264_cabac_encode_bypass x264_cabac_encode_bypass_c +#define x264_cabac_encode_terminal x264_cabac_encode_terminal_c +#endif +#define x264_cabac_encode_decision_noup x264_cabac_encode_decision + +static ALWAYS_INLINE int x264_cabac_pos( x264_cabac_t *cb ) +{ + return (cb->p - cb->p_start + cb->i_bytes_outstanding) * 8 + cb->i_queue; +} + +/* internal only. these don't write the bitstream, just calculate bit cost: */ + +static ALWAYS_INLINE void x264_cabac_size_decision( x264_cabac_t *cb, long i_ctx, long b ) +{ + int i_state = cb->state[i_ctx]; + cb->state[i_ctx] = x264_cabac_transition[i_state][b]; + cb->f8_bits_encoded += x264_cabac_entropy[i_state^b]; +} + +static ALWAYS_INLINE int x264_cabac_size_decision2( uint8_t *state, long b ) +{ + int i_state = *state; + *state = x264_cabac_transition[i_state][b]; + return x264_cabac_entropy[i_state^b]; +} + +static ALWAYS_INLINE void x264_cabac_size_decision_noup( x264_cabac_t *cb, long i_ctx, long b ) +{ + int i_state = cb->state[i_ctx]; + cb->f8_bits_encoded += x264_cabac_entropy[i_state^b]; +} + +static ALWAYS_INLINE int x264_cabac_size_decision_noup2( uint8_t *state, long b ) +{ + return x264_cabac_entropy[*state^b]; +} + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/common.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/common.c new file mode 100644 index 00000000..561212d3 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/common.c @@ -0,0 +1,1446 @@ +/***************************************************************************** + * common.c: misc common functions + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#include + +#if HAVE_MALLOC_H +#include +#endif +#if HAVE_THP +#include +#endif + +const int x264_bit_depth = BIT_DEPTH; + +const int x264_chroma_format = X264_CHROMA_FORMAT; + +static void x264_log_default( void *, int, const char *, va_list ); + +/**************************************************************************** + * x264_param_default: + ****************************************************************************/ +void x264_param_default( x264_param_t *param ) +{ + /* */ + memset( param, 0, sizeof( x264_param_t ) ); + + /* CPU autodetect */ + param->cpu = x264_cpu_detect(); + param->i_threads = X264_THREADS_AUTO; + param->i_lookahead_threads = X264_THREADS_AUTO; + param->b_deterministic = 1; + param->i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO; + + /* Video properties */ + param->i_csp = X264_CHROMA_FORMAT ? X264_CHROMA_FORMAT : X264_CSP_I420; + param->i_width = 0; + param->i_height = 0; + param->vui.i_sar_width = 0; + param->vui.i_sar_height= 0; + param->vui.i_overscan = 0; /* undef */ + param->vui.i_vidformat = 5; /* undef */ + param->vui.b_fullrange = -1; /* default depends on input */ + param->vui.i_colorprim = 2; /* undef */ + param->vui.i_transfer = 2; /* undef */ + param->vui.i_colmatrix = -1; /* default depends on input */ + param->vui.i_chroma_loc= 0; /* left center */ + param->i_fps_num = 25; + param->i_fps_den = 1; + param->i_level_idc = -1; + param->i_slice_max_size = 0; + param->i_slice_max_mbs = 0; + param->i_slice_count = 0; + + /* Encoder parameters */ + param->i_frame_reference = 3; + param->i_keyint_max = 250; + param->i_keyint_min = X264_KEYINT_MIN_AUTO; + param->i_bframe = 3; + param->i_scenecut_threshold = 40; + param->i_bframe_adaptive = X264_B_ADAPT_FAST; + param->i_bframe_bias = 0; + param->i_bframe_pyramid = X264_B_PYRAMID_NORMAL; + param->b_interlaced = 0; + param->b_constrained_intra = 0; + + param->b_deblocking_filter = 1; + param->i_deblocking_filter_alphac0 = 0; + param->i_deblocking_filter_beta = 0; + + param->b_cabac = 1; + param->i_cabac_init_idc = 0; + + param->rc.i_rc_method = X264_RC_CRF; + param->rc.i_bitrate = 0; + param->rc.f_rate_tolerance = 1.0; + param->rc.i_vbv_max_bitrate = 0; + param->rc.i_vbv_buffer_size = 0; + param->rc.f_vbv_buffer_init = 0.9; + param->rc.i_qp_constant = 23 + QP_BD_OFFSET; + param->rc.f_rf_constant = 23; + param->rc.i_qp_min = 0; + param->rc.i_qp_max = QP_MAX; + param->rc.i_qp_step = 4; + param->rc.f_ip_factor = 1.4; + param->rc.f_pb_factor = 1.3; + param->rc.i_aq_mode = X264_AQ_VARIANCE; + param->rc.f_aq_strength = 1.0; + param->rc.i_lookahead = 40; + + param->rc.b_stat_write = 0; + param->rc.psz_stat_out = "x264_2pass.log"; + param->rc.b_stat_read = 0; + param->rc.psz_stat_in = "x264_2pass.log"; + param->rc.f_qcompress = 0.6; + param->rc.f_qblur = 0.5; + param->rc.f_complexity_blur = 20; + param->rc.i_zones = 0; + param->rc.b_mb_tree = 1; + + /* Log */ + param->pf_log = x264_log_default; + param->p_log_private = NULL; + param->i_log_level = X264_LOG_INFO; + + /* */ + param->analyse.intra = X264_ANALYSE_I4x4 | X264_ANALYSE_I8x8; + param->analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_I8x8 + | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_BSUB16x16; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; + param->analyse.i_me_method = X264_ME_HEX; + param->analyse.f_psy_rd = 1.0; + param->analyse.b_psy = 1; + param->analyse.f_psy_trellis = 0; + param->analyse.i_me_range = 16; + param->analyse.i_subpel_refine = 7; + param->analyse.b_mixed_references = 1; + param->analyse.b_chroma_me = 1; + param->analyse.i_mv_range_thread = -1; + param->analyse.i_mv_range = -1; // set from level_idc + param->analyse.i_chroma_qp_offset = 0; + param->analyse.b_fast_pskip = 1; + param->analyse.b_weighted_bipred = 1; + param->analyse.i_weighted_pred = X264_WEIGHTP_SMART; + param->analyse.b_dct_decimate = 1; + param->analyse.b_transform_8x8 = 1; + param->analyse.i_trellis = 1; + param->analyse.i_luma_deadzone[0] = 21; + param->analyse.i_luma_deadzone[1] = 11; + param->analyse.b_psnr = 0; + param->analyse.b_ssim = 0; + + param->i_cqm_preset = X264_CQM_FLAT; + memset( param->cqm_4iy, 16, sizeof( param->cqm_4iy ) ); + memset( param->cqm_4py, 16, sizeof( param->cqm_4py ) ); + memset( param->cqm_4ic, 16, sizeof( param->cqm_4ic ) ); + memset( param->cqm_4pc, 16, sizeof( param->cqm_4pc ) ); + memset( param->cqm_8iy, 16, sizeof( param->cqm_8iy ) ); + memset( param->cqm_8py, 16, sizeof( param->cqm_8py ) ); + memset( param->cqm_8ic, 16, sizeof( param->cqm_8ic ) ); + memset( param->cqm_8pc, 16, sizeof( param->cqm_8pc ) ); + + param->b_repeat_headers = 1; + param->b_annexb = 1; + param->b_aud = 0; + param->b_vfr_input = 1; + param->i_nal_hrd = X264_NAL_HRD_NONE; + param->b_tff = 1; + param->b_pic_struct = 0; + param->b_fake_interlaced = 0; + param->i_frame_packing = -1; + param->b_opencl = 0; + param->i_opencl_device = 0; + param->opencl_device_id = NULL; + param->psz_clbin_file = NULL; +} + +static int x264_param_apply_preset( x264_param_t *param, const char *preset ) +{ + char *end; + int i = strtol( preset, &end, 10 ); + if( *end == 0 && i >= 0 && i < sizeof(x264_preset_names)/sizeof(*x264_preset_names)-1 ) + preset = x264_preset_names[i]; + + if( !strcasecmp( preset, "ultrafast" ) ) + { + param->i_frame_reference = 1; + param->i_scenecut_threshold = 0; + param->b_deblocking_filter = 0; + param->b_cabac = 0; + param->i_bframe = 0; + param->analyse.intra = 0; + param->analyse.inter = 0; + param->analyse.b_transform_8x8 = 0; + param->analyse.i_me_method = X264_ME_DIA; + param->analyse.i_subpel_refine = 0; + param->rc.i_aq_mode = 0; + param->analyse.b_mixed_references = 0; + param->analyse.i_trellis = 0; + param->i_bframe_adaptive = X264_B_ADAPT_NONE; + param->rc.b_mb_tree = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_NONE; + param->analyse.b_weighted_bipred = 0; + param->rc.i_lookahead = 0; + } + else if( !strcasecmp( preset, "superfast" ) ) + { + param->analyse.inter = X264_ANALYSE_I8x8|X264_ANALYSE_I4x4; + param->analyse.i_me_method = X264_ME_DIA; + param->analyse.i_subpel_refine = 1; + param->i_frame_reference = 1; + param->analyse.b_mixed_references = 0; + param->analyse.i_trellis = 0; + param->rc.b_mb_tree = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_SIMPLE; + param->rc.i_lookahead = 0; + } + else if( !strcasecmp( preset, "veryfast" ) ) + { + param->analyse.i_subpel_refine = 2; + param->i_frame_reference = 1; + param->analyse.b_mixed_references = 0; + param->analyse.i_trellis = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_SIMPLE; + param->rc.i_lookahead = 10; + } + else if( !strcasecmp( preset, "faster" ) ) + { + param->analyse.b_mixed_references = 0; + param->i_frame_reference = 2; + param->analyse.i_subpel_refine = 4; + param->analyse.i_weighted_pred = X264_WEIGHTP_SIMPLE; + param->rc.i_lookahead = 20; + } + else if( !strcasecmp( preset, "fast" ) ) + { + param->i_frame_reference = 2; + param->analyse.i_subpel_refine = 6; + param->analyse.i_weighted_pred = X264_WEIGHTP_SIMPLE; + param->rc.i_lookahead = 30; + } + else if( !strcasecmp( preset, "medium" ) ) + { + /* Default is medium */ + } + else if( !strcasecmp( preset, "slow" ) ) + { + param->analyse.i_subpel_refine = 8; + param->i_frame_reference = 5; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; + param->analyse.i_trellis = 2; + param->rc.i_lookahead = 50; + } + else if( !strcasecmp( preset, "slower" ) ) + { + param->analyse.i_me_method = X264_ME_UMH; + param->analyse.i_subpel_refine = 9; + param->i_frame_reference = 8; + param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; + param->analyse.inter |= X264_ANALYSE_PSUB8x8; + param->analyse.i_trellis = 2; + param->rc.i_lookahead = 60; + } + else if( !strcasecmp( preset, "veryslow" ) ) + { + param->analyse.i_me_method = X264_ME_UMH; + param->analyse.i_subpel_refine = 10; + param->analyse.i_me_range = 24; + param->i_frame_reference = 16; + param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; + param->analyse.inter |= X264_ANALYSE_PSUB8x8; + param->analyse.i_trellis = 2; + param->i_bframe = 8; + param->rc.i_lookahead = 60; + } + else if( !strcasecmp( preset, "placebo" ) ) + { + param->analyse.i_me_method = X264_ME_TESA; + param->analyse.i_subpel_refine = 11; + param->analyse.i_me_range = 24; + param->i_frame_reference = 16; + param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; + param->analyse.inter |= X264_ANALYSE_PSUB8x8; + param->analyse.b_fast_pskip = 0; + param->analyse.i_trellis = 2; + param->i_bframe = 16; + param->rc.i_lookahead = 60; + } + else + { + x264_log( NULL, X264_LOG_ERROR, "invalid preset '%s'\n", preset ); + return -1; + } + return 0; +} + +static int x264_param_apply_tune( x264_param_t *param, const char *tune ) +{ + char *tmp = x264_malloc( strlen( tune ) + 1 ); + if( !tmp ) + return -1; + tmp = strcpy( tmp, tune ); + char *s = strtok( tmp, ",./-+" ); + int psy_tuning_used = 0; + while( s ) + { + if( !strncasecmp( s, "film", 4 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_deblocking_filter_alphac0 = -1; + param->i_deblocking_filter_beta = -1; + param->analyse.f_psy_trellis = 0.15; + } + else if( !strncasecmp( s, "animation", 9 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_frame_reference = param->i_frame_reference > 1 ? param->i_frame_reference*2 : 1; + param->i_deblocking_filter_alphac0 = 1; + param->i_deblocking_filter_beta = 1; + param->analyse.f_psy_rd = 0.4; + param->rc.f_aq_strength = 0.6; + param->i_bframe += 2; + } + else if( !strncasecmp( s, "grain", 5 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_deblocking_filter_alphac0 = -2; + param->i_deblocking_filter_beta = -2; + param->analyse.f_psy_trellis = 0.25; + param->analyse.b_dct_decimate = 0; + param->rc.f_pb_factor = 1.1; + param->rc.f_ip_factor = 1.1; + param->rc.f_aq_strength = 0.5; + param->analyse.i_luma_deadzone[0] = 6; + param->analyse.i_luma_deadzone[1] = 6; + param->rc.f_qcompress = 0.8; + } + else if( !strncasecmp( s, "stillimage", 10 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_deblocking_filter_alphac0 = -3; + param->i_deblocking_filter_beta = -3; + param->analyse.f_psy_rd = 2.0; + param->analyse.f_psy_trellis = 0.7; + param->rc.f_aq_strength = 1.2; + } + else if( !strncasecmp( s, "psnr", 4 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->rc.i_aq_mode = X264_AQ_NONE; + param->analyse.b_psy = 0; + } + else if( !strncasecmp( s, "ssim", 4 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->rc.i_aq_mode = X264_AQ_AUTOVARIANCE; + param->analyse.b_psy = 0; + } + else if( !strncasecmp( s, "fastdecode", 10 ) ) + { + param->b_deblocking_filter = 0; + param->b_cabac = 0; + param->analyse.b_weighted_bipred = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_NONE; + } + else if( !strncasecmp( s, "zerolatency", 11 ) ) + { + param->rc.i_lookahead = 0; + param->i_sync_lookahead = 0; + param->i_bframe = 0; + param->b_sliced_threads = 1; + param->b_vfr_input = 0; + param->rc.b_mb_tree = 0; + } + else if( !strncasecmp( s, "touhou", 6 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_frame_reference = param->i_frame_reference > 1 ? param->i_frame_reference*2 : 1; + param->i_deblocking_filter_alphac0 = -1; + param->i_deblocking_filter_beta = -1; + param->analyse.f_psy_trellis = 0.2; + param->rc.f_aq_strength = 1.3; + if( param->analyse.inter & X264_ANALYSE_PSUB16x16 ) + param->analyse.inter |= X264_ANALYSE_PSUB8x8; + } + else + { + x264_log( NULL, X264_LOG_ERROR, "invalid tune '%s'\n", s ); + x264_free( tmp ); + return -1; + } + if( 0 ) + { + psy_failure: + x264_log( NULL, X264_LOG_WARNING, "only 1 psy tuning can be used: ignoring tune %s\n", s ); + } + s = strtok( NULL, ",./-+" ); + } + x264_free( tmp ); + return 0; +} + +int x264_param_default_preset( x264_param_t *param, const char *preset, const char *tune ) +{ + x264_param_default( param ); + + if( preset && x264_param_apply_preset( param, preset ) < 0 ) + return -1; + if( tune && x264_param_apply_tune( param, tune ) < 0 ) + return -1; + return 0; +} + +void x264_param_apply_fastfirstpass( x264_param_t *param ) +{ + /* Set faster options in case of turbo firstpass. */ + if( param->rc.b_stat_write && !param->rc.b_stat_read ) + { + param->i_frame_reference = 1; + param->analyse.b_transform_8x8 = 0; + param->analyse.inter = 0; + param->analyse.i_me_method = X264_ME_DIA; + param->analyse.i_subpel_refine = X264_MIN( 2, param->analyse.i_subpel_refine ); + param->analyse.i_trellis = 0; + param->analyse.b_fast_pskip = 1; + } +} + +static int profile_string_to_int( const char *str ) +{ + if( !strcasecmp( str, "baseline" ) ) + return PROFILE_BASELINE; + if( !strcasecmp( str, "main" ) ) + return PROFILE_MAIN; + if( !strcasecmp( str, "high" ) ) + return PROFILE_HIGH; + if( !strcasecmp( str, "high10" ) ) + return PROFILE_HIGH10; + if( !strcasecmp( str, "high422" ) ) + return PROFILE_HIGH422; + if( !strcasecmp( str, "high444" ) ) + return PROFILE_HIGH444_PREDICTIVE; + return -1; +} + +int x264_param_apply_profile( x264_param_t *param, const char *profile ) +{ + if( !profile ) + return 0; + + int p = profile_string_to_int( profile ); + if( p < 0 ) + { + x264_log( NULL, X264_LOG_ERROR, "invalid profile: %s\n", profile ); + return -1; + } + if( p < PROFILE_HIGH444_PREDICTIVE && ((param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant <= 0) || + (param->rc.i_rc_method == X264_RC_CRF && (int)(param->rc.f_rf_constant + QP_BD_OFFSET) <= 0)) ) + { + x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support lossless\n", profile ); + return -1; + } + if( p < PROFILE_HIGH444_PREDICTIVE && (param->i_csp & X264_CSP_MASK) >= X264_CSP_I444 ) + { + x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support 4:4:4\n", profile ); + return -1; + } + if( p < PROFILE_HIGH422 && (param->i_csp & X264_CSP_MASK) >= X264_CSP_I422 ) + { + x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support 4:2:2\n", profile ); + return -1; + } + if( p < PROFILE_HIGH10 && BIT_DEPTH > 8 ) + { + x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support a bit depth of %d\n", profile, BIT_DEPTH ); + return -1; + } + + if( p == PROFILE_BASELINE ) + { + param->analyse.b_transform_8x8 = 0; + param->b_cabac = 0; + param->i_cqm_preset = X264_CQM_FLAT; + param->psz_cqm_file = NULL; + param->i_bframe = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_NONE; + if( param->b_interlaced ) + { + x264_log( NULL, X264_LOG_ERROR, "baseline profile doesn't support interlacing\n" ); + return -1; + } + if( param->b_fake_interlaced ) + { + x264_log( NULL, X264_LOG_ERROR, "baseline profile doesn't support fake interlacing\n" ); + return -1; + } + } + else if( p == PROFILE_MAIN ) + { + param->analyse.b_transform_8x8 = 0; + param->i_cqm_preset = X264_CQM_FLAT; + param->psz_cqm_file = NULL; + } + return 0; +} + +static int parse_enum( const char *arg, const char * const *names, int *dst ) +{ + for( int i = 0; names[i]; i++ ) + if( !strcasecmp( arg, names[i] ) ) + { + *dst = i; + return 0; + } + return -1; +} + +static int parse_cqm( const char *str, uint8_t *cqm, int length ) +{ + int i = 0; + do { + int coef; + if( !sscanf( str, "%d", &coef ) || coef < 1 || coef > 255 ) + return -1; + cqm[i++] = coef; + } while( i < length && (str = strchr( str, ',' )) && str++ ); + return (i == length) ? 0 : -1; +} + +static int x264_atobool( const char *str, int *b_error ) +{ + if( !strcmp(str, "1") || + !strcasecmp(str, "true") || + !strcasecmp(str, "yes") ) + return 1; + if( !strcmp(str, "0") || + !strcasecmp(str, "false") || + !strcasecmp(str, "no") ) + return 0; + *b_error = 1; + return 0; +} + +static int x264_atoi( const char *str, int *b_error ) +{ + char *end; + int v = strtol( str, &end, 0 ); + if( end == str || *end != '\0' ) + *b_error = 1; + return v; +} + +static double x264_atof( const char *str, int *b_error ) +{ + char *end; + double v = strtod( str, &end ); + if( end == str || *end != '\0' ) + *b_error = 1; + return v; +} + +#define atobool(str) ( name_was_bool = 1, x264_atobool( str, &b_error ) ) +#undef atoi +#undef atof +#define atoi(str) x264_atoi( str, &b_error ) +#define atof(str) x264_atof( str, &b_error ) + +int x264_param_parse( x264_param_t *p, const char *name, const char *value ) +{ + char *name_buf = NULL; + int b_error = 0; + int errortype = X264_PARAM_BAD_VALUE; + int name_was_bool; + int value_was_null = !value; + + if( !name ) + return X264_PARAM_BAD_NAME; + if( !value ) + value = "true"; + + if( value[0] == '=' ) + value++; + + if( strchr( name, '_' ) ) // s/_/-/g + { + char *c; + name_buf = strdup(name); + if( !name_buf ) + return X264_PARAM_BAD_NAME; + while( (c = strchr( name_buf, '_' )) ) + *c = '-'; + name = name_buf; + } + + if( !strncmp( name, "no", 2 ) ) + { + name += 2; + if( name[0] == '-' ) + name++; + value = atobool(value) ? "false" : "true"; + } + name_was_bool = 0; + +#define OPT(STR) else if( !strcmp( name, STR ) ) +#define OPT2(STR0, STR1) else if( !strcmp( name, STR0 ) || !strcmp( name, STR1 ) ) + if( 0 ); + OPT("asm") + { + p->cpu = isdigit(value[0]) ? atoi(value) : + !strcasecmp(value, "auto") || atobool(value) ? x264_cpu_detect() : 0; + if( b_error ) + { + char *buf = strdup( value ); + if( buf ) + { + char *tok, UNUSED *saveptr=NULL, *init; + b_error = 0; + p->cpu = 0; + for( init=buf; (tok=strtok_r(init, ",", &saveptr)); init=NULL ) + { + int i = 0; + while( x264_cpu_names[i].flags && strcasecmp(tok, x264_cpu_names[i].name) ) + i++; + p->cpu |= x264_cpu_names[i].flags; + if( !x264_cpu_names[i].flags ) + b_error = 1; + } + free( buf ); + if( (p->cpu&X264_CPU_SSSE3) && !(p->cpu&X264_CPU_SSE2_IS_SLOW) ) + p->cpu |= X264_CPU_SSE2_IS_FAST; + } + } + } + OPT("threads") + { + if( !strcasecmp(value, "auto") ) + p->i_threads = X264_THREADS_AUTO; + else + p->i_threads = atoi(value); + } + OPT("lookahead-threads") + { + if( !strcasecmp(value, "auto") ) + p->i_lookahead_threads = X264_THREADS_AUTO; + else + p->i_lookahead_threads = atoi(value); + } + OPT("sliced-threads") + p->b_sliced_threads = atobool(value); + OPT("sync-lookahead") + { + if( !strcasecmp(value, "auto") ) + p->i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO; + else + p->i_sync_lookahead = atoi(value); + } + OPT2("deterministic", "n-deterministic") + p->b_deterministic = atobool(value); + OPT("cpu-independent") + p->b_cpu_independent = atobool(value); + OPT2("level", "level-idc") + { + if( !strcmp(value, "1b") ) + p->i_level_idc = 9; + else if( atof(value) < 7 ) + p->i_level_idc = (int)(10*atof(value)+.5); + else + p->i_level_idc = atoi(value); + } + OPT("bluray-compat") + p->b_bluray_compat = atobool(value); + OPT("avcintra-class") + p->i_avcintra_class = atoi(value); + OPT("sar") + { + b_error = ( 2 != sscanf( value, "%d:%d", &p->vui.i_sar_width, &p->vui.i_sar_height ) && + 2 != sscanf( value, "%d/%d", &p->vui.i_sar_width, &p->vui.i_sar_height ) ); + } + OPT("overscan") + b_error |= parse_enum( value, x264_overscan_names, &p->vui.i_overscan ); + OPT("videoformat") + b_error |= parse_enum( value, x264_vidformat_names, &p->vui.i_vidformat ); + OPT("fullrange") + b_error |= parse_enum( value, x264_fullrange_names, &p->vui.b_fullrange ); + OPT("colorprim") + b_error |= parse_enum( value, x264_colorprim_names, &p->vui.i_colorprim ); + OPT("transfer") + b_error |= parse_enum( value, x264_transfer_names, &p->vui.i_transfer ); + OPT("colormatrix") + b_error |= parse_enum( value, x264_colmatrix_names, &p->vui.i_colmatrix ); + OPT("chromaloc") + { + p->vui.i_chroma_loc = atoi(value); + b_error = ( p->vui.i_chroma_loc < 0 || p->vui.i_chroma_loc > 5 ); + } + OPT("fps") + { + if( sscanf( value, "%u/%u", &p->i_fps_num, &p->i_fps_den ) != 2 ) + { + double fps = atof(value); + if( fps > 0.0 && fps <= INT_MAX/1000.0 ) + { + p->i_fps_num = (int)(fps * 1000.0 + .5); + p->i_fps_den = 1000; + } + else + { + p->i_fps_num = atoi(value); + p->i_fps_den = 1; + } + } + } + OPT2("ref", "frameref") + p->i_frame_reference = atoi(value); + OPT("dpb-size") + p->i_dpb_size = atoi(value); + OPT("keyint") + { + if( strstr( value, "infinite" ) ) + p->i_keyint_max = X264_KEYINT_MAX_INFINITE; + else + p->i_keyint_max = atoi(value); + } + OPT2("min-keyint", "keyint-min") + { + p->i_keyint_min = atoi(value); + if( p->i_keyint_max < p->i_keyint_min ) + p->i_keyint_max = p->i_keyint_min; + } + OPT("scenecut") + { + p->i_scenecut_threshold = atobool(value); + if( b_error || p->i_scenecut_threshold ) + { + b_error = 0; + p->i_scenecut_threshold = atoi(value); + } + } + OPT("intra-refresh") + p->b_intra_refresh = atobool(value); + OPT("bframes") + p->i_bframe = atoi(value); + OPT("b-adapt") + { + p->i_bframe_adaptive = atobool(value); + if( b_error ) + { + b_error = 0; + p->i_bframe_adaptive = atoi(value); + } + } + OPT("b-bias") + p->i_bframe_bias = atoi(value); + OPT("b-pyramid") + { + b_error |= parse_enum( value, x264_b_pyramid_names, &p->i_bframe_pyramid ); + if( b_error ) + { + b_error = 0; + p->i_bframe_pyramid = atoi(value); + } + } + OPT("open-gop") + p->b_open_gop = atobool(value); + OPT("nf") + p->b_deblocking_filter = !atobool(value); + OPT2("filter", "deblock") + { + if( 2 == sscanf( value, "%d:%d", &p->i_deblocking_filter_alphac0, &p->i_deblocking_filter_beta ) || + 2 == sscanf( value, "%d,%d", &p->i_deblocking_filter_alphac0, &p->i_deblocking_filter_beta ) ) + { + p->b_deblocking_filter = 1; + } + else if( sscanf( value, "%d", &p->i_deblocking_filter_alphac0 ) ) + { + p->b_deblocking_filter = 1; + p->i_deblocking_filter_beta = p->i_deblocking_filter_alphac0; + } + else + p->b_deblocking_filter = atobool(value); + } + OPT("slice-max-size") + p->i_slice_max_size = atoi(value); + OPT("slice-max-mbs") + p->i_slice_max_mbs = atoi(value); + OPT("slice-min-mbs") + p->i_slice_min_mbs = atoi(value); + OPT("slices") + p->i_slice_count = atoi(value); + OPT("slices-max") + p->i_slice_count_max = atoi(value); + OPT("cabac") + p->b_cabac = atobool(value); + OPT("cabac-idc") + p->i_cabac_init_idc = atoi(value); + OPT("interlaced") + p->b_interlaced = atobool(value); + OPT("tff") + p->b_interlaced = p->b_tff = atobool(value); + OPT("bff") + { + p->b_interlaced = atobool(value); + p->b_tff = !p->b_interlaced; + } + OPT("constrained-intra") + p->b_constrained_intra = atobool(value); + OPT("cqm") + { + if( strstr( value, "flat" ) ) + p->i_cqm_preset = X264_CQM_FLAT; + else if( strstr( value, "jvt" ) ) + p->i_cqm_preset = X264_CQM_JVT; + else + p->psz_cqm_file = strdup(value); + } + OPT("cqmfile") + p->psz_cqm_file = strdup(value); + OPT("cqm4") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_4iy, 16 ); + b_error |= parse_cqm( value, p->cqm_4py, 16 ); + b_error |= parse_cqm( value, p->cqm_4ic, 16 ); + b_error |= parse_cqm( value, p->cqm_4pc, 16 ); + } + OPT("cqm8") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_8iy, 64 ); + b_error |= parse_cqm( value, p->cqm_8py, 64 ); + b_error |= parse_cqm( value, p->cqm_8ic, 64 ); + b_error |= parse_cqm( value, p->cqm_8pc, 64 ); + } + OPT("cqm4i") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_4iy, 16 ); + b_error |= parse_cqm( value, p->cqm_4ic, 16 ); + } + OPT("cqm4p") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_4py, 16 ); + b_error |= parse_cqm( value, p->cqm_4pc, 16 ); + } + OPT("cqm4iy") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_4iy, 16 ); + } + OPT("cqm4ic") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_4ic, 16 ); + } + OPT("cqm4py") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_4py, 16 ); + } + OPT("cqm4pc") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_4pc, 16 ); + } + OPT("cqm8i") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_8iy, 64 ); + b_error |= parse_cqm( value, p->cqm_8ic, 64 ); + } + OPT("cqm8p") + { + p->i_cqm_preset = X264_CQM_CUSTOM; + b_error |= parse_cqm( value, p->cqm_8py, 64 ); + b_error |= parse_cqm( value, p->cqm_8pc, 64 ); + } + OPT("log") + p->i_log_level = atoi(value); + OPT("dump-yuv") + p->psz_dump_yuv = strdup(value); + OPT2("analyse", "partitions") + { + p->analyse.inter = 0; + if( strstr( value, "none" ) ) p->analyse.inter = 0; + if( strstr( value, "all" ) ) p->analyse.inter = ~0; + + if( strstr( value, "i4x4" ) ) p->analyse.inter |= X264_ANALYSE_I4x4; + if( strstr( value, "i8x8" ) ) p->analyse.inter |= X264_ANALYSE_I8x8; + if( strstr( value, "p8x8" ) ) p->analyse.inter |= X264_ANALYSE_PSUB16x16; + if( strstr( value, "p4x4" ) ) p->analyse.inter |= X264_ANALYSE_PSUB8x8; + if( strstr( value, "b8x8" ) ) p->analyse.inter |= X264_ANALYSE_BSUB16x16; + } + OPT("8x8dct") + p->analyse.b_transform_8x8 = atobool(value); + OPT2("weightb", "weight-b") + p->analyse.b_weighted_bipred = atobool(value); + OPT("weightp") + p->analyse.i_weighted_pred = atoi(value); + OPT2("direct", "direct-pred") + b_error |= parse_enum( value, x264_direct_pred_names, &p->analyse.i_direct_mv_pred ); + OPT("chroma-qp-offset") + p->analyse.i_chroma_qp_offset = atoi(value); + OPT("me") + b_error |= parse_enum( value, x264_motion_est_names, &p->analyse.i_me_method ); + OPT2("merange", "me-range") + p->analyse.i_me_range = atoi(value); + OPT2("mvrange", "mv-range") + p->analyse.i_mv_range = atoi(value); + OPT2("mvrange-thread", "mv-range-thread") + p->analyse.i_mv_range_thread = atoi(value); + OPT2("subme", "subq") + p->analyse.i_subpel_refine = atoi(value); + OPT("psy-rd") + { + if( 2 == sscanf( value, "%f:%f", &p->analyse.f_psy_rd, &p->analyse.f_psy_trellis ) || + 2 == sscanf( value, "%f,%f", &p->analyse.f_psy_rd, &p->analyse.f_psy_trellis ) || + 2 == sscanf( value, "%f|%f", &p->analyse.f_psy_rd, &p->analyse.f_psy_trellis )) + { } + else if( sscanf( value, "%f", &p->analyse.f_psy_rd ) ) + { + p->analyse.f_psy_trellis = 0; + } + else + { + p->analyse.f_psy_rd = 0; + p->analyse.f_psy_trellis = 0; + } + } + OPT("psy") + p->analyse.b_psy = atobool(value); + OPT("chroma-me") + p->analyse.b_chroma_me = atobool(value); + OPT("mixed-refs") + p->analyse.b_mixed_references = atobool(value); + OPT("trellis") + p->analyse.i_trellis = atoi(value); + OPT("fast-pskip") + p->analyse.b_fast_pskip = atobool(value); + OPT("dct-decimate") + p->analyse.b_dct_decimate = atobool(value); + OPT("deadzone-inter") + p->analyse.i_luma_deadzone[0] = atoi(value); + OPT("deadzone-intra") + p->analyse.i_luma_deadzone[1] = atoi(value); + OPT("nr") + p->analyse.i_noise_reduction = atoi(value); + OPT("bitrate") + { + p->rc.i_bitrate = atoi(value); + p->rc.i_rc_method = X264_RC_ABR; + } + OPT2("qp", "qp_constant") + { + p->rc.i_qp_constant = atoi(value); + p->rc.i_rc_method = X264_RC_CQP; + } + OPT("crf") + { + p->rc.f_rf_constant = atof(value); + p->rc.i_rc_method = X264_RC_CRF; + } + OPT("crf-max") + p->rc.f_rf_constant_max = atof(value); + OPT("rc-lookahead") + p->rc.i_lookahead = atoi(value); + OPT2("qpmin", "qp-min") + p->rc.i_qp_min = atoi(value); + OPT2("qpmax", "qp-max") + p->rc.i_qp_max = atoi(value); + OPT2("qpstep", "qp-step") + p->rc.i_qp_step = atoi(value); + OPT("ratetol") + p->rc.f_rate_tolerance = !strncmp("inf", value, 3) ? 1e9 : atof(value); + OPT("vbv-maxrate") + p->rc.i_vbv_max_bitrate = atoi(value); + OPT("vbv-bufsize") + p->rc.i_vbv_buffer_size = atoi(value); + OPT("vbv-init") + p->rc.f_vbv_buffer_init = atof(value); + OPT2("ipratio", "ip-factor") + p->rc.f_ip_factor = atof(value); + OPT2("pbratio", "pb-factor") + p->rc.f_pb_factor = atof(value); + OPT("aq-mode") + p->rc.i_aq_mode = atoi(value); + OPT("aq-strength") + p->rc.f_aq_strength = atof(value); + OPT("pass") + { + int pass = x264_clip3( atoi(value), 0, 3 ); + p->rc.b_stat_write = pass & 1; + p->rc.b_stat_read = pass & 2; + } + OPT("stats") + { + p->rc.psz_stat_in = strdup(value); + p->rc.psz_stat_out = strdup(value); + } + OPT("qcomp") + p->rc.f_qcompress = atof(value); + OPT("mbtree") + p->rc.b_mb_tree = atobool(value); + OPT("qblur") + p->rc.f_qblur = atof(value); + OPT2("cplxblur", "cplx-blur") + p->rc.f_complexity_blur = atof(value); + OPT("zones") + p->rc.psz_zones = strdup(value); + OPT("crop-rect") + b_error |= sscanf( value, "%u,%u,%u,%u", &p->crop_rect.i_left, &p->crop_rect.i_top, + &p->crop_rect.i_right, &p->crop_rect.i_bottom ) != 4; + OPT("psnr") + p->analyse.b_psnr = atobool(value); + OPT("ssim") + p->analyse.b_ssim = atobool(value); + OPT("aud") + p->b_aud = atobool(value); + OPT("sps-id") + p->i_sps_id = atoi(value); + OPT("global-header") + p->b_repeat_headers = !atobool(value); + OPT("repeat-headers") + p->b_repeat_headers = atobool(value); + OPT("annexb") + p->b_annexb = atobool(value); + OPT("force-cfr") + p->b_vfr_input = !atobool(value); + OPT("nal-hrd") + b_error |= parse_enum( value, x264_nal_hrd_names, &p->i_nal_hrd ); + OPT("filler") + p->rc.b_filler = atobool(value); + OPT("pic-struct") + p->b_pic_struct = atobool(value); + OPT("fake-interlaced") + p->b_fake_interlaced = atobool(value); + OPT("frame-packing") + p->i_frame_packing = atoi(value); + OPT("stitchable") + p->b_stitchable = atobool(value); + OPT("opencl") + p->b_opencl = atobool( value ); + OPT("opencl-clbin") + p->psz_clbin_file = strdup( value ); + OPT("opencl-device") + p->i_opencl_device = atoi( value ); + else + { + b_error = 1; + errortype = X264_PARAM_BAD_NAME; + } +#undef OPT +#undef OPT2 +#undef atobool +#undef atoi +#undef atof + + if( name_buf ) + free( name_buf ); + + b_error |= value_was_null && !name_was_bool; + return b_error ? errortype : 0; +} + +/**************************************************************************** + * x264_log: + ****************************************************************************/ +void x264_log( x264_t *h, int i_level, const char *psz_fmt, ... ) +{ + if( !h || i_level <= h->param.i_log_level ) + { + va_list arg; + va_start( arg, psz_fmt ); + if( !h ) + x264_log_default( NULL, i_level, psz_fmt, arg ); + else + h->param.pf_log( h->param.p_log_private, i_level, psz_fmt, arg ); + va_end( arg ); + } +} + +static void x264_log_default( void *p_unused, int i_level, const char *psz_fmt, va_list arg ) +{ + char *psz_prefix; + switch( i_level ) + { + case X264_LOG_ERROR: + psz_prefix = "error"; + break; + case X264_LOG_WARNING: + psz_prefix = "warning"; + break; + case X264_LOG_INFO: + psz_prefix = "info"; + break; + case X264_LOG_DEBUG: + psz_prefix = "debug"; + break; + default: + psz_prefix = "unknown"; + break; + } + fprintf( stderr, "x264 [%s]: ", psz_prefix ); + x264_vfprintf( stderr, psz_fmt, arg ); +} + +/**************************************************************************** + * x264_picture_init: + ****************************************************************************/ +void x264_picture_init( x264_picture_t *pic ) +{ + memset( pic, 0, sizeof( x264_picture_t ) ); + pic->i_type = X264_TYPE_AUTO; + pic->i_qpplus1 = X264_QP_AUTO; + pic->i_pic_struct = PIC_STRUCT_AUTO; +} + +/**************************************************************************** + * x264_picture_alloc: + ****************************************************************************/ +int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height ) +{ + typedef struct + { + int planes; + int width_fix8[3]; + int height_fix8[3]; + } x264_csp_tab_t; + + static const x264_csp_tab_t x264_csp_tab[] = + { + [X264_CSP_I420] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256/2, 256/2 } }, + [X264_CSP_YV12] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256/2, 256/2 } }, + [X264_CSP_NV12] = { 2, { 256*1, 256*1 }, { 256*1, 256/2 }, }, + [X264_CSP_NV21] = { 2, { 256*1, 256*1 }, { 256*1, 256/2 }, }, + [X264_CSP_I422] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256*1, 256*1 } }, + [X264_CSP_YV16] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256*1, 256*1 } }, + [X264_CSP_NV16] = { 2, { 256*1, 256*1 }, { 256*1, 256*1 }, }, + [X264_CSP_YUYV] = { 1, { 256*2 }, { 256*1 }, }, + [X264_CSP_UYVY] = { 1, { 256*2 }, { 256*1 }, }, + [X264_CSP_I444] = { 3, { 256*1, 256*1, 256*1 }, { 256*1, 256*1, 256*1 } }, + [X264_CSP_YV24] = { 3, { 256*1, 256*1, 256*1 }, { 256*1, 256*1, 256*1 } }, + [X264_CSP_BGR] = { 1, { 256*3 }, { 256*1 }, }, + [X264_CSP_BGRA] = { 1, { 256*4 }, { 256*1 }, }, + [X264_CSP_RGB] = { 1, { 256*3 }, { 256*1 }, }, + }; + + int csp = i_csp & X264_CSP_MASK; + if( csp <= X264_CSP_NONE || csp >= X264_CSP_MAX || csp == X264_CSP_V210 ) + return -1; + x264_picture_init( pic ); + pic->img.i_csp = i_csp; + pic->img.i_plane = x264_csp_tab[csp].planes; + int depth_factor = i_csp & X264_CSP_HIGH_DEPTH ? 2 : 1; + int plane_offset[3] = {0}; + int frame_size = 0; + for( int i = 0; i < pic->img.i_plane; i++ ) + { + int stride = (((int64_t)i_width * x264_csp_tab[csp].width_fix8[i]) >> 8) * depth_factor; + int plane_size = (((int64_t)i_height * x264_csp_tab[csp].height_fix8[i]) >> 8) * stride; + pic->img.i_stride[i] = stride; + plane_offset[i] = frame_size; + frame_size += plane_size; + } + pic->img.plane[0] = x264_malloc( frame_size ); + if( !pic->img.plane[0] ) + return -1; + for( int i = 1; i < pic->img.i_plane; i++ ) + pic->img.plane[i] = pic->img.plane[0] + plane_offset[i]; + return 0; +} + +/**************************************************************************** + * x264_picture_clean: + ****************************************************************************/ +void x264_picture_clean( x264_picture_t *pic ) +{ + x264_free( pic->img.plane[0] ); + + /* just to be safe */ + memset( pic, 0, sizeof( x264_picture_t ) ); +} + +/**************************************************************************** + * x264_malloc: + ****************************************************************************/ +void *x264_malloc( int i_size ) +{ + uint8_t *align_buf = NULL; +#if HAVE_MALLOC_H +#if HAVE_THP +#define HUGE_PAGE_SIZE 2*1024*1024 +#define HUGE_PAGE_THRESHOLD HUGE_PAGE_SIZE*7/8 /* FIXME: Is this optimal? */ + /* Attempt to allocate huge pages to reduce TLB misses. */ + if( i_size >= HUGE_PAGE_THRESHOLD ) + { + align_buf = memalign( HUGE_PAGE_SIZE, i_size ); + if( align_buf ) + { + /* Round up to the next huge page boundary if we are close enough. */ + size_t madv_size = (i_size + HUGE_PAGE_SIZE - HUGE_PAGE_THRESHOLD) & ~(HUGE_PAGE_SIZE-1); + madvise( align_buf, madv_size, MADV_HUGEPAGE ); + } + } + else +#undef HUGE_PAGE_SIZE +#undef HUGE_PAGE_THRESHOLD +#endif + align_buf = memalign( NATIVE_ALIGN, i_size ); +#else + uint8_t *buf = malloc( i_size + (NATIVE_ALIGN-1) + sizeof(void **) ); + if( buf ) + { + align_buf = buf + (NATIVE_ALIGN-1) + sizeof(void **); + align_buf -= (intptr_t) align_buf & (NATIVE_ALIGN-1); + *( (void **) ( align_buf - sizeof(void **) ) ) = buf; + } +#endif + if( !align_buf ) + x264_log( NULL, X264_LOG_ERROR, "malloc of size %d failed\n", i_size ); + return align_buf; +} + +/**************************************************************************** + * x264_free: + ****************************************************************************/ +void x264_free( void *p ) +{ + if( p ) + { +#if HAVE_MALLOC_H + free( p ); +#else + free( *( ( ( void **) p ) - 1 ) ); +#endif + } +} + +/**************************************************************************** + * x264_reduce_fraction: + ****************************************************************************/ +#define REDUCE_FRACTION( name, type )\ +void name( type *n, type *d )\ +{ \ + type a = *n; \ + type b = *d; \ + type c; \ + if( !a || !b ) \ + return; \ + c = a % b; \ + while( c ) \ + { \ + a = b; \ + b = c; \ + c = a % b; \ + } \ + *n /= b; \ + *d /= b; \ +} + +REDUCE_FRACTION( x264_reduce_fraction , uint32_t ) +REDUCE_FRACTION( x264_reduce_fraction64, uint64_t ) + +/**************************************************************************** + * x264_slurp_file: + ****************************************************************************/ +char *x264_slurp_file( const char *filename ) +{ + int b_error = 0; + int64_t i_size; + char *buf; + FILE *fh = x264_fopen( filename, "rb" ); + if( !fh ) + return NULL; + + b_error |= fseek( fh, 0, SEEK_END ) < 0; + b_error |= ( i_size = ftell( fh ) ) <= 0; + if( WORD_SIZE == 4 ) + b_error |= i_size > INT32_MAX; + b_error |= fseek( fh, 0, SEEK_SET ) < 0; + if( b_error ) + goto error; + + buf = x264_malloc( i_size+2 ); + if( !buf ) + goto error; + + b_error |= fread( buf, 1, i_size, fh ) != i_size; + fclose( fh ); + if( b_error ) + { + x264_free( buf ); + return NULL; + } + + if( buf[i_size-1] != '\n' ) + buf[i_size++] = '\n'; + buf[i_size] = '\0'; + + return buf; +error: + fclose( fh ); + return NULL; +} + +/**************************************************************************** + * x264_param2string: + ****************************************************************************/ +char *x264_param2string( x264_param_t *p, int b_res ) +{ + int len = 1000; + char *buf, *s; + if( p->rc.psz_zones ) + len += strlen(p->rc.psz_zones); + buf = s = x264_malloc( len ); + if( !buf ) + return NULL; + + if( b_res ) + { + s += sprintf( s, "%dx%d ", p->i_width, p->i_height ); + s += sprintf( s, "fps=%u/%u ", p->i_fps_num, p->i_fps_den ); + s += sprintf( s, "timebase=%u/%u ", p->i_timebase_num, p->i_timebase_den ); + s += sprintf( s, "bitdepth=%d ", BIT_DEPTH ); + } + + if( p->b_opencl ) + s += sprintf( s, "opencl=%d ", p->b_opencl ); + s += sprintf( s, "cabac=%d", p->b_cabac ); + s += sprintf( s, " ref=%d", p->i_frame_reference ); + s += sprintf( s, " deblock=%d:%d:%d", p->b_deblocking_filter, + p->i_deblocking_filter_alphac0, p->i_deblocking_filter_beta ); + s += sprintf( s, " analyse=%#x:%#x", p->analyse.intra, p->analyse.inter ); + s += sprintf( s, " me=%s", x264_motion_est_names[ p->analyse.i_me_method ] ); + s += sprintf( s, " subme=%d", p->analyse.i_subpel_refine ); + s += sprintf( s, " psy=%d", p->analyse.b_psy ); + if( p->analyse.b_psy ) + s += sprintf( s, " psy_rd=%.2f:%.2f", p->analyse.f_psy_rd, p->analyse.f_psy_trellis ); + s += sprintf( s, " mixed_ref=%d", p->analyse.b_mixed_references ); + s += sprintf( s, " me_range=%d", p->analyse.i_me_range ); + s += sprintf( s, " chroma_me=%d", p->analyse.b_chroma_me ); + s += sprintf( s, " trellis=%d", p->analyse.i_trellis ); + s += sprintf( s, " 8x8dct=%d", p->analyse.b_transform_8x8 ); + s += sprintf( s, " cqm=%d", p->i_cqm_preset ); + s += sprintf( s, " deadzone=%d,%d", p->analyse.i_luma_deadzone[0], p->analyse.i_luma_deadzone[1] ); + s += sprintf( s, " fast_pskip=%d", p->analyse.b_fast_pskip ); + s += sprintf( s, " chroma_qp_offset=%d", p->analyse.i_chroma_qp_offset ); + s += sprintf( s, " threads=%d", p->i_threads ); + s += sprintf( s, " lookahead_threads=%d", p->i_lookahead_threads ); + s += sprintf( s, " sliced_threads=%d", p->b_sliced_threads ); + if( p->i_slice_count ) + s += sprintf( s, " slices=%d", p->i_slice_count ); + if( p->i_slice_count_max ) + s += sprintf( s, " slices_max=%d", p->i_slice_count_max ); + if( p->i_slice_max_size ) + s += sprintf( s, " slice_max_size=%d", p->i_slice_max_size ); + if( p->i_slice_max_mbs ) + s += sprintf( s, " slice_max_mbs=%d", p->i_slice_max_mbs ); + if( p->i_slice_min_mbs ) + s += sprintf( s, " slice_min_mbs=%d", p->i_slice_min_mbs ); + s += sprintf( s, " nr=%d", p->analyse.i_noise_reduction ); + s += sprintf( s, " decimate=%d", p->analyse.b_dct_decimate ); + s += sprintf( s, " interlaced=%s", p->b_interlaced ? p->b_tff ? "tff" : "bff" : p->b_fake_interlaced ? "fake" : "0" ); + s += sprintf( s, " bluray_compat=%d", p->b_bluray_compat ); + if( p->b_stitchable ) + s += sprintf( s, " stitchable=%d", p->b_stitchable ); + + s += sprintf( s, " constrained_intra=%d", p->b_constrained_intra ); + + s += sprintf( s, " bframes=%d", p->i_bframe ); + if( p->i_bframe ) + { + s += sprintf( s, " b_pyramid=%d b_adapt=%d b_bias=%d direct=%d weightb=%d open_gop=%d", + p->i_bframe_pyramid, p->i_bframe_adaptive, p->i_bframe_bias, + p->analyse.i_direct_mv_pred, p->analyse.b_weighted_bipred, p->b_open_gop ); + } + s += sprintf( s, " weightp=%d", p->analyse.i_weighted_pred > 0 ? p->analyse.i_weighted_pred : 0 ); + + if( p->i_keyint_max == X264_KEYINT_MAX_INFINITE ) + s += sprintf( s, " keyint=infinite" ); + else + s += sprintf( s, " keyint=%d", p->i_keyint_max ); + s += sprintf( s, " keyint_min=%d scenecut=%d intra_refresh=%d", + p->i_keyint_min, p->i_scenecut_threshold, p->b_intra_refresh ); + + if( p->rc.b_mb_tree || p->rc.i_vbv_buffer_size ) + s += sprintf( s, " rc_lookahead=%d", p->rc.i_lookahead ); + + s += sprintf( s, " rc=%s mbtree=%d", p->rc.i_rc_method == X264_RC_ABR ? + ( p->rc.b_stat_read ? "2pass" : p->rc.i_vbv_max_bitrate == p->rc.i_bitrate ? "cbr" : "abr" ) + : p->rc.i_rc_method == X264_RC_CRF ? "crf" : "cqp", p->rc.b_mb_tree ); + if( p->rc.i_rc_method == X264_RC_ABR || p->rc.i_rc_method == X264_RC_CRF ) + { + if( p->rc.i_rc_method == X264_RC_CRF ) + s += sprintf( s, " crf=%.1f", p->rc.f_rf_constant ); + else + s += sprintf( s, " bitrate=%d ratetol=%.1f", + p->rc.i_bitrate, p->rc.f_rate_tolerance ); + s += sprintf( s, " qcomp=%.2f qpmin=%d qpmax=%d qpstep=%d", + p->rc.f_qcompress, p->rc.i_qp_min, p->rc.i_qp_max, p->rc.i_qp_step ); + if( p->rc.b_stat_read ) + s += sprintf( s, " cplxblur=%.1f qblur=%.1f", + p->rc.f_complexity_blur, p->rc.f_qblur ); + if( p->rc.i_vbv_buffer_size ) + { + s += sprintf( s, " vbv_maxrate=%d vbv_bufsize=%d", + p->rc.i_vbv_max_bitrate, p->rc.i_vbv_buffer_size ); + if( p->rc.i_rc_method == X264_RC_CRF ) + s += sprintf( s, " crf_max=%.1f", p->rc.f_rf_constant_max ); + } + } + else if( p->rc.i_rc_method == X264_RC_CQP ) + s += sprintf( s, " qp=%d", p->rc.i_qp_constant ); + + if( p->rc.i_vbv_buffer_size ) + s += sprintf( s, " nal_hrd=%s filler=%d", x264_nal_hrd_names[p->i_nal_hrd], p->rc.b_filler ); + if( p->crop_rect.i_left | p->crop_rect.i_top | p->crop_rect.i_right | p->crop_rect.i_bottom ) + s += sprintf( s, " crop_rect=%u,%u,%u,%u", p->crop_rect.i_left, p->crop_rect.i_top, + p->crop_rect.i_right, p->crop_rect.i_bottom ); + if( p->i_frame_packing >= 0 ) + s += sprintf( s, " frame-packing=%d", p->i_frame_packing ); + + if( !(p->rc.i_rc_method == X264_RC_CQP && p->rc.i_qp_constant == 0) ) + { + s += sprintf( s, " ip_ratio=%.2f", p->rc.f_ip_factor ); + if( p->i_bframe && !p->rc.b_mb_tree ) + s += sprintf( s, " pb_ratio=%.2f", p->rc.f_pb_factor ); + s += sprintf( s, " aq=%d", p->rc.i_aq_mode ); + if( p->rc.i_aq_mode ) + s += sprintf( s, ":%.2f", p->rc.f_aq_strength ); + if( p->rc.psz_zones ) + s += sprintf( s, " zones=%s", p->rc.psz_zones ); + else if( p->rc.i_zones ) + s += sprintf( s, " zones" ); + } + + return buf; +} + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/common.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/common.h new file mode 100644 index 00000000..867b2073 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/common.h @@ -0,0 +1,1022 @@ +/***************************************************************************** + * common.h: misc common functions + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_COMMON_H +#define X264_COMMON_H + +/**************************************************************************** + * Macros + ****************************************************************************/ +#define X264_MIN(a,b) ( (a)<(b) ? (a) : (b) ) +#define X264_MAX(a,b) ( (a)>(b) ? (a) : (b) ) +#define X264_MIN3(a,b,c) X264_MIN((a),X264_MIN((b),(c))) +#define X264_MAX3(a,b,c) X264_MAX((a),X264_MAX((b),(c))) +#define X264_MIN4(a,b,c,d) X264_MIN((a),X264_MIN3((b),(c),(d))) +#define X264_MAX4(a,b,c,d) X264_MAX((a),X264_MAX3((b),(c),(d))) +#define XCHG(type,a,b) do { type t = a; a = b; b = t; } while( 0 ) +#define IS_DISPOSABLE(type) ( type == X264_TYPE_B ) +#define FIX8(f) ((int)(f*(1<<8)+.5)) +#define ALIGN(x,a) (((x)+((a)-1))&~((a)-1)) +#define ARRAY_ELEMS(a) ((sizeof(a))/(sizeof(a[0]))) + +#define CHECKED_MALLOC( var, size )\ +do {\ + var = x264_malloc( size );\ + if( !var )\ + goto fail;\ +} while( 0 ) +#define CHECKED_MALLOCZERO( var, size )\ +do {\ + CHECKED_MALLOC( var, size );\ + memset( var, 0, size );\ +} while( 0 ) + +/* Macros for merging multiple allocations into a single large malloc, for improved + * use with huge pages. */ + +/* Needs to be enough to contain any set of buffers that use combined allocations */ +#define PREALLOC_BUF_SIZE 1024 + +#define PREALLOC_INIT\ + int prealloc_idx = 0;\ + size_t prealloc_size = 0;\ + uint8_t **preallocs[PREALLOC_BUF_SIZE]; + +#define PREALLOC( var, size )\ +do {\ + var = (void*)prealloc_size;\ + preallocs[prealloc_idx++] = (uint8_t**)&var;\ + prealloc_size += ALIGN(size, NATIVE_ALIGN);\ +} while( 0 ) + +#define PREALLOC_END( ptr )\ +do {\ + CHECKED_MALLOC( ptr, prealloc_size );\ + while( prealloc_idx-- )\ + *preallocs[prealloc_idx] += (intptr_t)ptr;\ +} while( 0 ) + +#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) + +#define X264_BFRAME_MAX 16 +#define X264_REF_MAX 16 +#define X264_THREAD_MAX 128 +#define X264_LOOKAHEAD_THREAD_MAX 16 +#define X264_PCM_COST (FRAME_SIZE(256*BIT_DEPTH)+16) +#define X264_LOOKAHEAD_MAX 250 +#define QP_BD_OFFSET (6*(BIT_DEPTH-8)) +#define QP_MAX_SPEC (51+QP_BD_OFFSET) +#define QP_MAX (QP_MAX_SPEC+18) +#define QP_MAX_MAX (51+2*6+18) +#define PIXEL_MAX ((1 << BIT_DEPTH)-1) +// arbitrary, but low because SATD scores are 1/4 normal +#define X264_LOOKAHEAD_QP (12+QP_BD_OFFSET) +#define SPEC_QP(x) X264_MIN((x), QP_MAX_SPEC) + +// number of pixels (per thread) in progress at any given time. +// 16 for the macroblock in progress + 3 for deblocking + 3 for motion compensation filter + 2 for extra safety +#define X264_THREAD_HEIGHT 24 + +/* WEIGHTP_FAKE is set when mb_tree & psy are enabled, but normal weightp is disabled + * (such as in baseline). It checks for fades in lookahead and adjusts qp accordingly + * to increase quality. Defined as (-1) so that if(i_weighted_pred > 0) is true only when + * real weights are being used. */ + +#define X264_WEIGHTP_FAKE (-1) + +#define NALU_OVERHEAD 5 // startcode + NAL type costs 5 bytes per frame +#define FILLER_OVERHEAD (NALU_OVERHEAD+1) +#define SEI_OVERHEAD (NALU_OVERHEAD - (h->param.b_annexb && !h->param.i_avcintra_class && (h->out.i_nal-1))) + +/**************************************************************************** + * Includes + ****************************************************************************/ +#include "osdep.h" +#include +#include +#include +#include +#include +#include + +#if HAVE_INTERLACED +# define MB_INTERLACED h->mb.b_interlaced +# define SLICE_MBAFF h->sh.b_mbaff +# define PARAM_INTERLACED h->param.b_interlaced +#else +# define MB_INTERLACED 0 +# define SLICE_MBAFF 0 +# define PARAM_INTERLACED 0 +#endif + +#ifdef CHROMA_FORMAT +# define CHROMA_H_SHIFT (CHROMA_FORMAT == CHROMA_420 || CHROMA_FORMAT == CHROMA_422) +# define CHROMA_V_SHIFT (CHROMA_FORMAT == CHROMA_420) +#else +# define CHROMA_FORMAT h->sps->i_chroma_format_idc +# define CHROMA_H_SHIFT h->mb.chroma_h_shift +# define CHROMA_V_SHIFT h->mb.chroma_v_shift +#endif + +#define CHROMA_SIZE(s) ((s)>>(CHROMA_H_SHIFT+CHROMA_V_SHIFT)) +#define FRAME_SIZE(s) ((s)+2*CHROMA_SIZE(s)) +#define CHROMA444 (CHROMA_FORMAT == CHROMA_444) + +/* Unions for type-punning. + * Mn: load or store n bits, aligned, native-endian + * CPn: copy n bits, aligned, native-endian + * we don't use memcpy for CPn because memcpy's args aren't assumed to be aligned */ +typedef union { uint16_t i; uint8_t c[2]; } MAY_ALIAS x264_union16_t; +typedef union { uint32_t i; uint16_t b[2]; uint8_t c[4]; } MAY_ALIAS x264_union32_t; +typedef union { uint64_t i; uint32_t a[2]; uint16_t b[4]; uint8_t c[8]; } MAY_ALIAS x264_union64_t; +typedef struct { uint64_t i[2]; } x264_uint128_t; +typedef union { x264_uint128_t i; uint64_t a[2]; uint32_t b[4]; uint16_t c[8]; uint8_t d[16]; } MAY_ALIAS x264_union128_t; +#define M16(src) (((x264_union16_t*)(src))->i) +#define M32(src) (((x264_union32_t*)(src))->i) +#define M64(src) (((x264_union64_t*)(src))->i) +#define M128(src) (((x264_union128_t*)(src))->i) +#define M128_ZERO ((x264_uint128_t){{0,0}}) +#define CP16(dst,src) M16(dst) = M16(src) +#define CP32(dst,src) M32(dst) = M32(src) +#define CP64(dst,src) M64(dst) = M64(src) +#define CP128(dst,src) M128(dst) = M128(src) + +#if HIGH_BIT_DEPTH + typedef uint16_t pixel; + typedef uint64_t pixel4; + typedef int32_t dctcoef; + typedef uint32_t udctcoef; + +# define PIXEL_SPLAT_X4(x) ((x)*0x0001000100010001ULL) +# define MPIXEL_X4(src) M64(src) +#else + typedef uint8_t pixel; + typedef uint32_t pixel4; + typedef int16_t dctcoef; + typedef uint16_t udctcoef; + +# define PIXEL_SPLAT_X4(x) ((x)*0x01010101U) +# define MPIXEL_X4(src) M32(src) +#endif + +#define BIT_DEPTH X264_BIT_DEPTH + +#define CPPIXEL_X4(dst,src) MPIXEL_X4(dst) = MPIXEL_X4(src) + +#define X264_SCAN8_LUMA_SIZE (5*8) +#define X264_SCAN8_SIZE (X264_SCAN8_LUMA_SIZE*3) +#define X264_SCAN8_0 (4+1*8) + +/* Scan8 organization: + * 0 1 2 3 4 5 6 7 + * 0 DY y y y y y + * 1 y Y Y Y Y + * 2 y Y Y Y Y + * 3 y Y Y Y Y + * 4 y Y Y Y Y + * 5 DU u u u u u + * 6 u U U U U + * 7 u U U U U + * 8 u U U U U + * 9 u U U U U + * 10 DV v v v v v + * 11 v V V V V + * 12 v V V V V + * 13 v V V V V + * 14 v V V V V + * DY/DU/DV are for luma/chroma DC. + */ + +#define LUMA_DC 48 +#define CHROMA_DC 49 + +static const uint8_t x264_scan8[16*3 + 3] = +{ + 4+ 1*8, 5+ 1*8, 4+ 2*8, 5+ 2*8, + 6+ 1*8, 7+ 1*8, 6+ 2*8, 7+ 2*8, + 4+ 3*8, 5+ 3*8, 4+ 4*8, 5+ 4*8, + 6+ 3*8, 7+ 3*8, 6+ 4*8, 7+ 4*8, + 4+ 6*8, 5+ 6*8, 4+ 7*8, 5+ 7*8, + 6+ 6*8, 7+ 6*8, 6+ 7*8, 7+ 7*8, + 4+ 8*8, 5+ 8*8, 4+ 9*8, 5+ 9*8, + 6+ 8*8, 7+ 8*8, 6+ 9*8, 7+ 9*8, + 4+11*8, 5+11*8, 4+12*8, 5+12*8, + 6+11*8, 7+11*8, 6+12*8, 7+12*8, + 4+13*8, 5+13*8, 4+14*8, 5+14*8, + 6+13*8, 7+13*8, 6+14*8, 7+14*8, + 0+ 0*8, 0+ 5*8, 0+10*8 +}; + +#include "x264.h" +#if HAVE_OPENCL +#include "opencl.h" +#endif +#include "cabac.h" +#include "bitstream.h" +#include "set.h" +#include "predict.h" +#include "pixel.h" +#include "mc.h" +#include "frame.h" +#include "dct.h" +#include "quant.h" +#include "cpu.h" +#include "threadpool.h" + +/**************************************************************************** + * General functions + ****************************************************************************/ +/* x264_malloc : will do or emulate a memalign + * you have to use x264_free for buffers allocated with x264_malloc */ +void *x264_malloc( int ); +void x264_free( void * ); + +/* x264_slurp_file: malloc space for the whole file and read it */ +char *x264_slurp_file( const char *filename ); + +/* x264_param2string: return a (malloced) string containing most of + * the encoding options */ +char *x264_param2string( x264_param_t *p, int b_res ); + +/* log */ +void x264_log( x264_t *h, int i_level, const char *psz_fmt, ... ); + +void x264_reduce_fraction( uint32_t *n, uint32_t *d ); +void x264_reduce_fraction64( uint64_t *n, uint64_t *d ); +void x264_cavlc_init( x264_t *h ); +void x264_cabac_init( x264_t *h ); + +static ALWAYS_INLINE pixel x264_clip_pixel( int x ) +{ + return ( (x & ~PIXEL_MAX) ? (-x)>>31 & PIXEL_MAX : x ); +} + +static ALWAYS_INLINE int x264_clip3( int v, int i_min, int i_max ) +{ + return ( (v < i_min) ? i_min : (v > i_max) ? i_max : v ); +} + +static ALWAYS_INLINE double x264_clip3f( double v, double f_min, double f_max ) +{ + return ( (v < f_min) ? f_min : (v > f_max) ? f_max : v ); +} + +static ALWAYS_INLINE int x264_median( int a, int b, int c ) +{ + int t = (a-b)&((a-b)>>31); + a -= t; + b += t; + b -= (b-c)&((b-c)>>31); + b += (a-b)&((a-b)>>31); + return b; +} + +static ALWAYS_INLINE void x264_median_mv( int16_t *dst, int16_t *a, int16_t *b, int16_t *c ) +{ + dst[0] = x264_median( a[0], b[0], c[0] ); + dst[1] = x264_median( a[1], b[1], c[1] ); +} + +static ALWAYS_INLINE int x264_predictor_difference( int16_t (*mvc)[2], intptr_t i_mvc ) +{ + int sum = 0; + for( int i = 0; i < i_mvc-1; i++ ) + { + sum += abs( mvc[i][0] - mvc[i+1][0] ) + + abs( mvc[i][1] - mvc[i+1][1] ); + } + return sum; +} + +static ALWAYS_INLINE uint16_t x264_cabac_mvd_sum( uint8_t *mvdleft, uint8_t *mvdtop ) +{ + int amvd0 = mvdleft[0] + mvdtop[0]; + int amvd1 = mvdleft[1] + mvdtop[1]; + amvd0 = (amvd0 > 2) + (amvd0 > 32); + amvd1 = (amvd1 > 2) + (amvd1 > 32); + return amvd0 + (amvd1<<8); +} + +extern const uint8_t x264_exp2_lut[64]; +extern const float x264_log2_lut[128]; +extern const float x264_log2_lz_lut[32]; + +/* Not a general-purpose function; multiplies input by -1/6 to convert + * qp to qscale. */ +static ALWAYS_INLINE int x264_exp2fix8( float x ) +{ + int i = x*(-64.f/6.f) + 512.5f; + if( i < 0 ) return 0; + if( i > 1023 ) return 0xffff; + return (x264_exp2_lut[i&63]+256) << (i>>6) >> 8; +} + +static ALWAYS_INLINE float x264_log2( uint32_t x ) +{ + int lz = x264_clz( x ); + return x264_log2_lut[(x<>24)&0x7f] + x264_log2_lz_lut[lz]; +} + +/**************************************************************************** + * + ****************************************************************************/ +enum slice_type_e +{ + SLICE_TYPE_P = 0, + SLICE_TYPE_B = 1, + SLICE_TYPE_I = 2, +}; + +static const char slice_type_to_char[] = { 'P', 'B', 'I' }; + +enum sei_payload_type_e +{ + SEI_BUFFERING_PERIOD = 0, + SEI_PIC_TIMING = 1, + SEI_PAN_SCAN_RECT = 2, + SEI_FILLER = 3, + SEI_USER_DATA_REGISTERED = 4, + SEI_USER_DATA_UNREGISTERED = 5, + SEI_RECOVERY_POINT = 6, + SEI_DEC_REF_PIC_MARKING = 7, + SEI_FRAME_PACKING = 45, +}; + +typedef struct +{ + x264_sps_t *sps; + x264_pps_t *pps; + + int i_type; + int i_first_mb; + int i_last_mb; + + int i_pps_id; + + int i_frame_num; + + int b_mbaff; + int b_field_pic; + int b_bottom_field; + + int i_idr_pic_id; /* -1 if nal_type != 5 */ + + int i_poc; + int i_delta_poc_bottom; + + int i_delta_poc[2]; + int i_redundant_pic_cnt; + + int b_direct_spatial_mv_pred; + + int b_num_ref_idx_override; + int i_num_ref_idx_l0_active; + int i_num_ref_idx_l1_active; + + int b_ref_pic_list_reordering[2]; + struct + { + int idc; + int arg; + } ref_pic_list_order[2][X264_REF_MAX]; + + /* P-frame weighting */ + int b_weighted_pred; + x264_weight_t weight[X264_REF_MAX*2][3]; + + int i_mmco_remove_from_end; + int i_mmco_command_count; + struct /* struct for future expansion */ + { + int i_difference_of_pic_nums; + int i_poc; + } mmco[X264_REF_MAX]; + + int i_cabac_init_idc; + + int i_qp; + int i_qp_delta; + int b_sp_for_swidth; + int i_qs_delta; + + /* deblocking filter */ + int i_disable_deblocking_filter_idc; + int i_alpha_c0_offset; + int i_beta_offset; + +} x264_slice_header_t; + +typedef struct x264_lookahead_t +{ + volatile uint8_t b_exit_thread; + uint8_t b_thread_active; + uint8_t b_analyse_keyframe; + int i_last_keyframe; + int i_slicetype_length; + x264_frame_t *last_nonb; + x264_pthread_t thread_handle; + x264_sync_frame_list_t ifbuf; + x264_sync_frame_list_t next; + x264_sync_frame_list_t ofbuf; +} x264_lookahead_t; + +typedef struct x264_ratecontrol_t x264_ratecontrol_t; + +typedef struct x264_left_table_t +{ + uint8_t intra[4]; + uint8_t nnz[4]; + uint8_t nnz_chroma[4]; + uint8_t mv[4]; + uint8_t ref[4]; +} x264_left_table_t; + +/* Current frame stats */ +typedef struct +{ + /* MV bits (MV+Ref+Block Type) */ + int i_mv_bits; + /* Texture bits (DCT coefs) */ + int i_tex_bits; + /* ? */ + int i_misc_bits; + /* MB type counts */ + int i_mb_count[19]; + int i_mb_count_i; + int i_mb_count_p; + int i_mb_count_skip; + int i_mb_count_8x8dct[2]; + int i_mb_count_ref[2][X264_REF_MAX*2]; + int i_mb_partition[17]; + int i_mb_cbp[6]; + int i_mb_pred_mode[4][13]; + int i_mb_field[3]; + /* Adaptive direct mv pred */ + int i_direct_score[2]; + /* Metrics */ + int64_t i_ssd[3]; + double f_ssim; + int i_ssim_cnt; +} x264_frame_stat_t; + +struct x264_t +{ + /* encoder parameters */ + x264_param_t param; + + x264_t *thread[X264_THREAD_MAX+1]; + x264_t *lookahead_thread[X264_LOOKAHEAD_THREAD_MAX]; + int b_thread_active; + int i_thread_phase; /* which thread to use for the next frame */ + int i_thread_idx; /* which thread this is */ + int i_threadslice_start; /* first row in this thread slice */ + int i_threadslice_end; /* row after the end of this thread slice */ + int i_threadslice_pass; /* which pass of encoding we are on */ + x264_threadpool_t *threadpool; + x264_threadpool_t *lookaheadpool; + x264_pthread_mutex_t mutex; + x264_pthread_cond_t cv; + + /* bitstream output */ + struct + { + int i_nal; + int i_nals_allocated; + x264_nal_t *nal; + int i_bitstream; /* size of p_bitstream */ + uint8_t *p_bitstream; /* will hold data for all nal */ + bs_t bs; + } out; + + uint8_t *nal_buffer; + int nal_buffer_size; + + x264_t *reconfig_h; + int reconfig; + + /**** thread synchronization starts here ****/ + + /* frame number/poc */ + int i_frame; + int i_frame_num; + + int i_thread_frames; /* Number of different frames being encoded by threads; + * 1 when sliced-threads is on. */ + int i_nal_type; + int i_nal_ref_idc; + + int64_t i_disp_fields; /* Number of displayed fields (both coded and implied via pic_struct) */ + int i_disp_fields_last_frame; + int64_t i_prev_duration; /* Duration of previous frame */ + int64_t i_coded_fields; /* Number of coded fields (both coded and implied via pic_struct) */ + int64_t i_cpb_delay; /* Equal to number of fields preceding this field + * since last buffering_period SEI */ + int64_t i_coded_fields_lookahead; /* Use separate counters for lookahead */ + int64_t i_cpb_delay_lookahead; + + int64_t i_cpb_delay_pir_offset; + int64_t i_cpb_delay_pir_offset_next; + + int b_queued_intra_refresh; + int64_t i_last_idr_pts; + + int i_idr_pic_id; + + /* quantization matrix for decoding, [cqm][qp%6][coef] */ + int (*dequant4_mf[4])[16]; /* [4][6][16] */ + int (*dequant8_mf[4])[64]; /* [4][6][64] */ + /* quantization matrix for trellis, [cqm][qp][coef] */ + int (*unquant4_mf[4])[16]; /* [4][QP_MAX_SPEC+1][16] */ + int (*unquant8_mf[4])[64]; /* [4][QP_MAX_SPEC+1][64] */ + /* quantization matrix for deadzone */ + udctcoef (*quant4_mf[4])[16]; /* [4][QP_MAX_SPEC+1][16] */ + udctcoef (*quant8_mf[4])[64]; /* [4][QP_MAX_SPEC+1][64] */ + udctcoef (*quant4_bias[4])[16]; /* [4][QP_MAX_SPEC+1][16] */ + udctcoef (*quant8_bias[4])[64]; /* [4][QP_MAX_SPEC+1][64] */ + udctcoef (*quant4_bias0[4])[16]; /* [4][QP_MAX_SPEC+1][16] */ + udctcoef (*quant8_bias0[4])[64]; /* [4][QP_MAX_SPEC+1][64] */ + udctcoef (*nr_offset_emergency)[4][64]; + + /* mv/ref cost arrays. */ + uint16_t *cost_mv[QP_MAX+1]; + uint16_t *cost_mv_fpel[QP_MAX+1][4]; + + const uint8_t *chroma_qp_table; /* includes both the nonlinear luma->chroma mapping and chroma_qp_offset */ + + /* Slice header */ + x264_slice_header_t sh; + + /* SPS / PPS */ + x264_sps_t sps[1]; + x264_pps_t pps[1]; + + /* Slice header backup, for SEI_DEC_REF_PIC_MARKING */ + int b_sh_backup; + x264_slice_header_t sh_backup; + + /* cabac context */ + x264_cabac_t cabac; + + struct + { + /* Frames to be encoded (whose types have been decided) */ + x264_frame_t **current; + /* Unused frames: 0 = fenc, 1 = fdec */ + x264_frame_t **unused[2]; + + /* Unused blank frames (for duplicates) */ + x264_frame_t **blank_unused; + + /* frames used for reference + sentinels */ + x264_frame_t *reference[X264_REF_MAX+2]; + + int i_last_keyframe; /* Frame number of the last keyframe */ + int i_last_idr; /* Frame number of the last IDR (not RP)*/ + int i_poc_last_open_gop; /* Poc of the I frame of the last open-gop. The value + * is only assigned during the period between that + * I frame and the next P or I frame, else -1 */ + + int i_input; /* Number of input frames already accepted */ + + int i_max_dpb; /* Number of frames allocated in the decoded picture buffer */ + int i_max_ref0; + int i_max_ref1; + int i_delay; /* Number of frames buffered for B reordering */ + int i_bframe_delay; + int64_t i_bframe_delay_time; + int64_t i_first_pts; + int64_t i_prev_reordered_pts[2]; + int64_t i_largest_pts; + int64_t i_second_largest_pts; + int b_have_lowres; /* Whether 1/2 resolution luma planes are being used */ + int b_have_sub8x8_esa; + } frames; + + /* current frame being encoded */ + x264_frame_t *fenc; + + /* frame being reconstructed */ + x264_frame_t *fdec; + + /* references lists */ + int i_ref[2]; + x264_frame_t *fref[2][X264_REF_MAX+3]; + x264_frame_t *fref_nearest[2]; + int b_ref_reorder[2]; + + /* hrd */ + int initial_cpb_removal_delay; + int initial_cpb_removal_delay_offset; + int64_t i_reordered_pts_delay; + + /* Current MB DCT coeffs */ + struct + { + ALIGNED_64( dctcoef luma16x16_dc[3][16] ); + ALIGNED_16( dctcoef chroma_dc[2][8] ); + // FIXME share memory? + ALIGNED_64( dctcoef luma8x8[12][64] ); + ALIGNED_64( dctcoef luma4x4[16*3][16] ); + } dct; + + /* MB table and cache for current frame/mb */ + struct + { + int i_mb_width; + int i_mb_height; + int i_mb_count; /* number of mbs in a frame */ + + /* Chroma subsampling */ + int chroma_h_shift; + int chroma_v_shift; + + /* Strides */ + int i_mb_stride; + int i_b8_stride; + int i_b4_stride; + int left_b8[2]; + int left_b4[2]; + + /* Current index */ + int i_mb_x; + int i_mb_y; + int i_mb_xy; + int i_b8_xy; + int i_b4_xy; + + /* Search parameters */ + int i_me_method; + int i_subpel_refine; + int b_chroma_me; + int b_trellis; + int b_noise_reduction; + int b_dct_decimate; + int i_psy_rd; /* Psy RD strength--fixed point value*/ + int i_psy_trellis; /* Psy trellis strength--fixed point value*/ + + int b_interlaced; + int b_adaptive_mbaff; /* MBAFF+subme 0 requires non-adaptive MBAFF i.e. all field mbs */ + + /* Allowed qpel MV range to stay within the picture + emulated edge pixels */ + int mv_min[2]; + int mv_max[2]; + int mv_miny_row[3]; /* 0 == top progressive, 1 == bot progressive, 2 == interlaced */ + int mv_maxy_row[3]; + /* Subpel MV range for motion search. + * same mv_min/max but includes levels' i_mv_range. */ + int mv_min_spel[2]; + int mv_max_spel[2]; + int mv_miny_spel_row[3]; + int mv_maxy_spel_row[3]; + /* Fullpel MV range for motion search */ + ALIGNED_8( int16_t mv_limit_fpel[2][2] ); /* min_x, min_y, max_x, max_y */ + int mv_miny_fpel_row[3]; + int mv_maxy_fpel_row[3]; + + /* neighboring MBs */ + unsigned int i_neighbour; + unsigned int i_neighbour8[4]; /* neighbours of each 8x8 or 4x4 block that are available */ + unsigned int i_neighbour4[16]; /* at the time the block is coded */ + unsigned int i_neighbour_intra; /* for constrained intra pred */ + unsigned int i_neighbour_frame; /* ignoring slice boundaries */ + int i_mb_type_top; + int i_mb_type_left[2]; + int i_mb_type_topleft; + int i_mb_type_topright; + int i_mb_prev_xy; + int i_mb_left_xy[2]; + int i_mb_top_xy; + int i_mb_topleft_xy; + int i_mb_topright_xy; + int i_mb_top_y; + int i_mb_topleft_y; + int i_mb_topright_y; + const x264_left_table_t *left_index_table; + int i_mb_top_mbpair_xy; + int topleft_partition; + int b_allow_skip; + int field_decoding_flag; + + /**** thread synchronization ends here ****/ + /* subsequent variables are either thread-local or constant, + * and won't be copied from one thread to another */ + + /* mb table */ + uint8_t *base; /* base pointer for all malloced data in this mb */ + int8_t *type; /* mb type */ + uint8_t *partition; /* mb partition */ + int8_t *qp; /* mb qp */ + int16_t *cbp; /* mb cbp: 0x0?: luma, 0x?0: chroma, 0x100: luma dc, 0x200 and 0x400: chroma dc, 0x1000 PCM (all set for PCM) */ + int8_t (*intra4x4_pred_mode)[8]; /* intra4x4 pred mode. for non I4x4 set to I_PRED_4x4_DC(2) */ + /* actually has only 7 entries; set to 8 for write-combining optimizations */ + uint8_t (*non_zero_count)[16*3]; /* nzc. for I_PCM set to 16 */ + int8_t *chroma_pred_mode; /* chroma_pred_mode. cabac only. for non intra I_PRED_CHROMA_DC(0) */ + int16_t (*mv[2])[2]; /* mb mv. set to 0 for intra mb */ + uint8_t (*mvd[2])[8][2]; /* absolute value of mb mv difference with predict, clipped to [0,33]. set to 0 if intra. cabac only */ + int8_t *ref[2]; /* mb ref. set to -1 if non used (intra or Lx only) */ + int16_t (*mvr[2][X264_REF_MAX*2])[2];/* 16x16 mv for each possible ref */ + int8_t *skipbp; /* block pattern for SKIP or DIRECT (sub)mbs. B-frames + cabac only */ + int8_t *mb_transform_size; /* transform_size_8x8_flag of each mb */ + uint32_t *slice_table; /* sh->first_mb of the slice that the indexed mb is part of */ + uint8_t *field; + + /* buffer for weighted versions of the reference frames */ + pixel *p_weight_buf[X264_REF_MAX]; + + /* current value */ + int i_type; + int i_partition; + ALIGNED_4( uint8_t i_sub_partition[4] ); + int b_transform_8x8; + + int i_cbp_luma; + int i_cbp_chroma; + + int i_intra16x16_pred_mode; + int i_chroma_pred_mode; + + /* skip flags for i4x4 and i8x8 + * 0 = encode as normal. + * 1 (non-RD only) = the DCT is still in h->dct, restore fdec and skip reconstruction. + * 2 (RD only) = the DCT has since been overwritten by RD; restore that too. */ + int i_skip_intra; + /* skip flag for motion compensation */ + /* if we've already done MC, we don't need to do it again */ + int b_skip_mc; + /* set to true if we are re-encoding a macroblock. */ + int b_reencode_mb; + int ip_offset; /* Used by PIR to offset the quantizer of intra-refresh blocks. */ + int b_deblock_rdo; + int b_overflow; /* If CAVLC had a level code overflow during bitstream writing. */ + + struct + { + /* space for p_fenc and p_fdec */ +#define FENC_STRIDE 16 +#define FDEC_STRIDE 32 + ALIGNED_64( pixel fenc_buf[48*FENC_STRIDE] ); + ALIGNED_64( pixel fdec_buf[54*FDEC_STRIDE] ); + + /* i4x4 and i8x8 backup data, for skipping the encode stage when possible */ + ALIGNED_16( pixel i4x4_fdec_buf[16*16] ); + ALIGNED_16( pixel i8x8_fdec_buf[16*16] ); + ALIGNED_64( dctcoef i8x8_dct_buf[3][64] ); + ALIGNED_64( dctcoef i4x4_dct_buf[15][16] ); + uint32_t i4x4_nnz_buf[4]; + uint32_t i8x8_nnz_buf[4]; + + /* Psy trellis DCT data */ + ALIGNED_16( dctcoef fenc_dct8[4][64] ); + ALIGNED_16( dctcoef fenc_dct4[16][16] ); + + /* Psy RD SATD/SA8D scores cache */ + ALIGNED_64( uint32_t fenc_satd_cache[32] ); + ALIGNED_16( uint64_t fenc_hadamard_cache[9] ); + + int i4x4_cbp; + int i8x8_cbp; + + /* pointer over mb of the frame to be compressed */ + pixel *p_fenc[3]; /* y,u,v */ + /* pointer to the actual source frame, not a block copy */ + pixel *p_fenc_plane[3]; + + /* pointer over mb of the frame to be reconstructed */ + pixel *p_fdec[3]; + + /* pointer over mb of the references */ + int i_fref[2]; + /* [12]: yN, yH, yV, yHV, (NV12 ? uv : I444 ? (uN, uH, uV, uHV, vN, ...)) */ + pixel *p_fref[2][X264_REF_MAX*2][12]; + pixel *p_fref_w[X264_REF_MAX*2]; /* weighted fullpel luma */ + uint16_t *p_integral[2][X264_REF_MAX]; + + /* fref stride */ + int i_stride[3]; + } pic; + + /* cache */ + struct + { + /* real intra4x4_pred_mode if I_4X4 or I_8X8, I_PRED_4x4_DC if mb available, -1 if not */ + ALIGNED_16( int8_t intra4x4_pred_mode[X264_SCAN8_LUMA_SIZE] ); + + /* i_non_zero_count if available else 0x80. intentionally misaligned by 8 for asm */ + ALIGNED_8( uint8_t non_zero_count[X264_SCAN8_SIZE] ); + + /* -1 if unused, -2 if unavailable */ + ALIGNED_4( int8_t ref[2][X264_SCAN8_LUMA_SIZE] ); + + /* 0 if not available */ + ALIGNED_16( int16_t mv[2][X264_SCAN8_LUMA_SIZE][2] ); + ALIGNED_8( uint8_t mvd[2][X264_SCAN8_LUMA_SIZE][2] ); + + /* 1 if SKIP or DIRECT. set only for B-frames + CABAC */ + ALIGNED_4( int8_t skip[X264_SCAN8_LUMA_SIZE] ); + + ALIGNED_4( int16_t direct_mv[2][4][2] ); + ALIGNED_4( int8_t direct_ref[2][4] ); + int direct_partition; + ALIGNED_4( int16_t pskip_mv[2] ); + + /* number of neighbors (top and left) that used 8x8 dct */ + int i_neighbour_transform_size; + int i_neighbour_skip; + + /* neighbor CBPs */ + int i_cbp_top; + int i_cbp_left; + + /* extra data required for mbaff in mv prediction */ + int16_t topright_mv[2][3][2]; + int8_t topright_ref[2][3]; + + /* current mb deblock strength */ + uint8_t (*deblock_strength)[8][4]; + } cache; + + /* */ + int i_qp; /* current qp */ + int i_chroma_qp; + int i_last_qp; /* last qp */ + int i_last_dqp; /* last delta qp */ + int b_variable_qp; /* whether qp is allowed to vary per macroblock */ + int b_lossless; + int b_direct_auto_read; /* take stats for --direct auto from the 2pass log */ + int b_direct_auto_write; /* analyse direct modes, to use and/or save */ + + /* lambda values */ + int i_trellis_lambda2[2][2]; /* [luma,chroma][inter,intra] */ + int i_psy_rd_lambda; + int i_chroma_lambda2_offset; + + /* B_direct and weighted prediction */ + int16_t dist_scale_factor_buf[2][2][X264_REF_MAX*2][4]; + int16_t (*dist_scale_factor)[4]; + int8_t bipred_weight_buf[2][2][X264_REF_MAX*2][4]; + int8_t (*bipred_weight)[4]; + /* maps fref1[0]'s ref indices into the current list0 */ +#define map_col_to_list0(col) h->mb.map_col_to_list0[(col)+2] + int8_t map_col_to_list0[X264_REF_MAX+2]; + int ref_blind_dupe; /* The index of the blind reference frame duplicate. */ + int8_t deblock_ref_table[X264_REF_MAX*2+2]; +#define deblock_ref_table(x) h->mb.deblock_ref_table[(x)+2] + } mb; + + /* rate control encoding only */ + x264_ratecontrol_t *rc; + + /* stats */ + struct + { + /* Cumulated stats */ + + /* per slice info */ + int i_frame_count[3]; + int64_t i_frame_size[3]; + double f_frame_qp[3]; + int i_consecutive_bframes[X264_BFRAME_MAX+1]; + /* */ + double f_ssd_global[3]; + double f_psnr_average[3]; + double f_psnr_mean_y[3]; + double f_psnr_mean_u[3]; + double f_psnr_mean_v[3]; + double f_ssim_mean_y[3]; + double f_frame_duration[3]; + /* */ + int64_t i_mb_count[3][19]; + int64_t i_mb_partition[2][17]; + int64_t i_mb_count_8x8dct[2]; + int64_t i_mb_count_ref[2][2][X264_REF_MAX*2]; + int64_t i_mb_cbp[6]; + int64_t i_mb_pred_mode[4][13]; + int64_t i_mb_field[3]; + /* */ + int i_direct_score[2]; + int i_direct_frames[2]; + /* num p-frames weighted */ + int i_wpred[2]; + + /* Current frame stats */ + x264_frame_stat_t frame; + } stat; + + /* 0 = luma 4x4, 1 = luma 8x8, 2 = chroma 4x4, 3 = chroma 8x8 */ + udctcoef (*nr_offset)[64]; + uint32_t (*nr_residual_sum)[64]; + uint32_t *nr_count; + + ALIGNED_32( udctcoef nr_offset_denoise[4][64] ); + ALIGNED_32( uint32_t nr_residual_sum_buf[2][4][64] ); + uint32_t nr_count_buf[2][4]; + + uint8_t luma2chroma_pixel[7]; /* Subsampled pixel size */ + + /* Buffers that are allocated per-thread even in sliced threads. */ + void *scratch_buffer; /* for any temporary storage that doesn't want repeated malloc */ + void *scratch_buffer2; /* if the first one's already in use */ + pixel *intra_border_backup[5][3]; /* bottom pixels of the previous mb row, used for intra prediction after the framebuffer has been deblocked */ + /* Deblock strength values are stored for each 4x4 partition. In MBAFF + * there are four extra values that need to be stored, located in [4][i]. */ + uint8_t (*deblock_strength[2])[2][8][4]; + + /* CPU functions dependents */ + x264_predict_t predict_16x16[4+3]; + x264_predict8x8_t predict_8x8[9+3]; + x264_predict_t predict_4x4[9+3]; + x264_predict_t predict_chroma[4+3]; + x264_predict_t predict_8x8c[4+3]; + x264_predict_t predict_8x16c[4+3]; + x264_predict_8x8_filter_t predict_8x8_filter; + + x264_pixel_function_t pixf; + x264_mc_functions_t mc; + x264_dct_function_t dctf; + x264_zigzag_function_t zigzagf; + x264_zigzag_function_t zigzagf_interlaced; + x264_zigzag_function_t zigzagf_progressive; + x264_quant_function_t quantf; + x264_deblock_function_t loopf; + x264_bitstream_function_t bsf; + + x264_lookahead_t *lookahead; + +#if HAVE_OPENCL + x264_opencl_t opencl; +#endif +}; + +typedef struct +{ + int sad; + int16_t mv[2]; +} mvsad_t; + +// included at the end because it needs x264_t +#include "macroblock.h" + +static int ALWAYS_INLINE x264_predictor_roundclip( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv ) +{ + int cnt = 0; + for( int i = 0; i < i_mvc; i++ ) + { + int mx = (mvc[i][0] + 2) >> 2; + int my = (mvc[i][1] + 2) >> 2; + uint32_t mv = pack16to32_mask(mx, my); + if( !mv || mv == pmv ) continue; + dst[cnt][0] = x264_clip3( mx, mv_limit[0][0], mv_limit[1][0] ); + dst[cnt][1] = x264_clip3( my, mv_limit[0][1], mv_limit[1][1] ); + cnt++; + } + return cnt; +} + +static int ALWAYS_INLINE x264_predictor_clip( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv ) +{ + int cnt = 0; + int qpel_limit[4] = {mv_limit[0][0] << 2, mv_limit[0][1] << 2, mv_limit[1][0] << 2, mv_limit[1][1] << 2}; + for( int i = 0; i < i_mvc; i++ ) + { + uint32_t mv = M32( mvc[i] ); + int mx = mvc[i][0]; + int my = mvc[i][1]; + if( !mv || mv == pmv ) continue; + dst[cnt][0] = x264_clip3( mx, qpel_limit[0], qpel_limit[2] ); + dst[cnt][1] = x264_clip3( my, qpel_limit[1], qpel_limit[3] ); + cnt++; + } + return cnt; +} + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/util.h" +#endif + +#include "rectangle.h" + +#endif + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cpu.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cpu.c new file mode 100644 index 00000000..f365482f --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cpu.c @@ -0,0 +1,490 @@ +/***************************************************************************** + * cpu.c: cpu detection + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#if HAVE_POSIXTHREAD && SYS_LINUX +#include +#endif +#if SYS_BEOS +#include +#endif +#if SYS_MACOSX || SYS_FREEBSD +#include +#include +#endif +#if SYS_OPENBSD +#include +#include +#include +#endif + +const x264_cpu_name_t x264_cpu_names[] = +{ +#if HAVE_MMX +// {"MMX", X264_CPU_MMX}, // we don't support asm on mmx1 cpus anymore +#define MMX2 X264_CPU_MMX|X264_CPU_MMX2 + {"MMX2", MMX2}, + {"MMXEXT", MMX2}, + {"SSE", MMX2|X264_CPU_SSE}, +#define SSE2 MMX2|X264_CPU_SSE|X264_CPU_SSE2 + {"SSE2Slow", SSE2|X264_CPU_SSE2_IS_SLOW}, + {"SSE2", SSE2}, + {"SSE2Fast", SSE2|X264_CPU_SSE2_IS_FAST}, + {"LZCNT", SSE2|X264_CPU_LZCNT}, + {"SSE3", SSE2|X264_CPU_SSE3}, + {"SSSE3", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3}, + {"SSE4.1", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4}, + {"SSE4", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4}, + {"SSE4.2", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4|X264_CPU_SSE42}, +#define AVX SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4|X264_CPU_SSE42|X264_CPU_AVX + {"AVX", AVX}, + {"XOP", AVX|X264_CPU_XOP}, + {"FMA4", AVX|X264_CPU_FMA4}, + {"FMA3", AVX|X264_CPU_FMA3}, + {"BMI1", AVX|X264_CPU_LZCNT|X264_CPU_BMI1}, + {"BMI2", AVX|X264_CPU_LZCNT|X264_CPU_BMI1|X264_CPU_BMI2}, +#define AVX2 AVX|X264_CPU_FMA3|X264_CPU_LZCNT|X264_CPU_BMI1|X264_CPU_BMI2|X264_CPU_AVX2 + {"AVX2", AVX2}, + {"AVX512", AVX2|X264_CPU_AVX512}, +#undef AVX2 +#undef AVX +#undef SSE2 +#undef MMX2 + {"Cache32", X264_CPU_CACHELINE_32}, + {"Cache64", X264_CPU_CACHELINE_64}, + {"SlowAtom", X264_CPU_SLOW_ATOM}, + {"SlowPshufb", X264_CPU_SLOW_PSHUFB}, + {"SlowPalignr", X264_CPU_SLOW_PALIGNR}, + {"SlowShuffle", X264_CPU_SLOW_SHUFFLE}, + {"UnalignedStack", X264_CPU_STACK_MOD4}, +#elif ARCH_PPC + {"Altivec", X264_CPU_ALTIVEC}, +#elif ARCH_ARM + {"ARMv6", X264_CPU_ARMV6}, + {"NEON", X264_CPU_NEON}, + {"FastNeonMRC", X264_CPU_FAST_NEON_MRC}, +#elif ARCH_AARCH64 + {"ARMv8", X264_CPU_ARMV8}, + {"NEON", X264_CPU_NEON}, +#elif ARCH_MIPS + {"MSA", X264_CPU_MSA}, +#endif + {"", 0}, +}; + +#if (ARCH_PPC && SYS_LINUX) || (ARCH_ARM && !HAVE_NEON) +#include +#include +static sigjmp_buf jmpbuf; +static volatile sig_atomic_t canjump = 0; + +static void sigill_handler( int sig ) +{ + if( !canjump ) + { + signal( sig, SIG_DFL ); + raise( sig ); + } + + canjump = 0; + siglongjmp( jmpbuf, 1 ); +} +#endif + +#if HAVE_MMX +int x264_cpu_cpuid_test( void ); +void x264_cpu_cpuid( uint32_t op, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx ); +uint64_t x264_cpu_xgetbv( int xcr ); + +uint32_t x264_cpu_detect( void ) +{ + uint32_t cpu = 0; + uint32_t eax, ebx, ecx, edx; + uint32_t vendor[4] = {0}; + uint32_t max_extended_cap, max_basic_cap; + +#if !ARCH_X86_64 + if( !x264_cpu_cpuid_test() ) + return 0; +#endif + + x264_cpu_cpuid( 0, &max_basic_cap, vendor+0, vendor+2, vendor+1 ); + if( max_basic_cap == 0 ) + return 0; + + x264_cpu_cpuid( 1, &eax, &ebx, &ecx, &edx ); + if( edx&0x00800000 ) + cpu |= X264_CPU_MMX; + else + return cpu; + if( edx&0x02000000 ) + cpu |= X264_CPU_MMX2|X264_CPU_SSE; + if( edx&0x04000000 ) + cpu |= X264_CPU_SSE2; + if( ecx&0x00000001 ) + cpu |= X264_CPU_SSE3; + if( ecx&0x00000200 ) + cpu |= X264_CPU_SSSE3|X264_CPU_SSE2_IS_FAST; + if( ecx&0x00080000 ) + cpu |= X264_CPU_SSE4; + if( ecx&0x00100000 ) + cpu |= X264_CPU_SSE42; + + if( ecx&0x08000000 ) /* XGETBV supported and XSAVE enabled by OS */ + { + uint64_t xcr0 = x264_cpu_xgetbv( 0 ); + if( (xcr0&0x6) == 0x6 ) /* XMM/YMM state */ + { + if( ecx&0x10000000 ) + cpu |= X264_CPU_AVX; + if( ecx&0x00001000 ) + cpu |= X264_CPU_FMA3; + + if( max_basic_cap >= 7 ) + { + x264_cpu_cpuid( 7, &eax, &ebx, &ecx, &edx ); + if( ebx&0x00000008 ) + cpu |= X264_CPU_BMI1; + if( ebx&0x00000100 ) + cpu |= X264_CPU_BMI2; + if( ebx&0x00000020 ) + cpu |= X264_CPU_AVX2; + + if( (xcr0&0xE0) == 0xE0 ) /* OPMASK/ZMM state */ + { + if( (ebx&0xD0030000) == 0xD0030000 ) + cpu |= X264_CPU_AVX512; + } + } + } + } + + x264_cpu_cpuid( 0x80000000, &eax, &ebx, &ecx, &edx ); + max_extended_cap = eax; + + if( max_extended_cap >= 0x80000001 ) + { + x264_cpu_cpuid( 0x80000001, &eax, &ebx, &ecx, &edx ); + + if( ecx&0x00000020 ) + cpu |= X264_CPU_LZCNT; /* Supported by Intel chips starting with Haswell */ + if( ecx&0x00000040 ) /* SSE4a, AMD only */ + { + int family = ((eax>>8)&0xf) + ((eax>>20)&0xff); + cpu |= X264_CPU_SSE2_IS_FAST; /* Phenom and later CPUs have fast SSE units */ + if( family == 0x14 ) + { + cpu &= ~X264_CPU_SSE2_IS_FAST; /* SSSE3 doesn't imply fast SSE anymore... */ + cpu |= X264_CPU_SSE2_IS_SLOW; /* Bobcat has 64-bit SIMD units */ + cpu |= X264_CPU_SLOW_PALIGNR; /* palignr is insanely slow on Bobcat */ + } + if( family == 0x16 ) + { + cpu |= X264_CPU_SLOW_PSHUFB; /* Jaguar's pshufb isn't that slow, but it's slow enough + * compared to alternate instruction sequences that this + * is equal or faster on almost all such functions. */ + } + } + + if( cpu & X264_CPU_AVX ) + { + if( ecx&0x00000800 ) /* XOP */ + cpu |= X264_CPU_XOP; + if( ecx&0x00010000 ) /* FMA4 */ + cpu |= X264_CPU_FMA4; + } + + if( !strcmp((char*)vendor, "AuthenticAMD") ) + { + if( edx&0x00400000 ) + cpu |= X264_CPU_MMX2; + if( (cpu&X264_CPU_SSE2) && !(cpu&X264_CPU_SSE2_IS_FAST) ) + cpu |= X264_CPU_SSE2_IS_SLOW; /* AMD CPUs come in two types: terrible at SSE and great at it */ + } + } + + if( !strcmp((char*)vendor, "GenuineIntel") ) + { + x264_cpu_cpuid( 1, &eax, &ebx, &ecx, &edx ); + int family = ((eax>>8)&0xf) + ((eax>>20)&0xff); + int model = ((eax>>4)&0xf) + ((eax>>12)&0xf0); + if( family == 6 ) + { + /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and 6/14 (core1 "yonah") + * theoretically support sse2, but it's significantly slower than mmx for + * almost all of x264's functions, so let's just pretend they don't. */ + if( model == 9 || model == 13 || model == 14 ) + { + cpu &= ~(X264_CPU_SSE2|X264_CPU_SSE3); + assert(!(cpu&(X264_CPU_SSSE3|X264_CPU_SSE4))); + } + /* Detect Atom CPU */ + else if( model == 28 ) + { + cpu |= X264_CPU_SLOW_ATOM; + cpu |= X264_CPU_SLOW_PSHUFB; + } + /* Conroe has a slow shuffle unit. Check the model number to make sure not + * to include crippled low-end Penryns and Nehalems that don't have SSE4. */ + else if( (cpu&X264_CPU_SSSE3) && !(cpu&X264_CPU_SSE4) && model < 23 ) + cpu |= X264_CPU_SLOW_SHUFFLE; + } + } + + if( (!strcmp((char*)vendor, "GenuineIntel") || !strcmp((char*)vendor, "CyrixInstead")) && !(cpu&X264_CPU_SSE42)) + { + /* cacheline size is specified in 3 places, any of which may be missing */ + x264_cpu_cpuid( 1, &eax, &ebx, &ecx, &edx ); + int cache = (ebx&0xff00)>>5; // cflush size + if( !cache && max_extended_cap >= 0x80000006 ) + { + x264_cpu_cpuid( 0x80000006, &eax, &ebx, &ecx, &edx ); + cache = ecx&0xff; // cacheline size + } + if( !cache && max_basic_cap >= 2 ) + { + // Cache and TLB Information + static const char cache32_ids[] = { 0x0a, 0x0c, 0x41, 0x42, 0x43, 0x44, 0x45, 0x82, 0x83, 0x84, 0x85, 0 }; + static const char cache64_ids[] = { 0x22, 0x23, 0x25, 0x29, 0x2c, 0x46, 0x47, 0x49, 0x60, 0x66, 0x67, + 0x68, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7c, 0x7f, 0x86, 0x87, 0 }; + uint32_t buf[4]; + int max, i = 0; + do { + x264_cpu_cpuid( 2, buf+0, buf+1, buf+2, buf+3 ); + max = buf[0]&0xff; + buf[0] &= ~0xff; + for( int j = 0; j < 4; j++ ) + if( !(buf[j]>>31) ) + while( buf[j] ) + { + if( strchr( cache32_ids, buf[j]&0xff ) ) + cache = 32; + if( strchr( cache64_ids, buf[j]&0xff ) ) + cache = 64; + buf[j] >>= 8; + } + } while( ++i < max ); + } + + if( cache == 32 ) + cpu |= X264_CPU_CACHELINE_32; + else if( cache == 64 ) + cpu |= X264_CPU_CACHELINE_64; + else + x264_log( NULL, X264_LOG_WARNING, "unable to determine cacheline size\n" ); + } + +#if STACK_ALIGNMENT < 16 + cpu |= X264_CPU_STACK_MOD4; +#endif + + return cpu; +} + +#elif ARCH_PPC && HAVE_ALTIVEC + +#if SYS_MACOSX || SYS_OPENBSD || SYS_FREEBSD +#include +uint32_t x264_cpu_detect( void ) +{ + /* Thank you VLC */ + uint32_t cpu = 0; +#if SYS_OPENBSD + int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC }; +#elif SYS_MACOSX + int selectors[2] = { CTL_HW, HW_VECTORUNIT }; +#endif + int has_altivec = 0; + size_t length = sizeof( has_altivec ); +#if SYS_MACOSX || SYS_OPENBSD + int error = sysctl( selectors, 2, &has_altivec, &length, NULL, 0 ); +#else + int error = sysctlbyname( "hw.altivec", &has_altivec, &length, NULL, 0 ); +#endif + + if( error == 0 && has_altivec != 0 ) + cpu |= X264_CPU_ALTIVEC; + + return cpu; +} + +#elif SYS_LINUX + +uint32_t x264_cpu_detect( void ) +{ +#ifdef __NO_FPRS__ + return 0; +#else + static void (*oldsig)( int ); + + oldsig = signal( SIGILL, sigill_handler ); + if( sigsetjmp( jmpbuf, 1 ) ) + { + signal( SIGILL, oldsig ); + return 0; + } + + canjump = 1; + asm volatile( "mtspr 256, %0\n\t" + "vand 0, 0, 0\n\t" + : + : "r"(-1) ); + canjump = 0; + + signal( SIGILL, oldsig ); + + return X264_CPU_ALTIVEC; +#endif +} +#endif + +#elif ARCH_ARM + +void x264_cpu_neon_test( void ); +int x264_cpu_fast_neon_mrc_test( void ); + +uint32_t x264_cpu_detect( void ) +{ + int flags = 0; +#if HAVE_ARMV6 + flags |= X264_CPU_ARMV6; + + // don't do this hack if compiled with -mfpu=neon +#if !HAVE_NEON + static void (* oldsig)( int ); + oldsig = signal( SIGILL, sigill_handler ); + if( sigsetjmp( jmpbuf, 1 ) ) + { + signal( SIGILL, oldsig ); + return flags; + } + + canjump = 1; + x264_cpu_neon_test(); + canjump = 0; + signal( SIGILL, oldsig ); +#endif + + flags |= X264_CPU_NEON; + + // fast neon -> arm (Cortex-A9) detection relies on user access to the + // cycle counter; this assumes ARMv7 performance counters. + // NEON requires at least ARMv7, ARMv8 may require changes here, but + // hopefully this hacky detection method will have been replaced by then. + // Note that there is potential for a race condition if another program or + // x264 instance disables or reinits the counters while x264 is using them, + // which may result in incorrect detection and the counters stuck enabled. + // right now Apple does not seem to support performance counters for this test +#ifndef __MACH__ + flags |= x264_cpu_fast_neon_mrc_test() ? X264_CPU_FAST_NEON_MRC : 0; +#endif + // TODO: write dual issue test? currently it's A8 (dual issue) vs. A9 (fast mrc) +#endif + return flags; +} + +#elif ARCH_AARCH64 + +uint32_t x264_cpu_detect( void ) +{ + return X264_CPU_ARMV8 | X264_CPU_NEON; +} + +#elif ARCH_MIPS + +uint32_t x264_cpu_detect( void ) +{ + uint32_t flags = 0; +#if HAVE_MSA + flags |= X264_CPU_MSA; +#endif + return flags; +} + +#else + +uint32_t x264_cpu_detect( void ) +{ + return 0; +} + +#endif + +int x264_cpu_num_processors( void ) +{ +#if !HAVE_THREAD + return 1; + +#elif SYS_WINDOWS + return x264_pthread_num_processors_np(); + +#elif SYS_CYGWIN || SYS_SunOS + return sysconf( _SC_NPROCESSORS_ONLN ); + +#elif SYS_LINUX +#ifdef __ANDROID__ + // Android NDK does not expose sched_getaffinity + return sysconf( _SC_NPROCESSORS_CONF ); +#else + cpu_set_t p_aff; + memset( &p_aff, 0, sizeof(p_aff) ); + if( sched_getaffinity( 0, sizeof(p_aff), &p_aff ) ) + return 1; +#if HAVE_CPU_COUNT + return CPU_COUNT(&p_aff); +#else + int np = 0; + for( unsigned int bit = 0; bit < 8 * sizeof(p_aff); bit++ ) + np += (((uint8_t *)&p_aff)[bit / 8] >> (bit % 8)) & 1; + return np; +#endif +#endif + +#elif SYS_BEOS + system_info info; + get_system_info( &info ); + return info.cpu_count; + +#elif SYS_MACOSX || SYS_FREEBSD || SYS_OPENBSD + int ncpu; + size_t length = sizeof( ncpu ); +#if SYS_OPENBSD + int mib[2] = { CTL_HW, HW_NCPU }; + if( sysctl(mib, 2, &ncpu, &length, NULL, 0) ) +#else + if( sysctlbyname("hw.ncpu", &ncpu, &length, NULL, 0) ) +#endif + { + ncpu = 1; + } + return ncpu; + +#else + return 1; +#endif +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cpu.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cpu.h new file mode 100644 index 00000000..845034c4 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/cpu.h @@ -0,0 +1,73 @@ +/***************************************************************************** + * cpu.h: cpu detection + ***************************************************************************** + * Copyright (C) 2004-2017 x264 project + * + * Authors: Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_CPU_H +#define X264_CPU_H + +uint32_t x264_cpu_detect( void ); +int x264_cpu_num_processors( void ); +void x264_cpu_emms( void ); +void x264_cpu_sfence( void ); +#if HAVE_MMX +/* There is no way to forbid the compiler from using float instructions + * before the emms so miscompilation could theoretically occur in the + * unlikely event that the compiler reorders emms and float instructions. */ +#if HAVE_X86_INLINE_ASM +/* Clobbering memory makes the compiler less likely to reorder code. */ +#define x264_emms() asm volatile( "emms":::"memory","st","st(1)","st(2)", \ + "st(3)","st(4)","st(5)","st(6)","st(7)" ) +#else +#define x264_emms() x264_cpu_emms() +#endif +#else +#define x264_emms() +#endif +#define x264_sfence x264_cpu_sfence + +/* kludge: + * gcc can't give variables any greater alignment than the stack frame has. + * We need 32 byte alignment for AVX2, so here we make sure that the stack is + * aligned to 32 bytes. + * gcc 4.2 introduced __attribute__((force_align_arg_pointer)) to fix this + * problem, but I don't want to require such a new version. + * aligning to 32 bytes only works if the compiler supports keeping that + * alignment between functions (osdep.h handles manual alignment of arrays + * if it doesn't). + */ +#if HAVE_MMX && (STACK_ALIGNMENT > 16 || (ARCH_X86 && STACK_ALIGNMENT > 4)) +intptr_t x264_stack_align( void (*func)(), ... ); +#define x264_stack_align(func,...) x264_stack_align((void (*)())func, __VA_ARGS__) +#else +#define x264_stack_align(func,...) func(__VA_ARGS__) +#endif + +typedef struct +{ + const char *name; + uint32_t flags; +} x264_cpu_name_t; +extern const x264_cpu_name_t x264_cpu_names[]; + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/dct.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/dct.c new file mode 100644 index 00000000..a2010433 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/dct.c @@ -0,0 +1,1155 @@ +/***************************************************************************** + * dct.c: transform and zigzag + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" +#if HAVE_MMX +# include "x86/dct.h" +#endif +#if ARCH_PPC +# include "ppc/dct.h" +#endif +#if ARCH_ARM +# include "arm/dct.h" +#endif +#if ARCH_AARCH64 +# include "aarch64/dct.h" +#endif +#if ARCH_MIPS +# include "mips/dct.h" +#endif + +/* the inverse of the scaling factors introduced by 8x8 fdct */ +/* uint32 is for the asm implementation of trellis. the actual values fit in uint16. */ +#define W(i) (i==0 ? FIX8(1.0000) :\ + i==1 ? FIX8(0.8859) :\ + i==2 ? FIX8(1.6000) :\ + i==3 ? FIX8(0.9415) :\ + i==4 ? FIX8(1.2651) :\ + i==5 ? FIX8(1.1910) :0) +const uint32_t x264_dct8_weight_tab[64] = { + W(0), W(3), W(4), W(3), W(0), W(3), W(4), W(3), + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1), + W(4), W(5), W(2), W(5), W(4), W(5), W(2), W(5), + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1), + + W(0), W(3), W(4), W(3), W(0), W(3), W(4), W(3), + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1), + W(4), W(5), W(2), W(5), W(4), W(5), W(2), W(5), + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1) +}; +#undef W + +#define W(i) (i==0 ? FIX8(1.76777) :\ + i==1 ? FIX8(1.11803) :\ + i==2 ? FIX8(0.70711) :0) +const uint32_t x264_dct4_weight_tab[16] = { + W(0), W(1), W(0), W(1), + W(1), W(2), W(1), W(2), + W(0), W(1), W(0), W(1), + W(1), W(2), W(1), W(2) +}; +#undef W + +/* inverse squared */ +#define W(i) (i==0 ? FIX8(3.125) :\ + i==1 ? FIX8(1.25) :\ + i==2 ? FIX8(0.5) :0) +const uint32_t x264_dct4_weight2_tab[16] = { + W(0), W(1), W(0), W(1), + W(1), W(2), W(1), W(2), + W(0), W(1), W(0), W(1), + W(1), W(2), W(1), W(2) +}; +#undef W + +#define W(i) (i==0 ? FIX8(1.00000) :\ + i==1 ? FIX8(0.78487) :\ + i==2 ? FIX8(2.56132) :\ + i==3 ? FIX8(0.88637) :\ + i==4 ? FIX8(1.60040) :\ + i==5 ? FIX8(1.41850) :0) +const uint32_t x264_dct8_weight2_tab[64] = { + W(0), W(3), W(4), W(3), W(0), W(3), W(4), W(3), + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1), + W(4), W(5), W(2), W(5), W(4), W(5), W(2), W(5), + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1), + + W(0), W(3), W(4), W(3), W(0), W(3), W(4), W(3), + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1), + W(4), W(5), W(2), W(5), W(4), W(5), W(2), W(5), + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1) +}; +#undef W + + +static void dct4x4dc( dctcoef d[16] ) +{ + dctcoef tmp[16]; + + for( int i = 0; i < 4; i++ ) + { + int s01 = d[i*4+0] + d[i*4+1]; + int d01 = d[i*4+0] - d[i*4+1]; + int s23 = d[i*4+2] + d[i*4+3]; + int d23 = d[i*4+2] - d[i*4+3]; + + tmp[0*4+i] = s01 + s23; + tmp[1*4+i] = s01 - s23; + tmp[2*4+i] = d01 - d23; + tmp[3*4+i] = d01 + d23; + } + + for( int i = 0; i < 4; i++ ) + { + int s01 = tmp[i*4+0] + tmp[i*4+1]; + int d01 = tmp[i*4+0] - tmp[i*4+1]; + int s23 = tmp[i*4+2] + tmp[i*4+3]; + int d23 = tmp[i*4+2] - tmp[i*4+3]; + + d[i*4+0] = ( s01 + s23 + 1 ) >> 1; + d[i*4+1] = ( s01 - s23 + 1 ) >> 1; + d[i*4+2] = ( d01 - d23 + 1 ) >> 1; + d[i*4+3] = ( d01 + d23 + 1 ) >> 1; + } +} + +static void idct4x4dc( dctcoef d[16] ) +{ + dctcoef tmp[16]; + + for( int i = 0; i < 4; i++ ) + { + int s01 = d[i*4+0] + d[i*4+1]; + int d01 = d[i*4+0] - d[i*4+1]; + int s23 = d[i*4+2] + d[i*4+3]; + int d23 = d[i*4+2] - d[i*4+3]; + + tmp[0*4+i] = s01 + s23; + tmp[1*4+i] = s01 - s23; + tmp[2*4+i] = d01 - d23; + tmp[3*4+i] = d01 + d23; + } + + for( int i = 0; i < 4; i++ ) + { + int s01 = tmp[i*4+0] + tmp[i*4+1]; + int d01 = tmp[i*4+0] - tmp[i*4+1]; + int s23 = tmp[i*4+2] + tmp[i*4+3]; + int d23 = tmp[i*4+2] - tmp[i*4+3]; + + d[i*4+0] = s01 + s23; + d[i*4+1] = s01 - s23; + d[i*4+2] = d01 - d23; + d[i*4+3] = d01 + d23; + } +} + +static void dct2x4dc( dctcoef dct[8], dctcoef dct4x4[8][16] ) +{ + int a0 = dct4x4[0][0] + dct4x4[1][0]; + int a1 = dct4x4[2][0] + dct4x4[3][0]; + int a2 = dct4x4[4][0] + dct4x4[5][0]; + int a3 = dct4x4[6][0] + dct4x4[7][0]; + int a4 = dct4x4[0][0] - dct4x4[1][0]; + int a5 = dct4x4[2][0] - dct4x4[3][0]; + int a6 = dct4x4[4][0] - dct4x4[5][0]; + int a7 = dct4x4[6][0] - dct4x4[7][0]; + int b0 = a0 + a1; + int b1 = a2 + a3; + int b2 = a4 + a5; + int b3 = a6 + a7; + int b4 = a0 - a1; + int b5 = a2 - a3; + int b6 = a4 - a5; + int b7 = a6 - a7; + dct[0] = b0 + b1; + dct[1] = b2 + b3; + dct[2] = b0 - b1; + dct[3] = b2 - b3; + dct[4] = b4 - b5; + dct[5] = b6 - b7; + dct[6] = b4 + b5; + dct[7] = b6 + b7; + dct4x4[0][0] = 0; + dct4x4[1][0] = 0; + dct4x4[2][0] = 0; + dct4x4[3][0] = 0; + dct4x4[4][0] = 0; + dct4x4[5][0] = 0; + dct4x4[6][0] = 0; + dct4x4[7][0] = 0; +} + +static inline void pixel_sub_wxh( dctcoef *diff, int i_size, + pixel *pix1, int i_pix1, pixel *pix2, int i_pix2 ) +{ + for( int y = 0; y < i_size; y++ ) + { + for( int x = 0; x < i_size; x++ ) + diff[x + y*i_size] = pix1[x] - pix2[x]; + pix1 += i_pix1; + pix2 += i_pix2; + } +} + +static void sub4x4_dct( dctcoef dct[16], pixel *pix1, pixel *pix2 ) +{ + dctcoef d[16]; + dctcoef tmp[16]; + + pixel_sub_wxh( d, 4, pix1, FENC_STRIDE, pix2, FDEC_STRIDE ); + + for( int i = 0; i < 4; i++ ) + { + int s03 = d[i*4+0] + d[i*4+3]; + int s12 = d[i*4+1] + d[i*4+2]; + int d03 = d[i*4+0] - d[i*4+3]; + int d12 = d[i*4+1] - d[i*4+2]; + + tmp[0*4+i] = s03 + s12; + tmp[1*4+i] = 2*d03 + d12; + tmp[2*4+i] = s03 - s12; + tmp[3*4+i] = d03 - 2*d12; + } + + for( int i = 0; i < 4; i++ ) + { + int s03 = tmp[i*4+0] + tmp[i*4+3]; + int s12 = tmp[i*4+1] + tmp[i*4+2]; + int d03 = tmp[i*4+0] - tmp[i*4+3]; + int d12 = tmp[i*4+1] - tmp[i*4+2]; + + dct[i*4+0] = s03 + s12; + dct[i*4+1] = 2*d03 + d12; + dct[i*4+2] = s03 - s12; + dct[i*4+3] = d03 - 2*d12; + } +} + +static void sub8x8_dct( dctcoef dct[4][16], pixel *pix1, pixel *pix2 ) +{ + sub4x4_dct( dct[0], &pix1[0], &pix2[0] ); + sub4x4_dct( dct[1], &pix1[4], &pix2[4] ); + sub4x4_dct( dct[2], &pix1[4*FENC_STRIDE+0], &pix2[4*FDEC_STRIDE+0] ); + sub4x4_dct( dct[3], &pix1[4*FENC_STRIDE+4], &pix2[4*FDEC_STRIDE+4] ); +} + +static void sub16x16_dct( dctcoef dct[16][16], pixel *pix1, pixel *pix2 ) +{ + sub8x8_dct( &dct[ 0], &pix1[0], &pix2[0] ); + sub8x8_dct( &dct[ 4], &pix1[8], &pix2[8] ); + sub8x8_dct( &dct[ 8], &pix1[8*FENC_STRIDE+0], &pix2[8*FDEC_STRIDE+0] ); + sub8x8_dct( &dct[12], &pix1[8*FENC_STRIDE+8], &pix2[8*FDEC_STRIDE+8] ); +} + +static int sub4x4_dct_dc( pixel *pix1, pixel *pix2 ) +{ + int sum = 0; + for( int i=0; i<4; i++, pix1 += FENC_STRIDE, pix2 += FDEC_STRIDE ) + sum += pix1[0] + pix1[1] + pix1[2] + pix1[3] + - pix2[0] - pix2[1] - pix2[2] - pix2[3]; + return sum; +} + +static void sub8x8_dct_dc( dctcoef dct[4], pixel *pix1, pixel *pix2 ) +{ + dct[0] = sub4x4_dct_dc( &pix1[0], &pix2[0] ); + dct[1] = sub4x4_dct_dc( &pix1[4], &pix2[4] ); + dct[2] = sub4x4_dct_dc( &pix1[4*FENC_STRIDE+0], &pix2[4*FDEC_STRIDE+0] ); + dct[3] = sub4x4_dct_dc( &pix1[4*FENC_STRIDE+4], &pix2[4*FDEC_STRIDE+4] ); + + /* 2x2 DC transform */ + int d0 = dct[0] + dct[1]; + int d1 = dct[2] + dct[3]; + int d2 = dct[0] - dct[1]; + int d3 = dct[2] - dct[3]; + dct[0] = d0 + d1; + dct[1] = d0 - d1; + dct[2] = d2 + d3; + dct[3] = d2 - d3; +} + +static void sub8x16_dct_dc( dctcoef dct[8], pixel *pix1, pixel *pix2 ) +{ + int a0 = sub4x4_dct_dc( &pix1[ 0*FENC_STRIDE+0], &pix2[ 0*FDEC_STRIDE+0] ); + int a1 = sub4x4_dct_dc( &pix1[ 0*FENC_STRIDE+4], &pix2[ 0*FDEC_STRIDE+4] ); + int a2 = sub4x4_dct_dc( &pix1[ 4*FENC_STRIDE+0], &pix2[ 4*FDEC_STRIDE+0] ); + int a3 = sub4x4_dct_dc( &pix1[ 4*FENC_STRIDE+4], &pix2[ 4*FDEC_STRIDE+4] ); + int a4 = sub4x4_dct_dc( &pix1[ 8*FENC_STRIDE+0], &pix2[ 8*FDEC_STRIDE+0] ); + int a5 = sub4x4_dct_dc( &pix1[ 8*FENC_STRIDE+4], &pix2[ 8*FDEC_STRIDE+4] ); + int a6 = sub4x4_dct_dc( &pix1[12*FENC_STRIDE+0], &pix2[12*FDEC_STRIDE+0] ); + int a7 = sub4x4_dct_dc( &pix1[12*FENC_STRIDE+4], &pix2[12*FDEC_STRIDE+4] ); + + /* 2x4 DC transform */ + int b0 = a0 + a1; + int b1 = a2 + a3; + int b2 = a4 + a5; + int b3 = a6 + a7; + int b4 = a0 - a1; + int b5 = a2 - a3; + int b6 = a4 - a5; + int b7 = a6 - a7; + a0 = b0 + b1; + a1 = b2 + b3; + a2 = b4 + b5; + a3 = b6 + b7; + a4 = b0 - b1; + a5 = b2 - b3; + a6 = b4 - b5; + a7 = b6 - b7; + dct[0] = a0 + a1; + dct[1] = a2 + a3; + dct[2] = a0 - a1; + dct[3] = a2 - a3; + dct[4] = a4 - a5; + dct[5] = a6 - a7; + dct[6] = a4 + a5; + dct[7] = a6 + a7; +} + +static void add4x4_idct( pixel *p_dst, dctcoef dct[16] ) +{ + dctcoef d[16]; + dctcoef tmp[16]; + + for( int i = 0; i < 4; i++ ) + { + int s02 = dct[0*4+i] + dct[2*4+i]; + int d02 = dct[0*4+i] - dct[2*4+i]; + int s13 = dct[1*4+i] + (dct[3*4+i]>>1); + int d13 = (dct[1*4+i]>>1) - dct[3*4+i]; + + tmp[i*4+0] = s02 + s13; + tmp[i*4+1] = d02 + d13; + tmp[i*4+2] = d02 - d13; + tmp[i*4+3] = s02 - s13; + } + + for( int i = 0; i < 4; i++ ) + { + int s02 = tmp[0*4+i] + tmp[2*4+i]; + int d02 = tmp[0*4+i] - tmp[2*4+i]; + int s13 = tmp[1*4+i] + (tmp[3*4+i]>>1); + int d13 = (tmp[1*4+i]>>1) - tmp[3*4+i]; + + d[0*4+i] = ( s02 + s13 + 32 ) >> 6; + d[1*4+i] = ( d02 + d13 + 32 ) >> 6; + d[2*4+i] = ( d02 - d13 + 32 ) >> 6; + d[3*4+i] = ( s02 - s13 + 32 ) >> 6; + } + + + for( int y = 0; y < 4; y++ ) + { + for( int x = 0; x < 4; x++ ) + p_dst[x] = x264_clip_pixel( p_dst[x] + d[y*4+x] ); + p_dst += FDEC_STRIDE; + } +} + +static void add8x8_idct( pixel *p_dst, dctcoef dct[4][16] ) +{ + add4x4_idct( &p_dst[0], dct[0] ); + add4x4_idct( &p_dst[4], dct[1] ); + add4x4_idct( &p_dst[4*FDEC_STRIDE+0], dct[2] ); + add4x4_idct( &p_dst[4*FDEC_STRIDE+4], dct[3] ); +} + +static void add16x16_idct( pixel *p_dst, dctcoef dct[16][16] ) +{ + add8x8_idct( &p_dst[0], &dct[0] ); + add8x8_idct( &p_dst[8], &dct[4] ); + add8x8_idct( &p_dst[8*FDEC_STRIDE+0], &dct[8] ); + add8x8_idct( &p_dst[8*FDEC_STRIDE+8], &dct[12] ); +} + +/**************************************************************************** + * 8x8 transform: + ****************************************************************************/ + +#define DCT8_1D {\ + int s07 = SRC(0) + SRC(7);\ + int s16 = SRC(1) + SRC(6);\ + int s25 = SRC(2) + SRC(5);\ + int s34 = SRC(3) + SRC(4);\ + int a0 = s07 + s34;\ + int a1 = s16 + s25;\ + int a2 = s07 - s34;\ + int a3 = s16 - s25;\ + int d07 = SRC(0) - SRC(7);\ + int d16 = SRC(1) - SRC(6);\ + int d25 = SRC(2) - SRC(5);\ + int d34 = SRC(3) - SRC(4);\ + int a4 = d16 + d25 + (d07 + (d07>>1));\ + int a5 = d07 - d34 - (d25 + (d25>>1));\ + int a6 = d07 + d34 - (d16 + (d16>>1));\ + int a7 = d16 - d25 + (d34 + (d34>>1));\ + DST(0) = a0 + a1 ;\ + DST(1) = a4 + (a7>>2);\ + DST(2) = a2 + (a3>>1);\ + DST(3) = a5 + (a6>>2);\ + DST(4) = a0 - a1 ;\ + DST(5) = a6 - (a5>>2);\ + DST(6) = (a2>>1) - a3 ;\ + DST(7) = (a4>>2) - a7 ;\ +} + +static void sub8x8_dct8( dctcoef dct[64], pixel *pix1, pixel *pix2 ) +{ + dctcoef tmp[64]; + + pixel_sub_wxh( tmp, 8, pix1, FENC_STRIDE, pix2, FDEC_STRIDE ); + +#undef SRC +#define SRC(x) tmp[x*8+i] +#define DST(x) tmp[x*8+i] + for( int i = 0; i < 8; i++ ) + DCT8_1D +#undef SRC +#undef DST + +#define SRC(x) tmp[i*8+x] +#define DST(x) dct[x*8+i] + for( int i = 0; i < 8; i++ ) + DCT8_1D +#undef SRC +#undef DST +} + +static void sub16x16_dct8( dctcoef dct[4][64], pixel *pix1, pixel *pix2 ) +{ + sub8x8_dct8( dct[0], &pix1[0], &pix2[0] ); + sub8x8_dct8( dct[1], &pix1[8], &pix2[8] ); + sub8x8_dct8( dct[2], &pix1[8*FENC_STRIDE+0], &pix2[8*FDEC_STRIDE+0] ); + sub8x8_dct8( dct[3], &pix1[8*FENC_STRIDE+8], &pix2[8*FDEC_STRIDE+8] ); +} + +#define IDCT8_1D {\ + int a0 = SRC(0) + SRC(4);\ + int a2 = SRC(0) - SRC(4);\ + int a4 = (SRC(2)>>1) - SRC(6);\ + int a6 = (SRC(6)>>1) + SRC(2);\ + int b0 = a0 + a6;\ + int b2 = a2 + a4;\ + int b4 = a2 - a4;\ + int b6 = a0 - a6;\ + int a1 = -SRC(3) + SRC(5) - SRC(7) - (SRC(7)>>1);\ + int a3 = SRC(1) + SRC(7) - SRC(3) - (SRC(3)>>1);\ + int a5 = -SRC(1) + SRC(7) + SRC(5) + (SRC(5)>>1);\ + int a7 = SRC(3) + SRC(5) + SRC(1) + (SRC(1)>>1);\ + int b1 = (a7>>2) + a1;\ + int b3 = a3 + (a5>>2);\ + int b5 = (a3>>2) - a5;\ + int b7 = a7 - (a1>>2);\ + DST(0, b0 + b7);\ + DST(1, b2 + b5);\ + DST(2, b4 + b3);\ + DST(3, b6 + b1);\ + DST(4, b6 - b1);\ + DST(5, b4 - b3);\ + DST(6, b2 - b5);\ + DST(7, b0 - b7);\ +} + +static void add8x8_idct8( pixel *dst, dctcoef dct[64] ) +{ + dct[0] += 32; // rounding for the >>6 at the end + +#define SRC(x) dct[x*8+i] +#define DST(x,rhs) dct[x*8+i] = (rhs) + for( int i = 0; i < 8; i++ ) + IDCT8_1D +#undef SRC +#undef DST + +#define SRC(x) dct[i*8+x] +#define DST(x,rhs) dst[i + x*FDEC_STRIDE] = x264_clip_pixel( dst[i + x*FDEC_STRIDE] + ((rhs) >> 6) ); + for( int i = 0; i < 8; i++ ) + IDCT8_1D +#undef SRC +#undef DST +} + +static void add16x16_idct8( pixel *dst, dctcoef dct[4][64] ) +{ + add8x8_idct8( &dst[0], dct[0] ); + add8x8_idct8( &dst[8], dct[1] ); + add8x8_idct8( &dst[8*FDEC_STRIDE+0], dct[2] ); + add8x8_idct8( &dst[8*FDEC_STRIDE+8], dct[3] ); +} + +static void inline add4x4_idct_dc( pixel *p_dst, dctcoef dc ) +{ + dc = (dc + 32) >> 6; + for( int i = 0; i < 4; i++, p_dst += FDEC_STRIDE ) + { + p_dst[0] = x264_clip_pixel( p_dst[0] + dc ); + p_dst[1] = x264_clip_pixel( p_dst[1] + dc ); + p_dst[2] = x264_clip_pixel( p_dst[2] + dc ); + p_dst[3] = x264_clip_pixel( p_dst[3] + dc ); + } +} + +static void add8x8_idct_dc( pixel *p_dst, dctcoef dct[4] ) +{ + add4x4_idct_dc( &p_dst[0], dct[0] ); + add4x4_idct_dc( &p_dst[4], dct[1] ); + add4x4_idct_dc( &p_dst[4*FDEC_STRIDE+0], dct[2] ); + add4x4_idct_dc( &p_dst[4*FDEC_STRIDE+4], dct[3] ); +} + +static void add16x16_idct_dc( pixel *p_dst, dctcoef dct[16] ) +{ + for( int i = 0; i < 4; i++, dct += 4, p_dst += 4*FDEC_STRIDE ) + { + add4x4_idct_dc( &p_dst[ 0], dct[0] ); + add4x4_idct_dc( &p_dst[ 4], dct[1] ); + add4x4_idct_dc( &p_dst[ 8], dct[2] ); + add4x4_idct_dc( &p_dst[12], dct[3] ); + } +} + + +/**************************************************************************** + * x264_dct_init: + ****************************************************************************/ +void x264_dct_init( int cpu, x264_dct_function_t *dctf ) +{ + dctf->sub4x4_dct = sub4x4_dct; + dctf->add4x4_idct = add4x4_idct; + + dctf->sub8x8_dct = sub8x8_dct; + dctf->sub8x8_dct_dc = sub8x8_dct_dc; + dctf->add8x8_idct = add8x8_idct; + dctf->add8x8_idct_dc = add8x8_idct_dc; + + dctf->sub8x16_dct_dc = sub8x16_dct_dc; + + dctf->sub16x16_dct = sub16x16_dct; + dctf->add16x16_idct = add16x16_idct; + dctf->add16x16_idct_dc = add16x16_idct_dc; + + dctf->sub8x8_dct8 = sub8x8_dct8; + dctf->add8x8_idct8 = add8x8_idct8; + + dctf->sub16x16_dct8 = sub16x16_dct8; + dctf->add16x16_idct8 = add16x16_idct8; + + dctf->dct4x4dc = dct4x4dc; + dctf->idct4x4dc = idct4x4dc; + + dctf->dct2x4dc = dct2x4dc; + +#if HIGH_BIT_DEPTH +#if HAVE_MMX + if( cpu&X264_CPU_MMX ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_mmx; + dctf->sub8x8_dct = x264_sub8x8_dct_mmx; + dctf->sub16x16_dct = x264_sub16x16_dct_mmx; + } + if( cpu&X264_CPU_SSE2 ) + { + dctf->add4x4_idct = x264_add4x4_idct_sse2; + dctf->dct4x4dc = x264_dct4x4dc_sse2; + dctf->idct4x4dc = x264_idct4x4dc_sse2; + dctf->dct2x4dc = x264_dct2x4dc_sse2; + dctf->sub8x8_dct8 = x264_sub8x8_dct8_sse2; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_sse2; + dctf->add8x8_idct = x264_add8x8_idct_sse2; + dctf->add16x16_idct = x264_add16x16_idct_sse2; + dctf->add8x8_idct8 = x264_add8x8_idct8_sse2; + dctf->add16x16_idct8 = x264_add16x16_idct8_sse2; + dctf->sub8x8_dct_dc = x264_sub8x8_dct_dc_sse2; + dctf->add8x8_idct_dc = x264_add8x8_idct_dc_sse2; + dctf->sub8x16_dct_dc = x264_sub8x16_dct_dc_sse2; + dctf->add16x16_idct_dc= x264_add16x16_idct_dc_sse2; + } + if( cpu&X264_CPU_SSE4 ) + { + dctf->sub8x8_dct8 = x264_sub8x8_dct8_sse4; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_sse4; + } + if( cpu&X264_CPU_AVX ) + { + dctf->add4x4_idct = x264_add4x4_idct_avx; + dctf->dct4x4dc = x264_dct4x4dc_avx; + dctf->idct4x4dc = x264_idct4x4dc_avx; + dctf->dct2x4dc = x264_dct2x4dc_avx; + dctf->sub8x8_dct8 = x264_sub8x8_dct8_avx; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_avx; + dctf->add8x8_idct = x264_add8x8_idct_avx; + dctf->add16x16_idct = x264_add16x16_idct_avx; + dctf->add8x8_idct8 = x264_add8x8_idct8_avx; + dctf->add16x16_idct8 = x264_add16x16_idct8_avx; + dctf->add8x8_idct_dc = x264_add8x8_idct_dc_avx; + dctf->sub8x16_dct_dc = x264_sub8x16_dct_dc_avx; + dctf->add16x16_idct_dc= x264_add16x16_idct_dc_avx; + } +#endif // HAVE_MMX +#else // !HIGH_BIT_DEPTH +#if HAVE_MMX + if( cpu&X264_CPU_MMX ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_mmx; + dctf->add4x4_idct = x264_add4x4_idct_mmx; + dctf->idct4x4dc = x264_idct4x4dc_mmx; + dctf->sub8x8_dct_dc = x264_sub8x8_dct_dc_mmx2; + +#if !ARCH_X86_64 + dctf->sub8x8_dct = x264_sub8x8_dct_mmx; + dctf->sub16x16_dct = x264_sub16x16_dct_mmx; + dctf->add8x8_idct = x264_add8x8_idct_mmx; + dctf->add16x16_idct = x264_add16x16_idct_mmx; + + dctf->sub8x8_dct8 = x264_sub8x8_dct8_mmx; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_mmx; + dctf->add8x8_idct8 = x264_add8x8_idct8_mmx; + dctf->add16x16_idct8= x264_add16x16_idct8_mmx; +#endif + } + + if( cpu&X264_CPU_MMX2 ) + { + dctf->dct4x4dc = x264_dct4x4dc_mmx2; + dctf->dct2x4dc = x264_dct2x4dc_mmx2; + dctf->add8x8_idct_dc = x264_add8x8_idct_dc_mmx2; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_mmx2; + } + + if( cpu&X264_CPU_SSE2 ) + { + dctf->sub8x8_dct8 = x264_sub8x8_dct8_sse2; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_sse2; + dctf->sub8x8_dct_dc = x264_sub8x8_dct_dc_sse2; + dctf->sub8x16_dct_dc= x264_sub8x16_dct_dc_sse2; + dctf->add8x8_idct8 = x264_add8x8_idct8_sse2; + dctf->add16x16_idct8= x264_add16x16_idct8_sse2; + + if( !(cpu&X264_CPU_SSE2_IS_SLOW) ) + { + dctf->sub8x8_dct = x264_sub8x8_dct_sse2; + dctf->sub16x16_dct = x264_sub16x16_dct_sse2; + dctf->add8x8_idct = x264_add8x8_idct_sse2; + dctf->add16x16_idct = x264_add16x16_idct_sse2; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_sse2; + } + } + + if( (cpu&X264_CPU_SSSE3) && !(cpu&X264_CPU_SSE2_IS_SLOW) ) + { + dctf->sub8x16_dct_dc = x264_sub8x16_dct_dc_ssse3; + if( !(cpu&X264_CPU_SLOW_ATOM) ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_ssse3; + dctf->sub8x8_dct = x264_sub8x8_dct_ssse3; + dctf->sub16x16_dct = x264_sub16x16_dct_ssse3; + dctf->sub8x8_dct8 = x264_sub8x8_dct8_ssse3; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_ssse3; + if( !(cpu&X264_CPU_SLOW_PSHUFB) ) + { + dctf->add8x8_idct_dc = x264_add8x8_idct_dc_ssse3; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_ssse3; + } + } + } + + if( cpu&X264_CPU_SSE4 ) + dctf->add4x4_idct = x264_add4x4_idct_sse4; + + if( cpu&X264_CPU_AVX ) + { + dctf->add4x4_idct = x264_add4x4_idct_avx; + dctf->add8x8_idct = x264_add8x8_idct_avx; + dctf->add16x16_idct = x264_add16x16_idct_avx; + dctf->add8x8_idct8 = x264_add8x8_idct8_avx; + dctf->add16x16_idct8 = x264_add16x16_idct8_avx; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_avx; + dctf->sub8x8_dct = x264_sub8x8_dct_avx; + dctf->sub16x16_dct = x264_sub16x16_dct_avx; + dctf->sub8x8_dct8 = x264_sub8x8_dct8_avx; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_avx; + } + + if( cpu&X264_CPU_XOP ) + { + dctf->sub8x8_dct = x264_sub8x8_dct_xop; + dctf->sub16x16_dct = x264_sub16x16_dct_xop; + } + + if( cpu&X264_CPU_AVX2 ) + { + dctf->add8x8_idct = x264_add8x8_idct_avx2; + dctf->add16x16_idct = x264_add16x16_idct_avx2; + dctf->sub8x8_dct = x264_sub8x8_dct_avx2; + dctf->sub16x16_dct = x264_sub16x16_dct_avx2; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_avx2; +#if ARCH_X86_64 + dctf->sub16x16_dct8 = x264_sub16x16_dct8_avx2; +#endif + } + + if( cpu&X264_CPU_AVX512 ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_avx512; + dctf->sub8x8_dct = x264_sub8x8_dct_avx512; + dctf->sub16x16_dct = x264_sub16x16_dct_avx512; + dctf->sub8x8_dct_dc = x264_sub8x8_dct_dc_avx512; + dctf->sub8x16_dct_dc = x264_sub8x16_dct_dc_avx512; + dctf->add8x8_idct = x264_add8x8_idct_avx512; + } +#endif //HAVE_MMX + +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_altivec; + dctf->sub8x8_dct = x264_sub8x8_dct_altivec; + dctf->sub16x16_dct = x264_sub16x16_dct_altivec; + + dctf->add8x8_idct_dc = x264_add8x8_idct_dc_altivec; + + dctf->add4x4_idct = x264_add4x4_idct_altivec; + dctf->add8x8_idct = x264_add8x8_idct_altivec; + dctf->add16x16_idct = x264_add16x16_idct_altivec; + + dctf->sub8x8_dct_dc = x264_sub8x8_dct_dc_altivec; + dctf->sub8x8_dct8 = x264_sub8x8_dct8_altivec; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_altivec; + + dctf->add8x8_idct8 = x264_add8x8_idct8_altivec; + dctf->add16x16_idct8= x264_add16x16_idct8_altivec; + } +#endif + +#if HAVE_ARMV6 || ARCH_AARCH64 + if( cpu&X264_CPU_NEON ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_neon; + dctf->sub8x8_dct = x264_sub8x8_dct_neon; + dctf->sub16x16_dct = x264_sub16x16_dct_neon; + dctf->add8x8_idct_dc = x264_add8x8_idct_dc_neon; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_neon; + dctf->sub8x8_dct_dc = x264_sub8x8_dct_dc_neon; + dctf->dct4x4dc = x264_dct4x4dc_neon; + dctf->idct4x4dc = x264_idct4x4dc_neon; + + dctf->add4x4_idct = x264_add4x4_idct_neon; + dctf->add8x8_idct = x264_add8x8_idct_neon; + dctf->add16x16_idct = x264_add16x16_idct_neon; + + dctf->sub8x8_dct8 = x264_sub8x8_dct8_neon; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_neon; + + dctf->add8x8_idct8 = x264_add8x8_idct8_neon; + dctf->add16x16_idct8= x264_add16x16_idct8_neon; + dctf->sub8x16_dct_dc= x264_sub8x16_dct_dc_neon; + } +#endif + +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_msa; + dctf->sub8x8_dct = x264_sub8x8_dct_msa; + dctf->sub16x16_dct = x264_sub16x16_dct_msa; + dctf->sub8x8_dct_dc = x264_sub8x8_dct_dc_msa; + dctf->sub8x16_dct_dc = x264_sub8x16_dct_dc_msa; + dctf->dct4x4dc = x264_dct4x4dc_msa; + dctf->idct4x4dc = x264_idct4x4dc_msa; + dctf->add4x4_idct = x264_add4x4_idct_msa; + dctf->add8x8_idct = x264_add8x8_idct_msa; + dctf->add8x8_idct_dc = x264_add8x8_idct_dc_msa; + dctf->add16x16_idct = x264_add16x16_idct_msa; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_msa; + dctf->add8x8_idct8 = x264_add8x8_idct8_msa; + dctf->add16x16_idct8 = x264_add16x16_idct8_msa; + } +#endif + +#endif // HIGH_BIT_DEPTH +} + + +#define ZIG(i,y,x) level[i] = dct[x*8+y]; +#define ZIGZAG8_FRAME\ + ZIG( 0,0,0) ZIG( 1,0,1) ZIG( 2,1,0) ZIG( 3,2,0)\ + ZIG( 4,1,1) ZIG( 5,0,2) ZIG( 6,0,3) ZIG( 7,1,2)\ + ZIG( 8,2,1) ZIG( 9,3,0) ZIG(10,4,0) ZIG(11,3,1)\ + ZIG(12,2,2) ZIG(13,1,3) ZIG(14,0,4) ZIG(15,0,5)\ + ZIG(16,1,4) ZIG(17,2,3) ZIG(18,3,2) ZIG(19,4,1)\ + ZIG(20,5,0) ZIG(21,6,0) ZIG(22,5,1) ZIG(23,4,2)\ + ZIG(24,3,3) ZIG(25,2,4) ZIG(26,1,5) ZIG(27,0,6)\ + ZIG(28,0,7) ZIG(29,1,6) ZIG(30,2,5) ZIG(31,3,4)\ + ZIG(32,4,3) ZIG(33,5,2) ZIG(34,6,1) ZIG(35,7,0)\ + ZIG(36,7,1) ZIG(37,6,2) ZIG(38,5,3) ZIG(39,4,4)\ + ZIG(40,3,5) ZIG(41,2,6) ZIG(42,1,7) ZIG(43,2,7)\ + ZIG(44,3,6) ZIG(45,4,5) ZIG(46,5,4) ZIG(47,6,3)\ + ZIG(48,7,2) ZIG(49,7,3) ZIG(50,6,4) ZIG(51,5,5)\ + ZIG(52,4,6) ZIG(53,3,7) ZIG(54,4,7) ZIG(55,5,6)\ + ZIG(56,6,5) ZIG(57,7,4) ZIG(58,7,5) ZIG(59,6,6)\ + ZIG(60,5,7) ZIG(61,6,7) ZIG(62,7,6) ZIG(63,7,7)\ + +#define ZIGZAG8_FIELD\ + ZIG( 0,0,0) ZIG( 1,1,0) ZIG( 2,2,0) ZIG( 3,0,1)\ + ZIG( 4,1,1) ZIG( 5,3,0) ZIG( 6,4,0) ZIG( 7,2,1)\ + ZIG( 8,0,2) ZIG( 9,3,1) ZIG(10,5,0) ZIG(11,6,0)\ + ZIG(12,7,0) ZIG(13,4,1) ZIG(14,1,2) ZIG(15,0,3)\ + ZIG(16,2,2) ZIG(17,5,1) ZIG(18,6,1) ZIG(19,7,1)\ + ZIG(20,3,2) ZIG(21,1,3) ZIG(22,0,4) ZIG(23,2,3)\ + ZIG(24,4,2) ZIG(25,5,2) ZIG(26,6,2) ZIG(27,7,2)\ + ZIG(28,3,3) ZIG(29,1,4) ZIG(30,0,5) ZIG(31,2,4)\ + ZIG(32,4,3) ZIG(33,5,3) ZIG(34,6,3) ZIG(35,7,3)\ + ZIG(36,3,4) ZIG(37,1,5) ZIG(38,0,6) ZIG(39,2,5)\ + ZIG(40,4,4) ZIG(41,5,4) ZIG(42,6,4) ZIG(43,7,4)\ + ZIG(44,3,5) ZIG(45,1,6) ZIG(46,2,6) ZIG(47,4,5)\ + ZIG(48,5,5) ZIG(49,6,5) ZIG(50,7,5) ZIG(51,3,6)\ + ZIG(52,0,7) ZIG(53,1,7) ZIG(54,4,6) ZIG(55,5,6)\ + ZIG(56,6,6) ZIG(57,7,6) ZIG(58,2,7) ZIG(59,3,7)\ + ZIG(60,4,7) ZIG(61,5,7) ZIG(62,6,7) ZIG(63,7,7) + +#define ZIGZAG4_FRAME\ + ZIGDC( 0,0,0) ZIG( 1,0,1) ZIG( 2,1,0) ZIG( 3,2,0)\ + ZIG( 4,1,1) ZIG( 5,0,2) ZIG( 6,0,3) ZIG( 7,1,2)\ + ZIG( 8,2,1) ZIG( 9,3,0) ZIG(10,3,1) ZIG(11,2,2)\ + ZIG(12,1,3) ZIG(13,2,3) ZIG(14,3,2) ZIG(15,3,3) + +#define ZIGZAG4_FIELD\ + ZIGDC( 0,0,0) ZIG( 1,1,0) ZIG( 2,0,1) ZIG( 3,2,0)\ + ZIG( 4,3,0) ZIG( 5,1,1) ZIG( 6,2,1) ZIG( 7,3,1)\ + ZIG( 8,0,2) ZIG( 9,1,2) ZIG(10,2,2) ZIG(11,3,2)\ + ZIG(12,0,3) ZIG(13,1,3) ZIG(14,2,3) ZIG(15,3,3) + +static void zigzag_scan_8x8_frame( dctcoef level[64], dctcoef dct[64] ) +{ + ZIGZAG8_FRAME +} + +static void zigzag_scan_8x8_field( dctcoef level[64], dctcoef dct[64] ) +{ + ZIGZAG8_FIELD +} + +#undef ZIG +#define ZIG(i,y,x) level[i] = dct[x*4+y]; +#define ZIGDC(i,y,x) ZIG(i,y,x) + +static void zigzag_scan_4x4_frame( dctcoef level[16], dctcoef dct[16] ) +{ + ZIGZAG4_FRAME +} + +static void zigzag_scan_4x4_field( dctcoef level[16], dctcoef dct[16] ) +{ + memcpy( level, dct, 2 * sizeof(dctcoef) ); + ZIG(2,0,1) ZIG(3,2,0) ZIG(4,3,0) ZIG(5,1,1) + memcpy( level+6, dct+6, 10 * sizeof(dctcoef) ); +} + +#undef ZIG +#define ZIG(i,y,x) {\ + int oe = x+y*FENC_STRIDE;\ + int od = x+y*FDEC_STRIDE;\ + level[i] = p_src[oe] - p_dst[od];\ + nz |= level[i];\ +} +#define COPY4x4\ + CPPIXEL_X4( p_dst+0*FDEC_STRIDE, p_src+0*FENC_STRIDE );\ + CPPIXEL_X4( p_dst+1*FDEC_STRIDE, p_src+1*FENC_STRIDE );\ + CPPIXEL_X4( p_dst+2*FDEC_STRIDE, p_src+2*FENC_STRIDE );\ + CPPIXEL_X4( p_dst+3*FDEC_STRIDE, p_src+3*FENC_STRIDE ); +#define CPPIXEL_X8(dst,src) ( CPPIXEL_X4(dst,src), CPPIXEL_X4(dst+4,src+4) ) +#define COPY8x8\ + CPPIXEL_X8( p_dst+0*FDEC_STRIDE, p_src+0*FENC_STRIDE );\ + CPPIXEL_X8( p_dst+1*FDEC_STRIDE, p_src+1*FENC_STRIDE );\ + CPPIXEL_X8( p_dst+2*FDEC_STRIDE, p_src+2*FENC_STRIDE );\ + CPPIXEL_X8( p_dst+3*FDEC_STRIDE, p_src+3*FENC_STRIDE );\ + CPPIXEL_X8( p_dst+4*FDEC_STRIDE, p_src+4*FENC_STRIDE );\ + CPPIXEL_X8( p_dst+5*FDEC_STRIDE, p_src+5*FENC_STRIDE );\ + CPPIXEL_X8( p_dst+6*FDEC_STRIDE, p_src+6*FENC_STRIDE );\ + CPPIXEL_X8( p_dst+7*FDEC_STRIDE, p_src+7*FENC_STRIDE ); + +static int zigzag_sub_4x4_frame( dctcoef level[16], const pixel *p_src, pixel *p_dst ) +{ + int nz = 0; + ZIGZAG4_FRAME + COPY4x4 + return !!nz; +} + +static int zigzag_sub_4x4_field( dctcoef level[16], const pixel *p_src, pixel *p_dst ) +{ + int nz = 0; + ZIGZAG4_FIELD + COPY4x4 + return !!nz; +} + +#undef ZIGDC +#define ZIGDC(i,y,x) {\ + int oe = x+y*FENC_STRIDE;\ + int od = x+y*FDEC_STRIDE;\ + *dc = p_src[oe] - p_dst[od];\ + level[0] = 0;\ +} + +static int zigzag_sub_4x4ac_frame( dctcoef level[16], const pixel *p_src, pixel *p_dst, dctcoef *dc ) +{ + int nz = 0; + ZIGZAG4_FRAME + COPY4x4 + return !!nz; +} + +static int zigzag_sub_4x4ac_field( dctcoef level[16], const pixel *p_src, pixel *p_dst, dctcoef *dc ) +{ + int nz = 0; + ZIGZAG4_FIELD + COPY4x4 + return !!nz; +} + +static int zigzag_sub_8x8_frame( dctcoef level[64], const pixel *p_src, pixel *p_dst ) +{ + int nz = 0; + ZIGZAG8_FRAME + COPY8x8 + return !!nz; +} +static int zigzag_sub_8x8_field( dctcoef level[64], const pixel *p_src, pixel *p_dst ) +{ + int nz = 0; + ZIGZAG8_FIELD + COPY8x8 + return !!nz; +} + +#undef ZIG +#undef COPY4x4 + +static void zigzag_interleave_8x8_cavlc( dctcoef *dst, dctcoef *src, uint8_t *nnz ) +{ + for( int i = 0; i < 4; i++ ) + { + int nz = 0; + for( int j = 0; j < 16; j++ ) + { + nz |= src[i+j*4]; + dst[i*16+j] = src[i+j*4]; + } + nnz[(i&1) + (i>>1)*8] = !!nz; + } +} + +void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zigzag_function_t *pf_interlaced ) +{ + pf_interlaced->scan_8x8 = zigzag_scan_8x8_field; + pf_progressive->scan_8x8 = zigzag_scan_8x8_frame; + pf_interlaced->scan_4x4 = zigzag_scan_4x4_field; + pf_progressive->scan_4x4 = zigzag_scan_4x4_frame; + pf_interlaced->sub_8x8 = zigzag_sub_8x8_field; + pf_progressive->sub_8x8 = zigzag_sub_8x8_frame; + pf_interlaced->sub_4x4 = zigzag_sub_4x4_field; + pf_progressive->sub_4x4 = zigzag_sub_4x4_frame; + pf_interlaced->sub_4x4ac = zigzag_sub_4x4ac_field; + pf_progressive->sub_4x4ac = zigzag_sub_4x4ac_frame; + +#if HIGH_BIT_DEPTH +#if HAVE_MMX + if( cpu&X264_CPU_SSE2 ) + { + pf_interlaced->scan_4x4 = x264_zigzag_scan_4x4_field_sse2; + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_sse2; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_sse2; + } + if( cpu&X264_CPU_SSE4 ) + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_sse4; + if( cpu&X264_CPU_AVX ) + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_avx; +#if ARCH_X86_64 + if( cpu&X264_CPU_AVX ) + { + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_avx; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_avx; + } +#endif // ARCH_X86_64 + if( cpu&X264_CPU_AVX512 ) + { + pf_interlaced->scan_4x4 = x264_zigzag_scan_4x4_field_avx512; + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_avx512; + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_avx512; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_avx512; + } +#endif // HAVE_MMX +#else +#if HAVE_MMX + if( cpu&X264_CPU_MMX ) + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_mmx; + if( cpu&X264_CPU_MMX2 ) + { + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_mmx2; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_mmx2; + } + if( cpu&X264_CPU_SSE ) + pf_interlaced->scan_4x4 = x264_zigzag_scan_4x4_field_sse; + if( cpu&X264_CPU_SSE2_IS_FAST ) + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_sse2; + if( cpu&X264_CPU_SSSE3 ) + { + pf_interlaced->sub_4x4 = x264_zigzag_sub_4x4_field_ssse3; + pf_progressive->sub_4x4 = x264_zigzag_sub_4x4_frame_ssse3; + pf_interlaced->sub_4x4ac = x264_zigzag_sub_4x4ac_field_ssse3; + pf_progressive->sub_4x4ac= x264_zigzag_sub_4x4ac_frame_ssse3; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_ssse3; + if( !(cpu&X264_CPU_SLOW_SHUFFLE) ) + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_ssse3; + } + if( cpu&X264_CPU_AVX ) + { + pf_interlaced->sub_4x4 = x264_zigzag_sub_4x4_field_avx; + pf_progressive->sub_4x4 = x264_zigzag_sub_4x4_frame_avx; +#if ARCH_X86_64 + pf_interlaced->sub_4x4ac = x264_zigzag_sub_4x4ac_field_avx; + pf_progressive->sub_4x4ac= x264_zigzag_sub_4x4ac_frame_avx; +#endif + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_avx; + } + if( cpu&X264_CPU_XOP ) + { + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_xop; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_xop; + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_xop; + } + if( cpu&X264_CPU_AVX512 ) + { + pf_interlaced->scan_4x4 = x264_zigzag_scan_4x4_field_avx512; + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_avx512; + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_avx512; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_avx512; + } +#endif // HAVE_MMX +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + { + pf_interlaced->scan_4x4 = x264_zigzag_scan_4x4_field_altivec; + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_altivec; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_altivec; + } +#endif +#if HAVE_ARMV6 || ARCH_AARCH64 + if( cpu&X264_CPU_NEON ) + { + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_neon; +#if ARCH_AARCH64 + pf_interlaced->scan_4x4 = x264_zigzag_scan_4x4_field_neon; + pf_interlaced->scan_8x8 = x264_zigzag_scan_8x8_field_neon; + pf_interlaced->sub_4x4 = x264_zigzag_sub_4x4_field_neon; + pf_interlaced->sub_4x4ac = x264_zigzag_sub_4x4ac_field_neon; + pf_interlaced->sub_8x8 = x264_zigzag_sub_8x8_field_neon; + pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_neon; + pf_progressive->sub_4x4 = x264_zigzag_sub_4x4_frame_neon; + pf_progressive->sub_4x4ac = x264_zigzag_sub_4x4ac_frame_neon; + pf_progressive->sub_8x8 = x264_zigzag_sub_8x8_frame_neon; +#endif // ARCH_AARCH64 + } +#endif // HAVE_ARMV6 || ARCH_AARCH64 +#endif // HIGH_BIT_DEPTH + + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = zigzag_interleave_8x8_cavlc; +#if HAVE_MMX +#if HIGH_BIT_DEPTH + if( cpu&X264_CPU_SSE2 ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_sse2; + } + if( cpu&X264_CPU_AVX ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx; + } + if( cpu&X264_CPU_AVX512 ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx512; + } +#else + if( cpu&X264_CPU_MMX ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_mmx; + } + if( (cpu&X264_CPU_SSE2) && !(cpu&(X264_CPU_SLOW_SHUFFLE|X264_CPU_SSE2_IS_SLOW)) ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_sse2; + } + + if( cpu&X264_CPU_AVX ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx; + } + + if( cpu&X264_CPU_AVX2 ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx2; + } + if( cpu&X264_CPU_AVX512 ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_avx512; + } +#endif // HIGH_BIT_DEPTH +#endif +#if !HIGH_BIT_DEPTH +#if ARCH_AARCH64 + if( cpu&X264_CPU_NEON ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_neon; + } +#endif // ARCH_AARCH64 + +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + { + pf_interlaced->interleave_8x8_cavlc = + pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_altivec; + } +#endif // HAVE_ALTIVEC + +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + { + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_msa; + } +#endif +#endif // !HIGH_BIT_DEPTH +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/dct.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/dct.h new file mode 100644 index 00000000..d443e228 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/dct.h @@ -0,0 +1,80 @@ +/***************************************************************************** + * dct.h: transform and zigzag + ***************************************************************************** + * Copyright (C) 2004-2017 x264 project + * + * Authors: Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_DCT_H +#define X264_DCT_H + +extern const uint32_t x264_dct4_weight_tab[16]; +extern const uint32_t x264_dct8_weight_tab[64]; +extern const uint32_t x264_dct4_weight2_tab[16]; +extern const uint32_t x264_dct8_weight2_tab[64]; + +typedef struct +{ + // pix1 stride = FENC_STRIDE + // pix2 stride = FDEC_STRIDE + // p_dst stride = FDEC_STRIDE + void (*sub4x4_dct) ( dctcoef dct[16], pixel *pix1, pixel *pix2 ); + void (*add4x4_idct)( pixel *p_dst, dctcoef dct[16] ); + + void (*sub8x8_dct) ( dctcoef dct[4][16], pixel *pix1, pixel *pix2 ); + void (*sub8x8_dct_dc) ( dctcoef dct[4], pixel *pix1, pixel *pix2 ); + void (*add8x8_idct) ( pixel *p_dst, dctcoef dct[4][16] ); + void (*add8x8_idct_dc)( pixel *p_dst, dctcoef dct[4] ); + + void (*sub8x16_dct_dc)( dctcoef dct[8], pixel *pix1, pixel *pix2 ); + + void (*sub16x16_dct) ( dctcoef dct[16][16], pixel *pix1, pixel *pix2 ); + void (*add16x16_idct) ( pixel *p_dst, dctcoef dct[16][16] ); + void (*add16x16_idct_dc)( pixel *p_dst, dctcoef dct[16] ); + + void (*sub8x8_dct8) ( dctcoef dct[64], pixel *pix1, pixel *pix2 ); + void (*add8x8_idct8)( pixel *p_dst, dctcoef dct[64] ); + + void (*sub16x16_dct8) ( dctcoef dct[4][64], pixel *pix1, pixel *pix2 ); + void (*add16x16_idct8)( pixel *p_dst, dctcoef dct[4][64] ); + + void (*dct4x4dc) ( dctcoef d[16] ); + void (*idct4x4dc)( dctcoef d[16] ); + + void (*dct2x4dc)( dctcoef dct[8], dctcoef dct4x4[8][16] ); + +} x264_dct_function_t; + +typedef struct +{ + void (*scan_8x8)( dctcoef level[64], dctcoef dct[64] ); + void (*scan_4x4)( dctcoef level[16], dctcoef dct[16] ); + int (*sub_8x8) ( dctcoef level[64], const pixel *p_src, pixel *p_dst ); + int (*sub_4x4) ( dctcoef level[16], const pixel *p_src, pixel *p_dst ); + int (*sub_4x4ac)( dctcoef level[16], const pixel *p_src, pixel *p_dst, dctcoef *dc ); + void (*interleave_8x8_cavlc)( dctcoef *dst, dctcoef *src, uint8_t *nnz ); + +} x264_zigzag_function_t; + +void x264_dct_init( int cpu, x264_dct_function_t *dctf ); +void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zigzag_function_t *pf_interlaced ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/deblock.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/deblock.c new file mode 100644 index 00000000..0c7f128c --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/deblock.c @@ -0,0 +1,908 @@ +/***************************************************************************** + * deblock.c: deblocking + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +/* Deblocking filter */ +static const uint8_t i_alpha_table[52+12*3] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 4, 5, 6, + 7, 8, 9, 10, 12, 13, 15, 17, 20, 22, + 25, 28, 32, 36, 40, 45, 50, 56, 63, 71, + 80, 90,101,113,127,144,162,182,203,226, + 255,255, + 255,255,255,255,255,255,255,255,255,255,255,255, +}; +static const uint8_t i_beta_table[52+12*3] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 3, + 3, 3, 3, 4, 4, 4, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, + 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, + 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, +}; +static const int8_t i_tc0_table[52+12*3][4] = +{ + {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, + {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, + {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, + {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, + {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, + {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, + {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 1 }, + {-1, 0, 0, 1 }, {-1, 0, 0, 1 }, {-1, 0, 0, 1 }, {-1, 0, 1, 1 }, {-1, 0, 1, 1 }, {-1, 1, 1, 1 }, + {-1, 1, 1, 1 }, {-1, 1, 1, 1 }, {-1, 1, 1, 1 }, {-1, 1, 1, 2 }, {-1, 1, 1, 2 }, {-1, 1, 1, 2 }, + {-1, 1, 1, 2 }, {-1, 1, 2, 3 }, {-1, 1, 2, 3 }, {-1, 2, 2, 3 }, {-1, 2, 2, 4 }, {-1, 2, 3, 4 }, + {-1, 2, 3, 4 }, {-1, 3, 3, 5 }, {-1, 3, 4, 6 }, {-1, 3, 4, 6 }, {-1, 4, 5, 7 }, {-1, 4, 5, 8 }, + {-1, 4, 6, 9 }, {-1, 5, 7,10 }, {-1, 6, 8,11 }, {-1, 6, 8,13 }, {-1, 7,10,14 }, {-1, 8,11,16 }, + {-1, 9,12,18 }, {-1,10,13,20 }, {-1,11,15,23 }, {-1,13,17,25 }, + {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, + {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, +}; +#define alpha_table(x) i_alpha_table[(x)+24] +#define beta_table(x) i_beta_table[(x)+24] +#define tc0_table(x) i_tc0_table[(x)+24] + +/* From ffmpeg */ +static ALWAYS_INLINE void deblock_edge_luma_c( pixel *pix, intptr_t xstride, int alpha, int beta, int8_t tc0 ) +{ + int p2 = pix[-3*xstride]; + int p1 = pix[-2*xstride]; + int p0 = pix[-1*xstride]; + int q0 = pix[ 0*xstride]; + int q1 = pix[ 1*xstride]; + int q2 = pix[ 2*xstride]; + + if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta ) + { + int tc = tc0; + int delta; + if( abs( p2 - p0 ) < beta ) + { + if( tc0 ) + pix[-2*xstride] = p1 + x264_clip3( (( p2 + ((p0 + q0 + 1) >> 1)) >> 1) - p1, -tc0, tc0 ); + tc++; + } + if( abs( q2 - q0 ) < beta ) + { + if( tc0 ) + pix[ 1*xstride] = q1 + x264_clip3( (( q2 + ((p0 + q0 + 1) >> 1)) >> 1) - q1, -tc0, tc0 ); + tc++; + } + + delta = x264_clip3( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3, -tc, tc ); + pix[-1*xstride] = x264_clip_pixel( p0 + delta ); /* p0' */ + pix[ 0*xstride] = x264_clip_pixel( q0 - delta ); /* q0' */ + } +} +static inline void deblock_luma_c( pixel *pix, intptr_t xstride, intptr_t ystride, int alpha, int beta, int8_t *tc0 ) +{ + for( int i = 0; i < 4; i++ ) + { + if( tc0[i] < 0 ) + { + pix += 4*ystride; + continue; + } + for( int d = 0; d < 4; d++, pix += ystride ) + deblock_edge_luma_c( pix, xstride, alpha, beta, tc0[i] ); + } +} +static void deblock_h_luma_mbaff_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) +{ + for( int d = 0; d < 8; d++, pix += stride ) + deblock_edge_luma_c( pix, 1, alpha, beta, tc0[d>>1] ); +} +static void deblock_v_luma_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) +{ + deblock_luma_c( pix, stride, 1, alpha, beta, tc0 ); +} +static void deblock_h_luma_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) +{ + deblock_luma_c( pix, 1, stride, alpha, beta, tc0 ); +} + +static ALWAYS_INLINE void deblock_edge_chroma_c( pixel *pix, intptr_t xstride, int alpha, int beta, int8_t tc ) +{ + int p1 = pix[-2*xstride]; + int p0 = pix[-1*xstride]; + int q0 = pix[ 0*xstride]; + int q1 = pix[ 1*xstride]; + + if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta ) + { + int delta = x264_clip3( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3, -tc, tc ); + pix[-1*xstride] = x264_clip_pixel( p0 + delta ); /* p0' */ + pix[ 0*xstride] = x264_clip_pixel( q0 - delta ); /* q0' */ + } +} +static ALWAYS_INLINE void deblock_chroma_c( pixel *pix, int height, intptr_t xstride, intptr_t ystride, int alpha, int beta, int8_t *tc0 ) +{ + for( int i = 0; i < 4; i++ ) + { + int tc = tc0[i]; + if( tc <= 0 ) + { + pix += height*ystride; + continue; + } + for( int d = 0; d < height; d++, pix += ystride-2 ) + for( int e = 0; e < 2; e++, pix++ ) + deblock_edge_chroma_c( pix, xstride, alpha, beta, tc0[i] ); + } +} +static void deblock_h_chroma_mbaff_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) +{ + deblock_chroma_c( pix, 1, 2, stride, alpha, beta, tc0 ); +} +static void deblock_v_chroma_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) +{ + deblock_chroma_c( pix, 2, stride, 2, alpha, beta, tc0 ); +} +static void deblock_h_chroma_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) +{ + deblock_chroma_c( pix, 2, 2, stride, alpha, beta, tc0 ); +} +static void deblock_h_chroma_422_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) +{ + deblock_chroma_c( pix, 4, 2, stride, alpha, beta, tc0 ); +} + +static ALWAYS_INLINE void deblock_edge_luma_intra_c( pixel *pix, intptr_t xstride, int alpha, int beta ) +{ + int p2 = pix[-3*xstride]; + int p1 = pix[-2*xstride]; + int p0 = pix[-1*xstride]; + int q0 = pix[ 0*xstride]; + int q1 = pix[ 1*xstride]; + int q2 = pix[ 2*xstride]; + + if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta ) + { + if( abs( p0 - q0 ) < ((alpha >> 2) + 2) ) + { + if( abs( p2 - p0 ) < beta ) /* p0', p1', p2' */ + { + const int p3 = pix[-4*xstride]; + pix[-1*xstride] = ( p2 + 2*p1 + 2*p0 + 2*q0 + q1 + 4 ) >> 3; + pix[-2*xstride] = ( p2 + p1 + p0 + q0 + 2 ) >> 2; + pix[-3*xstride] = ( 2*p3 + 3*p2 + p1 + p0 + q0 + 4 ) >> 3; + } + else /* p0' */ + pix[-1*xstride] = ( 2*p1 + p0 + q1 + 2 ) >> 2; + if( abs( q2 - q0 ) < beta ) /* q0', q1', q2' */ + { + const int q3 = pix[3*xstride]; + pix[0*xstride] = ( p1 + 2*p0 + 2*q0 + 2*q1 + q2 + 4 ) >> 3; + pix[1*xstride] = ( p0 + q0 + q1 + q2 + 2 ) >> 2; + pix[2*xstride] = ( 2*q3 + 3*q2 + q1 + q0 + p0 + 4 ) >> 3; + } + else /* q0' */ + pix[0*xstride] = ( 2*q1 + q0 + p1 + 2 ) >> 2; + } + else /* p0', q0' */ + { + pix[-1*xstride] = ( 2*p1 + p0 + q1 + 2 ) >> 2; + pix[ 0*xstride] = ( 2*q1 + q0 + p1 + 2 ) >> 2; + } + } +} +static inline void deblock_luma_intra_c( pixel *pix, intptr_t xstride, intptr_t ystride, int alpha, int beta ) +{ + for( int d = 0; d < 16; d++, pix += ystride ) + deblock_edge_luma_intra_c( pix, xstride, alpha, beta ); +} +static void deblock_h_luma_intra_mbaff_c( pixel *pix, intptr_t ystride, int alpha, int beta ) +{ + for( int d = 0; d < 8; d++, pix += ystride ) + deblock_edge_luma_intra_c( pix, 1, alpha, beta ); +} +static void deblock_v_luma_intra_c( pixel *pix, intptr_t stride, int alpha, int beta ) +{ + deblock_luma_intra_c( pix, stride, 1, alpha, beta ); +} +static void deblock_h_luma_intra_c( pixel *pix, intptr_t stride, int alpha, int beta ) +{ + deblock_luma_intra_c( pix, 1, stride, alpha, beta ); +} + +static ALWAYS_INLINE void deblock_edge_chroma_intra_c( pixel *pix, intptr_t xstride, int alpha, int beta ) +{ + int p1 = pix[-2*xstride]; + int p0 = pix[-1*xstride]; + int q0 = pix[ 0*xstride]; + int q1 = pix[ 1*xstride]; + + if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta ) + { + pix[-1*xstride] = (2*p1 + p0 + q1 + 2) >> 2; /* p0' */ + pix[ 0*xstride] = (2*q1 + q0 + p1 + 2) >> 2; /* q0' */ + } +} +static ALWAYS_INLINE void deblock_chroma_intra_c( pixel *pix, int width, int height, intptr_t xstride, intptr_t ystride, int alpha, int beta ) +{ + for( int d = 0; d < height; d++, pix += ystride-2 ) + for( int e = 0; e < width; e++, pix++ ) + deblock_edge_chroma_intra_c( pix, xstride, alpha, beta ); +} +static void deblock_h_chroma_intra_mbaff_c( pixel *pix, intptr_t stride, int alpha, int beta ) +{ + deblock_chroma_intra_c( pix, 2, 4, 2, stride, alpha, beta ); +} +static void deblock_v_chroma_intra_c( pixel *pix, intptr_t stride, int alpha, int beta ) +{ + deblock_chroma_intra_c( pix, 1, 16, stride, 2, alpha, beta ); +} +static void deblock_h_chroma_intra_c( pixel *pix, intptr_t stride, int alpha, int beta ) +{ + deblock_chroma_intra_c( pix, 2, 8, 2, stride, alpha, beta ); +} +static void deblock_h_chroma_422_intra_c( pixel *pix, intptr_t stride, int alpha, int beta ) +{ + deblock_chroma_intra_c( pix, 2, 16, 2, stride, alpha, beta ); +} + +static void deblock_strength_c( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], int mvy_limit, + int bframe ) +{ + for( int dir = 0; dir < 2; dir++ ) + { + int s1 = dir ? 1 : 8; + int s2 = dir ? 8 : 1; + for( int edge = 0; edge < 4; edge++ ) + for( int i = 0, loc = X264_SCAN8_0+edge*s2; i < 4; i++, loc += s1 ) + { + int locn = loc - s2; + if( nnz[loc] || nnz[locn] ) + bs[dir][edge][i] = 2; + else if( ref[0][loc] != ref[0][locn] || + abs( mv[0][loc][0] - mv[0][locn][0] ) >= 4 || + abs( mv[0][loc][1] - mv[0][locn][1] ) >= mvy_limit || + (bframe && (ref[1][loc] != ref[1][locn] || + abs( mv[1][loc][0] - mv[1][locn][0] ) >= 4 || + abs( mv[1][loc][1] - mv[1][locn][1] ) >= mvy_limit ))) + { + bs[dir][edge][i] = 1; + } + else + bs[dir][edge][i] = 0; + } + } +} + +static ALWAYS_INLINE void deblock_edge( x264_t *h, pixel *pix, intptr_t i_stride, uint8_t bS[4], int i_qp, + int a, int b, int b_chroma, x264_deblock_inter_t pf_inter ) +{ + int index_a = i_qp + a; + int index_b = i_qp + b; + int alpha = alpha_table(index_a) << (BIT_DEPTH-8); + int beta = beta_table(index_b) << (BIT_DEPTH-8); + int8_t tc[4]; + + if( !M32(bS) || !alpha || !beta ) + return; + + tc[0] = (tc0_table(index_a)[bS[0]] << (BIT_DEPTH-8)) + b_chroma; + tc[1] = (tc0_table(index_a)[bS[1]] << (BIT_DEPTH-8)) + b_chroma; + tc[2] = (tc0_table(index_a)[bS[2]] << (BIT_DEPTH-8)) + b_chroma; + tc[3] = (tc0_table(index_a)[bS[3]] << (BIT_DEPTH-8)) + b_chroma; + + pf_inter( pix, i_stride, alpha, beta, tc ); +} + +static ALWAYS_INLINE void deblock_edge_intra( x264_t *h, pixel *pix, intptr_t i_stride, uint8_t bS[4], int i_qp, + int a, int b, int b_chroma, x264_deblock_intra_t pf_intra ) +{ + int index_a = i_qp + a; + int index_b = i_qp + b; + int alpha = alpha_table(index_a) << (BIT_DEPTH-8); + int beta = beta_table(index_b) << (BIT_DEPTH-8); + + if( !alpha || !beta ) + return; + + pf_intra( pix, i_stride, alpha, beta ); +} + +static ALWAYS_INLINE void x264_macroblock_cache_load_neighbours_deblock( x264_t *h, int mb_x, int mb_y ) +{ + int deblock_on_slice_edges = h->sh.i_disable_deblocking_filter_idc != 2; + + h->mb.i_neighbour = 0; + h->mb.i_mb_xy = mb_y * h->mb.i_mb_stride + mb_x; + h->mb.b_interlaced = PARAM_INTERLACED && h->mb.field[h->mb.i_mb_xy]; + h->mb.i_mb_top_y = mb_y - (1 << MB_INTERLACED); + h->mb.i_mb_top_xy = mb_x + h->mb.i_mb_stride*h->mb.i_mb_top_y; + h->mb.i_mb_left_xy[1] = + h->mb.i_mb_left_xy[0] = h->mb.i_mb_xy - 1; + if( SLICE_MBAFF ) + { + if( mb_y&1 ) + { + if( mb_x && h->mb.field[h->mb.i_mb_xy - 1] != MB_INTERLACED ) + h->mb.i_mb_left_xy[0] -= h->mb.i_mb_stride; + } + else + { + if( h->mb.i_mb_top_xy >= 0 && MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy] ) + { + h->mb.i_mb_top_xy += h->mb.i_mb_stride; + h->mb.i_mb_top_y++; + } + if( mb_x && h->mb.field[h->mb.i_mb_xy - 1] != MB_INTERLACED ) + h->mb.i_mb_left_xy[1] += h->mb.i_mb_stride; + } + } + + if( mb_x > 0 && (deblock_on_slice_edges || + h->mb.slice_table[h->mb.i_mb_left_xy[0]] == h->mb.slice_table[h->mb.i_mb_xy]) ) + h->mb.i_neighbour |= MB_LEFT; + if( mb_y > MB_INTERLACED && (deblock_on_slice_edges + || h->mb.slice_table[h->mb.i_mb_top_xy] == h->mb.slice_table[h->mb.i_mb_xy]) ) + h->mb.i_neighbour |= MB_TOP; +} + +void x264_frame_deblock_row( x264_t *h, int mb_y ) +{ + int b_interlaced = SLICE_MBAFF; + int a = h->sh.i_alpha_c0_offset - QP_BD_OFFSET; + int b = h->sh.i_beta_offset - QP_BD_OFFSET; + int qp_thresh = 15 - X264_MIN( a, b ) - X264_MAX( 0, h->pps->i_chroma_qp_index_offset ); + int stridey = h->fdec->i_stride[0]; + int strideuv = h->fdec->i_stride[1]; + int chroma444 = CHROMA444; + int chroma_height = 16 >> CHROMA_V_SHIFT; + intptr_t uvdiff = chroma444 ? h->fdec->plane[2] - h->fdec->plane[1] : 1; + + for( int mb_x = 0; mb_x < h->mb.i_mb_width; mb_x += (~b_interlaced | mb_y)&1, mb_y ^= b_interlaced ) + { + x264_prefetch_fenc( h, h->fdec, mb_x, mb_y ); + x264_macroblock_cache_load_neighbours_deblock( h, mb_x, mb_y ); + + int mb_xy = h->mb.i_mb_xy; + int transform_8x8 = h->mb.mb_transform_size[mb_xy]; + int intra_cur = IS_INTRA( h->mb.type[mb_xy] ); + uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?mb_xy:mb_x]; + + pixel *pixy = h->fdec->plane[0] + 16*mb_y*stridey + 16*mb_x; + pixel *pixuv = h->fdec->plane[1] + chroma_height*mb_y*strideuv + 16*mb_x; + + if( mb_y & MB_INTERLACED ) + { + pixy -= 15*stridey; + pixuv -= (chroma_height-1)*strideuv; + } + + int stride2y = stridey << MB_INTERLACED; + int stride2uv = strideuv << MB_INTERLACED; + int qp = h->mb.qp[mb_xy]; + int qpc = h->chroma_qp_table[qp]; + int first_edge_only = (h->mb.partition[mb_xy] == D_16x16 && !h->mb.cbp[mb_xy] && !intra_cur) || qp <= qp_thresh; + + #define FILTER( intra, dir, edge, qp, chroma_qp )\ + do\ + {\ + if( !(edge & 1) || !transform_8x8 )\ + {\ + deblock_edge##intra( h, pixy + 4*edge*(dir?stride2y:1),\ + stride2y, bs[dir][edge], qp, a, b, 0,\ + h->loopf.deblock_luma##intra[dir] );\ + if( CHROMA_FORMAT == CHROMA_444 )\ + {\ + deblock_edge##intra( h, pixuv + 4*edge*(dir?stride2uv:1),\ + stride2uv, bs[dir][edge], chroma_qp, a, b, 0,\ + h->loopf.deblock_luma##intra[dir] );\ + deblock_edge##intra( h, pixuv + uvdiff + 4*edge*(dir?stride2uv:1),\ + stride2uv, bs[dir][edge], chroma_qp, a, b, 0,\ + h->loopf.deblock_luma##intra[dir] );\ + }\ + else if( CHROMA_FORMAT == CHROMA_420 && !(edge & 1) )\ + {\ + deblock_edge##intra( h, pixuv + edge*(dir?2*stride2uv:4),\ + stride2uv, bs[dir][edge], chroma_qp, a, b, 1,\ + h->loopf.deblock_chroma##intra[dir] );\ + }\ + }\ + if( CHROMA_FORMAT == CHROMA_422 && (dir || !(edge & 1)) )\ + {\ + deblock_edge##intra( h, pixuv + edge*(dir?4*stride2uv:4),\ + stride2uv, bs[dir][edge], chroma_qp, a, b, 1,\ + h->loopf.deblock_chroma##intra[dir] );\ + }\ + } while( 0 ) + + if( h->mb.i_neighbour & MB_LEFT ) + { + if( b_interlaced && h->mb.field[h->mb.i_mb_left_xy[0]] != MB_INTERLACED ) + { + int luma_qp[2]; + int chroma_qp[2]; + int left_qp[2]; + x264_deblock_inter_t luma_deblock = h->loopf.deblock_luma_mbaff; + x264_deblock_inter_t chroma_deblock = h->loopf.deblock_chroma_mbaff; + x264_deblock_intra_t luma_intra_deblock = h->loopf.deblock_luma_intra_mbaff; + x264_deblock_intra_t chroma_intra_deblock = h->loopf.deblock_chroma_intra_mbaff; + int c = chroma444 ? 0 : 1; + + left_qp[0] = h->mb.qp[h->mb.i_mb_left_xy[0]]; + luma_qp[0] = (qp + left_qp[0] + 1) >> 1; + chroma_qp[0] = (qpc + h->chroma_qp_table[left_qp[0]] + 1) >> 1; + if( intra_cur || IS_INTRA( h->mb.type[h->mb.i_mb_left_xy[0]] ) ) + { + deblock_edge_intra( h, pixy, 2*stridey, bs[0][0], luma_qp[0], a, b, 0, luma_intra_deblock ); + deblock_edge_intra( h, pixuv, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock ); + if( chroma444 ) + deblock_edge_intra( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock ); + } + else + { + deblock_edge( h, pixy, 2*stridey, bs[0][0], luma_qp[0], a, b, 0, luma_deblock ); + deblock_edge( h, pixuv, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock ); + if( chroma444 ) + deblock_edge( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock ); + } + + int offy = MB_INTERLACED ? 4 : 0; + int offuv = MB_INTERLACED ? 4-CHROMA_V_SHIFT : 0; + left_qp[1] = h->mb.qp[h->mb.i_mb_left_xy[1]]; + luma_qp[1] = (qp + left_qp[1] + 1) >> 1; + chroma_qp[1] = (qpc + h->chroma_qp_table[left_qp[1]] + 1) >> 1; + if( intra_cur || IS_INTRA( h->mb.type[h->mb.i_mb_left_xy[1]] ) ) + { + deblock_edge_intra( h, pixy + (stridey<mb.qp[h->mb.i_mb_xy-1]; + int qp_left = (qp + qpl + 1) >> 1; + int qpc_left = (qpc + h->chroma_qp_table[qpl] + 1) >> 1; + int intra_left = IS_INTRA( h->mb.type[h->mb.i_mb_xy-1] ); + int intra_deblock = intra_cur || intra_left; + + /* Any MB that was coded, or that analysis decided to skip, has quality commensurate with its QP. + * But if deblocking affects neighboring MBs that were force-skipped, blur might accumulate there. + * So reset their effective QP to max, to indicate that lack of guarantee. */ + if( h->fdec->mb_info && M32( bs[0][0] ) ) + { +#define RESET_EFFECTIVE_QP(xy) h->fdec->effective_qp[xy] |= 0xff * !!(h->fdec->mb_info[xy] & X264_MBINFO_CONSTANT); + RESET_EFFECTIVE_QP(mb_xy); + RESET_EFFECTIVE_QP(h->mb.i_mb_left_xy[0]); + } + + if( intra_deblock ) + FILTER( _intra, 0, 0, qp_left, qpc_left ); + else + FILTER( , 0, 0, qp_left, qpc_left ); + } + } + if( !first_edge_only ) + { + FILTER( , 0, 1, qp, qpc ); + FILTER( , 0, 2, qp, qpc ); + FILTER( , 0, 3, qp, qpc ); + } + + if( h->mb.i_neighbour & MB_TOP ) + { + if( b_interlaced && !(mb_y&1) && !MB_INTERLACED && h->mb.field[h->mb.i_mb_top_xy] ) + { + int mbn_xy = mb_xy - 2 * h->mb.i_mb_stride; + + for( int j = 0; j < 2; j++, mbn_xy += h->mb.i_mb_stride ) + { + int qpt = h->mb.qp[mbn_xy]; + int qp_top = (qp + qpt + 1) >> 1; + int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1; + int intra_top = IS_INTRA( h->mb.type[mbn_xy] ); + if( intra_cur || intra_top ) + M32( bs[1][4*j] ) = 0x03030303; + + // deblock the first horizontal edge of the even rows, then the first horizontal edge of the odd rows + deblock_edge( h, pixy + j*stridey, 2* stridey, bs[1][4*j], qp_top, a, b, 0, h->loopf.deblock_luma[1] ); + if( chroma444 ) + { + deblock_edge( h, pixuv + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 0, h->loopf.deblock_luma[1] ); + deblock_edge( h, pixuv + uvdiff + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 0, h->loopf.deblock_luma[1] ); + } + else + deblock_edge( h, pixuv + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 1, h->loopf.deblock_chroma[1] ); + } + } + else + { + int qpt = h->mb.qp[h->mb.i_mb_top_xy]; + int qp_top = (qp + qpt + 1) >> 1; + int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1; + int intra_top = IS_INTRA( h->mb.type[h->mb.i_mb_top_xy] ); + int intra_deblock = intra_cur || intra_top; + + /* This edge has been modified, reset effective qp to max. */ + if( h->fdec->mb_info && M32( bs[1][0] ) ) + { + RESET_EFFECTIVE_QP(mb_xy); + RESET_EFFECTIVE_QP(h->mb.i_mb_top_xy); + } + + if( (!b_interlaced || (!MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy])) && intra_deblock ) + { + FILTER( _intra, 1, 0, qp_top, qpc_top ); + } + else + { + if( intra_deblock ) + M32( bs[1][0] ) = 0x03030303; + FILTER( , 1, 0, qp_top, qpc_top ); + } + } + } + + if( !first_edge_only ) + { + FILTER( , 1, 1, qp, qpc ); + FILTER( , 1, 2, qp, qpc ); + FILTER( , 1, 3, qp, qpc ); + } + + #undef FILTER + } +} + +/* For deblock-aware RD. + * TODO: + * deblock macroblock edges + * support analysis partitions smaller than 16x16 + * deblock chroma for 4:2:0/4:2:2 + * handle duplicate refs correctly + */ +void x264_macroblock_deblock( x264_t *h ) +{ + int a = h->sh.i_alpha_c0_offset - QP_BD_OFFSET; + int b = h->sh.i_beta_offset - QP_BD_OFFSET; + int qp_thresh = 15 - X264_MIN( a, b ) - X264_MAX( 0, h->pps->i_chroma_qp_index_offset ); + int intra_cur = IS_INTRA( h->mb.i_type ); + int qp = h->mb.i_qp; + int qpc = h->mb.i_chroma_qp; + if( (h->mb.i_partition == D_16x16 && !h->mb.i_cbp_luma && !intra_cur) || qp <= qp_thresh ) + return; + + uint8_t (*bs)[8][4] = h->mb.cache.deblock_strength; + if( intra_cur ) + { + M32( bs[0][1] ) = 0x03030303; + M64( bs[0][2] ) = 0x0303030303030303ULL; + M32( bs[1][1] ) = 0x03030303; + M64( bs[1][2] ) = 0x0303030303030303ULL; + } + else + h->loopf.deblock_strength( h->mb.cache.non_zero_count, h->mb.cache.ref, h->mb.cache.mv, + bs, 4 >> MB_INTERLACED, h->sh.i_type == SLICE_TYPE_B ); + + int transform_8x8 = h->mb.b_transform_8x8; + + #define FILTER( dir, edge )\ + do\ + {\ + deblock_edge( h, h->mb.pic.p_fdec[0] + 4*edge*(dir?FDEC_STRIDE:1),\ + FDEC_STRIDE, bs[dir][edge], qp, a, b, 0,\ + h->loopf.deblock_luma[dir] );\ + if( CHROMA444 )\ + {\ + deblock_edge( h, h->mb.pic.p_fdec[1] + 4*edge*(dir?FDEC_STRIDE:1),\ + FDEC_STRIDE, bs[dir][edge], qpc, a, b, 0,\ + h->loopf.deblock_luma[dir] );\ + deblock_edge( h, h->mb.pic.p_fdec[2] + 4*edge*(dir?FDEC_STRIDE:1),\ + FDEC_STRIDE, bs[dir][edge], qpc, a, b, 0,\ + h->loopf.deblock_luma[dir] );\ + }\ + } while( 0 ) + + if( !transform_8x8 ) FILTER( 0, 1 ); + FILTER( 0, 2 ); + if( !transform_8x8 ) FILTER( 0, 3 ); + + if( !transform_8x8 ) FILTER( 1, 1 ); + FILTER( 1, 2 ); + if( !transform_8x8 ) FILTER( 1, 3 ); + + #undef FILTER +} + +#if HAVE_MMX +void x264_deblock_v_luma_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_luma_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_luma_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_luma_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_chroma_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_chroma_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_mbaff_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_mbaff_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_422_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_422_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_422_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_luma_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_v_luma_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_luma_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_luma_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_v_chroma_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_v_chroma_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_422_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_422_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_422_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_strength_sse2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_strength_ssse3 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_strength_avx ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_strength_avx2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_strength_avx512( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); + +void x264_deblock_h_chroma_intra_mbaff_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_intra_mbaff_sse2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_intra_mbaff_avx ( pixel *pix, intptr_t stride, int alpha, int beta ); +#if ARCH_X86 +void x264_deblock_h_luma_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v8_luma_mmx2( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_chroma_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_mbaff_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_luma_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_v8_luma_intra_mmx2( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_v_chroma_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_intra_mbaff_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); + +#if HIGH_BIT_DEPTH +void x264_deblock_v_luma_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_luma_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta ); +#else +// FIXME this wrapper has a significant cpu cost +static void x264_deblock_v_luma_mmx2( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) +{ + x264_deblock_v8_luma_mmx2( pix, stride, alpha, beta, tc0 ); + x264_deblock_v8_luma_mmx2( pix+8, stride, alpha, beta, tc0+2 ); +} +static void x264_deblock_v_luma_intra_mmx2( uint8_t *pix, intptr_t stride, int alpha, int beta ) +{ + x264_deblock_v8_luma_intra_mmx2( pix, stride, alpha, beta ); + x264_deblock_v8_luma_intra_mmx2( pix+8, stride, alpha, beta ); +} +#endif // HIGH_BIT_DEPTH +#endif +#endif + +#if ARCH_PPC +void x264_deblock_v_luma_altivec( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_luma_altivec( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +#endif // ARCH_PPC + +#if HAVE_ARMV6 || ARCH_AARCH64 +void x264_deblock_v_luma_neon ( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_luma_neon ( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_chroma_neon( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_neon( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_strength_neon( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], + int mvy_limit, int bframe ); +void x264_deblock_h_chroma_422_neon( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_mbaff_neon( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_intra_mbaff_neon( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_422_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_v_chroma_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_luma_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_v_luma_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta ); +#endif + +#if !HIGH_BIT_DEPTH +#if HAVE_MSA +void x264_deblock_v_luma_msa( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_luma_msa( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_chroma_msa( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_h_chroma_msa( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +void x264_deblock_v_luma_intra_msa( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_luma_intra_msa( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_v_chroma_intra_msa( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_h_chroma_intra_msa( uint8_t *pix, intptr_t stride, int alpha, int beta ); +void x264_deblock_strength_msa( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], int mvy_limit, + int bframe ); +#endif +#endif + +void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mbaff ) +{ + pf->deblock_luma[1] = deblock_v_luma_c; + pf->deblock_luma[0] = deblock_h_luma_c; + pf->deblock_chroma[1] = deblock_v_chroma_c; + pf->deblock_h_chroma_420 = deblock_h_chroma_c; + pf->deblock_h_chroma_422 = deblock_h_chroma_422_c; + pf->deblock_luma_intra[1] = deblock_v_luma_intra_c; + pf->deblock_luma_intra[0] = deblock_h_luma_intra_c; + pf->deblock_chroma_intra[1] = deblock_v_chroma_intra_c; + pf->deblock_h_chroma_420_intra = deblock_h_chroma_intra_c; + pf->deblock_h_chroma_422_intra = deblock_h_chroma_422_intra_c; + pf->deblock_luma_mbaff = deblock_h_luma_mbaff_c; + pf->deblock_chroma_420_mbaff = deblock_h_chroma_mbaff_c; + pf->deblock_luma_intra_mbaff = deblock_h_luma_intra_mbaff_c; + pf->deblock_chroma_420_intra_mbaff = deblock_h_chroma_intra_mbaff_c; + pf->deblock_strength = deblock_strength_c; + +#if HAVE_MMX + if( cpu&X264_CPU_MMX2 ) + { +#if ARCH_X86 + pf->deblock_luma[1] = x264_deblock_v_luma_mmx2; + pf->deblock_luma[0] = x264_deblock_h_luma_mmx2; + pf->deblock_chroma[1] = x264_deblock_v_chroma_mmx2; + pf->deblock_h_chroma_420 = x264_deblock_h_chroma_mmx2; + pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_mmx2; + pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_mmx2; + pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_mmx2; + pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_mmx2; + pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_mmx2; + pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_mmx2; + pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_mmx2; + pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_mmx2; +#endif +#if !HIGH_BIT_DEPTH + pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_mmx2; +#endif + if( cpu&X264_CPU_SSE2 ) + { + pf->deblock_strength = x264_deblock_strength_sse2; + pf->deblock_h_chroma_420 = x264_deblock_h_chroma_sse2; + pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_sse2; + pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_sse2; + pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_sse2; + pf->deblock_luma[1] = x264_deblock_v_luma_sse2; + pf->deblock_luma[0] = x264_deblock_h_luma_sse2; + pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_sse2; + pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_sse2; + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + pf->deblock_chroma[1] = x264_deblock_v_chroma_sse2; + pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_sse2; + pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_sse2; +#if HIGH_BIT_DEPTH + pf->deblock_chroma_420_intra_mbaff= x264_deblock_h_chroma_intra_mbaff_sse2; +#endif + } + } + if( cpu&X264_CPU_SSSE3 ) + pf->deblock_strength = x264_deblock_strength_ssse3; + if( cpu&X264_CPU_AVX ) + { + pf->deblock_strength = x264_deblock_strength_avx; + pf->deblock_h_chroma_420 = x264_deblock_h_chroma_avx; + pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_avx; + pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_avx; + pf->deblock_luma[1] = x264_deblock_v_luma_avx; + pf->deblock_luma[0] = x264_deblock_h_luma_avx; + pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_avx; + pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_avx; + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + pf->deblock_chroma[1] = x264_deblock_v_chroma_avx; + pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_avx; + pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_avx; +#if HIGH_BIT_DEPTH + pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_avx; + pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_avx; +#endif + } + } + if( cpu&X264_CPU_AVX2 ) + { + pf->deblock_strength = x264_deblock_strength_avx2; + } + if( cpu&X264_CPU_AVX512 ) + { + pf->deblock_strength = x264_deblock_strength_avx512; + } + } +#endif + +#if !HIGH_BIT_DEPTH +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + { + pf->deblock_luma[1] = x264_deblock_v_luma_altivec; + pf->deblock_luma[0] = x264_deblock_h_luma_altivec; + } +#endif // HAVE_ALTIVEC + +#if HAVE_ARMV6 || ARCH_AARCH64 + if( cpu&X264_CPU_NEON ) + { + pf->deblock_luma[1] = x264_deblock_v_luma_neon; + pf->deblock_luma[0] = x264_deblock_h_luma_neon; + pf->deblock_chroma[1] = x264_deblock_v_chroma_neon; + pf->deblock_h_chroma_420 = x264_deblock_h_chroma_neon; + pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_neon; + pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_neon; + pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_neon; + pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_neon; + pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_neon; + pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_neon; + pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_neon; + pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_neon; + pf->deblock_strength = x264_deblock_strength_neon; + } +#endif + +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + { + pf->deblock_luma[1] = x264_deblock_v_luma_msa; + pf->deblock_luma[0] = x264_deblock_h_luma_msa; + pf->deblock_chroma[1] = x264_deblock_v_chroma_msa; + pf->deblock_h_chroma_420 = x264_deblock_h_chroma_msa; + pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_msa; + pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_msa; + pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_msa; + pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_msa; + pf->deblock_strength = x264_deblock_strength_msa; + } +#endif +#endif // !HIGH_BIT_DEPTH + + /* These functions are equivalent, so don't duplicate them. */ + pf->deblock_chroma_422_mbaff = pf->deblock_h_chroma_420; + pf->deblock_chroma_422_intra_mbaff = pf->deblock_h_chroma_420_intra; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/frame.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/frame.c new file mode 100644 index 00000000..4d80cbb0 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/frame.c @@ -0,0 +1,899 @@ +/***************************************************************************** + * frame.c: frame handling + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +static int align_stride( int x, int align, int disalign ) +{ + x = ALIGN( x, align ); + if( !(x&(disalign-1)) ) + x += align; + return x; +} + +static int align_plane_size( int x, int disalign ) +{ + if( !(x&(disalign-1)) ) + x += 128; + return x; +} + +static int x264_frame_internal_csp( int external_csp ) +{ + switch( external_csp & X264_CSP_MASK ) + { + case X264_CSP_NV12: + case X264_CSP_NV21: + case X264_CSP_I420: + case X264_CSP_YV12: + return X264_CSP_NV12; + case X264_CSP_NV16: + case X264_CSP_I422: + case X264_CSP_YV16: + case X264_CSP_YUYV: + case X264_CSP_UYVY: + case X264_CSP_V210: + return X264_CSP_NV16; + case X264_CSP_I444: + case X264_CSP_YV24: + case X264_CSP_BGR: + case X264_CSP_BGRA: + case X264_CSP_RGB: + return X264_CSP_I444; + default: + return X264_CSP_NONE; + } +} + +static x264_frame_t *x264_frame_new( x264_t *h, int b_fdec ) +{ + x264_frame_t *frame; + int i_csp = x264_frame_internal_csp( h->param.i_csp ); + int i_mb_count = h->mb.i_mb_count; + int i_stride, i_width, i_lines, luma_plane_count; + int i_padv = PADV << PARAM_INTERLACED; + int align = 16; +#if ARCH_X86 || ARCH_X86_64 + if( h->param.cpu&X264_CPU_CACHELINE_64 || h->param.cpu&X264_CPU_AVX512 ) + align = 64; + else if( h->param.cpu&X264_CPU_CACHELINE_32 || h->param.cpu&X264_CPU_AVX ) + align = 32; +#endif +#if ARCH_PPC + int disalign = 1<<9; +#else + int disalign = 1<<10; +#endif + + CHECKED_MALLOCZERO( frame, sizeof(x264_frame_t) ); + PREALLOC_INIT + + /* allocate frame data (+64 for extra data for me) */ + i_width = h->mb.i_mb_width*16; + i_lines = h->mb.i_mb_height*16; + i_stride = align_stride( i_width + 2*PADH, align, disalign ); + + if( i_csp == X264_CSP_NV12 || i_csp == X264_CSP_NV16 ) + { + luma_plane_count = 1; + frame->i_plane = 2; + for( int i = 0; i < 2; i++ ) + { + frame->i_width[i] = i_width >> i; + frame->i_lines[i] = i_lines >> (i && i_csp == X264_CSP_NV12); + frame->i_stride[i] = i_stride; + } + } + else if( i_csp == X264_CSP_I444 ) + { + luma_plane_count = 3; + frame->i_plane = 3; + for( int i = 0; i < 3; i++ ) + { + frame->i_width[i] = i_width; + frame->i_lines[i] = i_lines; + frame->i_stride[i] = i_stride; + } + } + else + goto fail; + + frame->i_csp = i_csp; + frame->i_width_lowres = frame->i_width[0]/2; + frame->i_lines_lowres = frame->i_lines[0]/2; + frame->i_stride_lowres = align_stride( frame->i_width_lowres + 2*PADH, align, disalign<<1 ); + + for( int i = 0; i < h->param.i_bframe + 2; i++ ) + for( int j = 0; j < h->param.i_bframe + 2; j++ ) + PREALLOC( frame->i_row_satds[i][j], i_lines/16 * sizeof(int) ); + + frame->i_poc = -1; + frame->i_type = X264_TYPE_AUTO; + frame->i_qpplus1 = X264_QP_AUTO; + frame->i_pts = -1; + frame->i_frame = -1; + frame->i_frame_num = -1; + frame->i_lines_completed = -1; + frame->b_fdec = b_fdec; + frame->i_pic_struct = PIC_STRUCT_AUTO; + frame->i_field_cnt = -1; + frame->i_duration = + frame->i_cpb_duration = + frame->i_dpb_output_delay = + frame->i_cpb_delay = 0; + frame->i_coded_fields_lookahead = + frame->i_cpb_delay_lookahead = -1; + + frame->orig = frame; + + if( i_csp == X264_CSP_NV12 || i_csp == X264_CSP_NV16 ) + { + int chroma_padv = i_padv >> (i_csp == X264_CSP_NV12); + int chroma_plane_size = (frame->i_stride[1] * (frame->i_lines[1] + 2*chroma_padv)); + PREALLOC( frame->buffer[1], chroma_plane_size * sizeof(pixel) ); + if( PARAM_INTERLACED ) + PREALLOC( frame->buffer_fld[1], chroma_plane_size * sizeof(pixel) ); + } + + /* all 4 luma planes allocated together, since the cacheline split code + * requires them to be in-phase wrt cacheline alignment. */ + + for( int p = 0; p < luma_plane_count; p++ ) + { + int luma_plane_size = align_plane_size( frame->i_stride[p] * (frame->i_lines[p] + 2*i_padv), disalign ); + if( h->param.analyse.i_subpel_refine && b_fdec ) + { + /* FIXME: Don't allocate both buffers in non-adaptive MBAFF. */ + PREALLOC( frame->buffer[p], 4*luma_plane_size * sizeof(pixel) ); + if( PARAM_INTERLACED ) + PREALLOC( frame->buffer_fld[p], 4*luma_plane_size * sizeof(pixel) ); + } + else + { + PREALLOC( frame->buffer[p], luma_plane_size * sizeof(pixel) ); + if( PARAM_INTERLACED ) + PREALLOC( frame->buffer_fld[p], luma_plane_size * sizeof(pixel) ); + } + } + + frame->b_duplicate = 0; + + if( b_fdec ) /* fdec frame */ + { + PREALLOC( frame->mb_type, i_mb_count * sizeof(int8_t) ); + PREALLOC( frame->mb_partition, i_mb_count * sizeof(uint8_t) ); + PREALLOC( frame->mv[0], 2*16 * i_mb_count * sizeof(int16_t) ); + PREALLOC( frame->mv16x16, 2*(i_mb_count+1) * sizeof(int16_t) ); + PREALLOC( frame->ref[0], 4 * i_mb_count * sizeof(int8_t) ); + if( h->param.i_bframe ) + { + PREALLOC( frame->mv[1], 2*16 * i_mb_count * sizeof(int16_t) ); + PREALLOC( frame->ref[1], 4 * i_mb_count * sizeof(int8_t) ); + } + else + { + frame->mv[1] = NULL; + frame->ref[1] = NULL; + } + PREALLOC( frame->i_row_bits, i_lines/16 * sizeof(int) ); + PREALLOC( frame->f_row_qp, i_lines/16 * sizeof(float) ); + PREALLOC( frame->f_row_qscale, i_lines/16 * sizeof(float) ); + if( h->param.analyse.i_me_method >= X264_ME_ESA ) + PREALLOC( frame->buffer[3], frame->i_stride[0] * (frame->i_lines[0] + 2*i_padv) * sizeof(uint16_t) << h->frames.b_have_sub8x8_esa ); + if( PARAM_INTERLACED ) + PREALLOC( frame->field, i_mb_count * sizeof(uint8_t) ); + if( h->param.analyse.b_mb_info ) + PREALLOC( frame->effective_qp, i_mb_count * sizeof(uint8_t) ); + } + else /* fenc frame */ + { + if( h->frames.b_have_lowres ) + { + int luma_plane_size = align_plane_size( frame->i_stride_lowres * (frame->i_lines[0]/2 + 2*PADV), disalign ); + + PREALLOC( frame->buffer_lowres[0], 4 * luma_plane_size * sizeof(pixel) ); + + for( int j = 0; j <= !!h->param.i_bframe; j++ ) + for( int i = 0; i <= h->param.i_bframe; i++ ) + { + PREALLOC( frame->lowres_mvs[j][i], 2*h->mb.i_mb_count*sizeof(int16_t) ); + PREALLOC( frame->lowres_mv_costs[j][i], h->mb.i_mb_count*sizeof(int) ); + } + PREALLOC( frame->i_propagate_cost, i_mb_count * sizeof(uint16_t) ); + for( int j = 0; j <= h->param.i_bframe+1; j++ ) + for( int i = 0; i <= h->param.i_bframe+1; i++ ) + PREALLOC( frame->lowres_costs[j][i], i_mb_count * sizeof(uint16_t) ); + + /* mbtree asm can overread the input buffers, make sure we don't read outside of allocated memory. */ + prealloc_size += NATIVE_ALIGN; + } + if( h->param.rc.i_aq_mode ) + { + PREALLOC( frame->f_qp_offset, h->mb.i_mb_count * sizeof(float) ); + PREALLOC( frame->f_qp_offset_aq, h->mb.i_mb_count * sizeof(float) ); + if( h->frames.b_have_lowres ) + PREALLOC( frame->i_inv_qscale_factor, (h->mb.i_mb_count+3) * sizeof(uint16_t) ); + } + } + + PREALLOC_END( frame->base ); + + if( i_csp == X264_CSP_NV12 || i_csp == X264_CSP_NV16 ) + { + int chroma_padv = i_padv >> (i_csp == X264_CSP_NV12); + frame->plane[1] = frame->buffer[1] + frame->i_stride[1] * chroma_padv + PADH; + if( PARAM_INTERLACED ) + frame->plane_fld[1] = frame->buffer_fld[1] + frame->i_stride[1] * chroma_padv + PADH; + } + + for( int p = 0; p < luma_plane_count; p++ ) + { + int luma_plane_size = align_plane_size( frame->i_stride[p] * (frame->i_lines[p] + 2*i_padv), disalign ); + if( h->param.analyse.i_subpel_refine && b_fdec ) + { + for( int i = 0; i < 4; i++ ) + { + frame->filtered[p][i] = frame->buffer[p] + i*luma_plane_size + frame->i_stride[p] * i_padv + PADH; + frame->filtered_fld[p][i] = frame->buffer_fld[p] + i*luma_plane_size + frame->i_stride[p] * i_padv + PADH; + } + frame->plane[p] = frame->filtered[p][0]; + frame->plane_fld[p] = frame->filtered_fld[p][0]; + } + else + { + frame->filtered[p][0] = frame->plane[p] = frame->buffer[p] + frame->i_stride[p] * i_padv + PADH; + frame->filtered_fld[p][0] = frame->plane_fld[p] = frame->buffer_fld[p] + frame->i_stride[p] * i_padv + PADH; + } + } + + if( b_fdec ) + { + M32( frame->mv16x16[0] ) = 0; + frame->mv16x16++; + + if( h->param.analyse.i_me_method >= X264_ME_ESA ) + frame->integral = (uint16_t*)frame->buffer[3] + frame->i_stride[0] * i_padv + PADH; + } + else + { + if( h->frames.b_have_lowres ) + { + int luma_plane_size = align_plane_size( frame->i_stride_lowres * (frame->i_lines[0]/2 + 2*PADV), disalign ); + for( int i = 0; i < 4; i++ ) + frame->lowres[i] = frame->buffer_lowres[0] + (frame->i_stride_lowres * PADV + PADH) + i * luma_plane_size; + + for( int j = 0; j <= !!h->param.i_bframe; j++ ) + for( int i = 0; i <= h->param.i_bframe; i++ ) + memset( frame->lowres_mvs[j][i], 0, 2*h->mb.i_mb_count*sizeof(int16_t) ); + + frame->i_intra_cost = frame->lowres_costs[0][0]; + memset( frame->i_intra_cost, -1, (i_mb_count+3) * sizeof(uint16_t) ); + + if( h->param.rc.i_aq_mode ) + /* shouldn't really be initialized, just silences a valgrind false-positive in x264_mbtree_propagate_cost_sse2 */ + memset( frame->i_inv_qscale_factor, 0, (h->mb.i_mb_count+3) * sizeof(uint16_t) ); + } + } + + if( x264_pthread_mutex_init( &frame->mutex, NULL ) ) + goto fail; + if( x264_pthread_cond_init( &frame->cv, NULL ) ) + goto fail; + +#if HAVE_OPENCL + frame->opencl.ocl = h->opencl.ocl; +#endif + + return frame; + +fail: + x264_free( frame ); + return NULL; +} + +void x264_frame_delete( x264_frame_t *frame ) +{ + /* Duplicate frames are blank copies of real frames (including pointers), + * so freeing those pointers would cause a double free later. */ + if( !frame->b_duplicate ) + { + x264_free( frame->base ); + + if( frame->param && frame->param->param_free ) + frame->param->param_free( frame->param ); + if( frame->mb_info_free ) + frame->mb_info_free( frame->mb_info ); + if( frame->extra_sei.sei_free ) + { + for( int i = 0; i < frame->extra_sei.num_payloads; i++ ) + frame->extra_sei.sei_free( frame->extra_sei.payloads[i].payload ); + frame->extra_sei.sei_free( frame->extra_sei.payloads ); + } + x264_pthread_mutex_destroy( &frame->mutex ); + x264_pthread_cond_destroy( &frame->cv ); +#if HAVE_OPENCL + x264_opencl_frame_delete( frame ); +#endif + } + x264_free( frame ); +} + +static int get_plane_ptr( x264_t *h, x264_picture_t *src, uint8_t **pix, int *stride, int plane, int xshift, int yshift ) +{ + int width = h->param.i_width >> xshift; + int height = h->param.i_height >> yshift; + *pix = src->img.plane[plane]; + *stride = src->img.i_stride[plane]; + if( src->img.i_csp & X264_CSP_VFLIP ) + { + *pix += (height-1) * *stride; + *stride = -*stride; + } + if( width > abs(*stride) ) + { + x264_log( h, X264_LOG_ERROR, "Input picture width (%d) is greater than stride (%d)\n", width, *stride ); + return -1; + } + return 0; +} + +#define get_plane_ptr(...) do { if( get_plane_ptr(__VA_ARGS__) < 0 ) return -1; } while( 0 ) + +int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src ) +{ + int i_csp = src->img.i_csp & X264_CSP_MASK; + if( dst->i_csp != x264_frame_internal_csp( i_csp ) ) + { + x264_log( h, X264_LOG_ERROR, "Invalid input colorspace\n" ); + return -1; + } + +#if HIGH_BIT_DEPTH + if( !(src->img.i_csp & X264_CSP_HIGH_DEPTH) ) + { + x264_log( h, X264_LOG_ERROR, "This build of x264 requires high depth input. Rebuild to support 8-bit input.\n" ); + return -1; + } +#else + if( src->img.i_csp & X264_CSP_HIGH_DEPTH ) + { + x264_log( h, X264_LOG_ERROR, "This build of x264 requires 8-bit input. Rebuild to support high depth input.\n" ); + return -1; + } +#endif + + if( BIT_DEPTH != 10 && i_csp == X264_CSP_V210 ) + { + x264_log( h, X264_LOG_ERROR, "v210 input is only compatible with bit-depth of 10 bits\n" ); + return -1; + } + + if( src->i_type < X264_TYPE_AUTO || src->i_type > X264_TYPE_KEYFRAME ) + { + x264_log( h, X264_LOG_WARNING, "forced frame type (%d) at %d is unknown\n", src->i_type, h->frames.i_input ); + dst->i_forced_type = X264_TYPE_AUTO; + } + else + dst->i_forced_type = src->i_type; + + dst->i_type = dst->i_forced_type; + dst->i_qpplus1 = src->i_qpplus1; + dst->i_pts = dst->i_reordered_pts = src->i_pts; + dst->param = src->param; + dst->i_pic_struct = src->i_pic_struct; + dst->extra_sei = src->extra_sei; + dst->opaque = src->opaque; + dst->mb_info = h->param.analyse.b_mb_info ? src->prop.mb_info : NULL; + dst->mb_info_free = h->param.analyse.b_mb_info ? src->prop.mb_info_free : NULL; + + uint8_t *pix[3]; + int stride[3]; + if( i_csp == X264_CSP_YUYV || i_csp == X264_CSP_UYVY ) + { + int p = i_csp == X264_CSP_UYVY; + h->mc.plane_copy_deinterleave_yuyv( dst->plane[p], dst->i_stride[p], dst->plane[p^1], dst->i_stride[p^1], + (pixel*)src->img.plane[0], src->img.i_stride[0], h->param.i_width, h->param.i_height ); + } + else if( i_csp == X264_CSP_V210 ) + { + stride[0] = src->img.i_stride[0]; + pix[0] = src->img.plane[0]; + + h->mc.plane_copy_deinterleave_v210( dst->plane[0], dst->i_stride[0], + dst->plane[1], dst->i_stride[1], + (uint32_t *)pix[0], stride[0]/sizeof(uint32_t), h->param.i_width, h->param.i_height ); + } + else if( i_csp >= X264_CSP_BGR ) + { + stride[0] = src->img.i_stride[0]; + pix[0] = src->img.plane[0]; + if( src->img.i_csp & X264_CSP_VFLIP ) + { + pix[0] += (h->param.i_height-1) * stride[0]; + stride[0] = -stride[0]; + } + int b = i_csp==X264_CSP_RGB; + h->mc.plane_copy_deinterleave_rgb( dst->plane[1+b], dst->i_stride[1+b], + dst->plane[0], dst->i_stride[0], + dst->plane[2-b], dst->i_stride[2-b], + (pixel*)pix[0], stride[0]/sizeof(pixel), i_csp==X264_CSP_BGRA ? 4 : 3, h->param.i_width, h->param.i_height ); + } + else + { + int v_shift = CHROMA_V_SHIFT; + get_plane_ptr( h, src, &pix[0], &stride[0], 0, 0, 0 ); + h->mc.plane_copy( dst->plane[0], dst->i_stride[0], (pixel*)pix[0], + stride[0]/sizeof(pixel), h->param.i_width, h->param.i_height ); + if( i_csp == X264_CSP_NV12 || i_csp == X264_CSP_NV16 ) + { + get_plane_ptr( h, src, &pix[1], &stride[1], 1, 0, v_shift ); + h->mc.plane_copy( dst->plane[1], dst->i_stride[1], (pixel*)pix[1], + stride[1]/sizeof(pixel), h->param.i_width, h->param.i_height>>v_shift ); + } + else if( i_csp == X264_CSP_NV21 ) + { + get_plane_ptr( h, src, &pix[1], &stride[1], 1, 0, v_shift ); + h->mc.plane_copy_swap( dst->plane[1], dst->i_stride[1], (pixel*)pix[1], + stride[1]/sizeof(pixel), h->param.i_width>>1, h->param.i_height>>v_shift ); + } + else if( i_csp == X264_CSP_I420 || i_csp == X264_CSP_I422 || i_csp == X264_CSP_YV12 || i_csp == X264_CSP_YV16 ) + { + int uv_swap = i_csp == X264_CSP_YV12 || i_csp == X264_CSP_YV16; + get_plane_ptr( h, src, &pix[1], &stride[1], uv_swap ? 2 : 1, 1, v_shift ); + get_plane_ptr( h, src, &pix[2], &stride[2], uv_swap ? 1 : 2, 1, v_shift ); + h->mc.plane_copy_interleave( dst->plane[1], dst->i_stride[1], + (pixel*)pix[1], stride[1]/sizeof(pixel), + (pixel*)pix[2], stride[2]/sizeof(pixel), + h->param.i_width>>1, h->param.i_height>>v_shift ); + } + else //if( i_csp == X264_CSP_I444 || i_csp == X264_CSP_YV24 ) + { + get_plane_ptr( h, src, &pix[1], &stride[1], i_csp==X264_CSP_I444 ? 1 : 2, 0, 0 ); + get_plane_ptr( h, src, &pix[2], &stride[2], i_csp==X264_CSP_I444 ? 2 : 1, 0, 0 ); + h->mc.plane_copy( dst->plane[1], dst->i_stride[1], (pixel*)pix[1], + stride[1]/sizeof(pixel), h->param.i_width, h->param.i_height ); + h->mc.plane_copy( dst->plane[2], dst->i_stride[2], (pixel*)pix[2], + stride[2]/sizeof(pixel), h->param.i_width, h->param.i_height ); + } + } + return 0; +} + +static void ALWAYS_INLINE pixel_memset( pixel *dst, pixel *src, int len, int size ) +{ + uint8_t *dstp = (uint8_t*)dst; + uint32_t v1 = *src; + uint32_t v2 = size == 1 ? v1 + (v1 << 8) : M16( src ); + uint32_t v4 = size <= 2 ? v2 + (v2 << 16) : M32( src ); + int i = 0; + len *= size; + + /* Align the input pointer if it isn't already */ + if( (intptr_t)dstp & (WORD_SIZE - 1) ) + { + if( size <= 2 && ((intptr_t)dstp & 3) ) + { + if( size == 1 && ((intptr_t)dstp & 1) ) + dstp[i++] = v1; + if( (intptr_t)dstp & 2 ) + { + M16( dstp+i ) = v2; + i += 2; + } + } + if( WORD_SIZE == 8 && (intptr_t)dstp & 4 ) + { + M32( dstp+i ) = v4; + i += 4; + } + } + + /* Main copy loop */ + if( WORD_SIZE == 8 ) + { + uint64_t v8 = v4 + ((uint64_t)v4<<32); + for( ; i < len - 7; i+=8 ) + M64( dstp+i ) = v8; + } + for( ; i < len - 3; i+=4 ) + M32( dstp+i ) = v4; + + /* Finish up the last few bytes */ + if( size <= 2 ) + { + if( i < len - 1 ) + { + M16( dstp+i ) = v2; + i += 2; + } + if( size == 1 && i != len ) + dstp[i] = v1; + } +} + +static void ALWAYS_INLINE plane_expand_border( pixel *pix, int i_stride, int i_width, int i_height, int i_padh, int i_padv, int b_pad_top, int b_pad_bottom, int b_chroma ) +{ +#define PPIXEL(x, y) ( pix + (x) + (y)*i_stride ) + for( int y = 0; y < i_height; y++ ) + { + /* left band */ + pixel_memset( PPIXEL(-i_padh, y), PPIXEL(0, y), i_padh>>b_chroma, sizeof(pixel)<>b_chroma, sizeof(pixel)<mb.i_mb_height - (1 << SLICE_MBAFF); + int b_start = mb_y == h->i_threadslice_start; + int b_end = mb_y == h->i_threadslice_end - (1 << SLICE_MBAFF); + if( mb_y & SLICE_MBAFF ) + return; + for( int i = 0; i < frame->i_plane; i++ ) + { + int h_shift = i && CHROMA_H_SHIFT; + int v_shift = i && CHROMA_V_SHIFT; + int stride = frame->i_stride[i]; + int width = 16*h->mb.i_mb_width; + int height = (pad_bot ? 16*(h->mb.i_mb_height - mb_y) >> SLICE_MBAFF : 16) >> v_shift; + int padh = PADH; + int padv = PADV >> v_shift; + // buffer: 2 chroma, 3 luma (rounded to 4) because deblocking goes beyond the top of the mb + if( b_end && !b_start ) + height += 4 >> (v_shift + SLICE_MBAFF); + pixel *pix; + int starty = 16*mb_y - 4*!b_start; + if( SLICE_MBAFF ) + { + // border samples for each field are extended separately + pix = frame->plane_fld[i] + (starty*stride >> v_shift); + plane_expand_border( pix, stride*2, width, height, padh, padv, pad_top, pad_bot, h_shift ); + plane_expand_border( pix+stride, stride*2, width, height, padh, padv, pad_top, pad_bot, h_shift ); + + height = (pad_bot ? 16*(h->mb.i_mb_height - mb_y) : 32) >> v_shift; + if( b_end && !b_start ) + height += 4 >> v_shift; + pix = frame->plane[i] + (starty*stride >> v_shift); + plane_expand_border( pix, stride, width, height, padh, padv, pad_top, pad_bot, h_shift ); + } + else + { + pix = frame->plane[i] + (starty*stride >> v_shift); + plane_expand_border( pix, stride, width, height, padh, padv, pad_top, pad_bot, h_shift ); + } + } +} + +void x264_frame_expand_border_filtered( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ) +{ + /* during filtering, 8 extra pixels were filtered on each edge, + * but up to 3 of the horizontal ones may be wrong. + we want to expand border from the last filtered pixel */ + int b_start = !mb_y; + int width = 16*h->mb.i_mb_width + 8; + int height = b_end ? (16*(h->mb.i_mb_height - mb_y) >> SLICE_MBAFF) + 16 : 16; + int padh = PADH - 4; + int padv = PADV - 8; + for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ ) + for( int i = 1; i < 4; i++ ) + { + int stride = frame->i_stride[p]; + // buffer: 8 luma, to match the hpel filter + pixel *pix; + if( SLICE_MBAFF ) + { + pix = frame->filtered_fld[p][i] + (16*mb_y - 16) * stride - 4; + plane_expand_border( pix, stride*2, width, height, padh, padv, b_start, b_end, 0 ); + plane_expand_border( pix+stride, stride*2, width, height, padh, padv, b_start, b_end, 0 ); + } + + pix = frame->filtered[p][i] + (16*mb_y - 8) * stride - 4; + plane_expand_border( pix, stride, width, height << SLICE_MBAFF, padh, padv, b_start, b_end, 0 ); + } +} + +void x264_frame_expand_border_lowres( x264_frame_t *frame ) +{ + for( int i = 0; i < 4; i++ ) + plane_expand_border( frame->lowres[i], frame->i_stride_lowres, frame->i_width_lowres, frame->i_lines_lowres, PADH, PADV, 1, 1, 0 ); +} + +void x264_frame_expand_border_chroma( x264_t *h, x264_frame_t *frame, int plane ) +{ + int v_shift = CHROMA_V_SHIFT; + plane_expand_border( frame->plane[plane], frame->i_stride[plane], 16*h->mb.i_mb_width, 16*h->mb.i_mb_height>>v_shift, + PADH, PADV>>v_shift, 1, 1, CHROMA_H_SHIFT ); +} + +void x264_frame_expand_border_mod16( x264_t *h, x264_frame_t *frame ) +{ + for( int i = 0; i < frame->i_plane; i++ ) + { + int i_width = h->param.i_width; + int h_shift = i && CHROMA_H_SHIFT; + int v_shift = i && CHROMA_V_SHIFT; + int i_height = h->param.i_height >> v_shift; + int i_padx = (h->mb.i_mb_width * 16 - h->param.i_width); + int i_pady = (h->mb.i_mb_height * 16 - h->param.i_height) >> v_shift; + + if( i_padx ) + { + for( int y = 0; y < i_height; y++ ) + pixel_memset( &frame->plane[i][y*frame->i_stride[i] + i_width], + &frame->plane[i][y*frame->i_stride[i] + i_width - 1-h_shift], + i_padx>>h_shift, sizeof(pixel)<plane[i][y*frame->i_stride[i]], + &frame->plane[i][(i_height-(~y&PARAM_INTERLACED)-1)*frame->i_stride[i]], + (i_width + i_padx) * sizeof(pixel) ); + } + } +} + +void x264_expand_border_mbpair( x264_t *h, int mb_x, int mb_y ) +{ + for( int i = 0; i < h->fenc->i_plane; i++ ) + { + int v_shift = i && CHROMA_V_SHIFT; + int stride = h->fenc->i_stride[i]; + int height = h->param.i_height >> v_shift; + int pady = (h->mb.i_mb_height * 16 - h->param.i_height) >> v_shift; + pixel *fenc = h->fenc->plane[i] + 16*mb_x; + for( int y = height; y < height + pady; y++ ) + memcpy( fenc + y*stride, fenc + (height-1)*stride, 16*sizeof(pixel) ); + } +} + +/* threading */ +void x264_frame_cond_broadcast( x264_frame_t *frame, int i_lines_completed ) +{ + x264_pthread_mutex_lock( &frame->mutex ); + frame->i_lines_completed = i_lines_completed; + x264_pthread_cond_broadcast( &frame->cv ); + x264_pthread_mutex_unlock( &frame->mutex ); +} + +void x264_frame_cond_wait( x264_frame_t *frame, int i_lines_completed ) +{ + x264_pthread_mutex_lock( &frame->mutex ); + while( frame->i_lines_completed < i_lines_completed ) + x264_pthread_cond_wait( &frame->cv, &frame->mutex ); + x264_pthread_mutex_unlock( &frame->mutex ); +} + +void x264_threadslice_cond_broadcast( x264_t *h, int pass ) +{ + x264_pthread_mutex_lock( &h->mutex ); + h->i_threadslice_pass = pass; + if( pass > 0 ) + x264_pthread_cond_broadcast( &h->cv ); + x264_pthread_mutex_unlock( &h->mutex ); +} + +void x264_threadslice_cond_wait( x264_t *h, int pass ) +{ + x264_pthread_mutex_lock( &h->mutex ); + while( h->i_threadslice_pass < pass ) + x264_pthread_cond_wait( &h->cv, &h->mutex ); + x264_pthread_mutex_unlock( &h->mutex ); +} + +int x264_frame_new_slice( x264_t *h, x264_frame_t *frame ) +{ + if( h->param.i_slice_count_max ) + { + int slice_count; + if( h->param.b_sliced_threads ) + slice_count = x264_pthread_fetch_and_add( &frame->i_slice_count, 1, &frame->mutex ); + else + slice_count = frame->i_slice_count++; + if( slice_count >= h->param.i_slice_count_max ) + return -1; + } + return 0; +} + +/* list operators */ + +void x264_frame_push( x264_frame_t **list, x264_frame_t *frame ) +{ + int i = 0; + while( list[i] ) i++; + list[i] = frame; +} + +x264_frame_t *x264_frame_pop( x264_frame_t **list ) +{ + x264_frame_t *frame; + int i = 0; + assert( list[0] ); + while( list[i+1] ) i++; + frame = list[i]; + list[i] = NULL; + return frame; +} + +void x264_frame_unshift( x264_frame_t **list, x264_frame_t *frame ) +{ + int i = 0; + while( list[i] ) i++; + while( i-- ) + list[i+1] = list[i]; + list[0] = frame; +} + +x264_frame_t *x264_frame_shift( x264_frame_t **list ) +{ + x264_frame_t *frame = list[0]; + int i; + for( i = 0; list[i]; i++ ) + list[i] = list[i+1]; + assert(frame); + return frame; +} + +void x264_frame_push_unused( x264_t *h, x264_frame_t *frame ) +{ + assert( frame->i_reference_count > 0 ); + frame->i_reference_count--; + if( frame->i_reference_count == 0 ) + x264_frame_push( h->frames.unused[frame->b_fdec], frame ); +} + +x264_frame_t *x264_frame_pop_unused( x264_t *h, int b_fdec ) +{ + x264_frame_t *frame; + if( h->frames.unused[b_fdec][0] ) + frame = x264_frame_pop( h->frames.unused[b_fdec] ); + else + frame = x264_frame_new( h, b_fdec ); + if( !frame ) + return NULL; + frame->b_last_minigop_bframe = 0; + frame->i_reference_count = 1; + frame->b_intra_calculated = 0; + frame->b_scenecut = 1; + frame->b_keyframe = 0; + frame->b_corrupt = 0; + frame->i_slice_count = h->param.b_sliced_threads ? h->param.i_threads : 1; + + memset( frame->weight, 0, sizeof(frame->weight) ); + memset( frame->f_weighted_cost_delta, 0, sizeof(frame->f_weighted_cost_delta) ); + + return frame; +} + +void x264_frame_push_blank_unused( x264_t *h, x264_frame_t *frame ) +{ + assert( frame->i_reference_count > 0 ); + frame->i_reference_count--; + if( frame->i_reference_count == 0 ) + x264_frame_push( h->frames.blank_unused, frame ); +} + +x264_frame_t *x264_frame_pop_blank_unused( x264_t *h ) +{ + x264_frame_t *frame; + if( h->frames.blank_unused[0] ) + frame = x264_frame_pop( h->frames.blank_unused ); + else + frame = x264_malloc( sizeof(x264_frame_t) ); + if( !frame ) + return NULL; + frame->b_duplicate = 1; + frame->i_reference_count = 1; + return frame; +} + +void x264_weight_scale_plane( x264_t *h, pixel *dst, intptr_t i_dst_stride, pixel *src, intptr_t i_src_stride, + int i_width, int i_height, x264_weight_t *w ) +{ + /* Weight horizontal strips of height 16. This was found to be the optimal height + * in terms of the cache loads. */ + while( i_height > 0 ) + { + int x; + for( x = 0; x < i_width-8; x += 16 ) + w->weightfn[16>>2]( dst+x, i_dst_stride, src+x, i_src_stride, w, X264_MIN( i_height, 16 ) ); + if( x < i_width ) + w->weightfn[ 8>>2]( dst+x, i_dst_stride, src+x, i_src_stride, w, X264_MIN( i_height, 16 ) ); + i_height -= 16; + dst += 16 * i_dst_stride; + src += 16 * i_src_stride; + } +} + +void x264_frame_delete_list( x264_frame_t **list ) +{ + int i = 0; + if( !list ) + return; + while( list[i] ) + x264_frame_delete( list[i++] ); + x264_free( list ); +} + +int x264_sync_frame_list_init( x264_sync_frame_list_t *slist, int max_size ) +{ + if( max_size < 0 ) + return -1; + slist->i_max_size = max_size; + slist->i_size = 0; + CHECKED_MALLOCZERO( slist->list, (max_size+1) * sizeof(x264_frame_t*) ); + if( x264_pthread_mutex_init( &slist->mutex, NULL ) || + x264_pthread_cond_init( &slist->cv_fill, NULL ) || + x264_pthread_cond_init( &slist->cv_empty, NULL ) ) + return -1; + return 0; +fail: + return -1; +} + +void x264_sync_frame_list_delete( x264_sync_frame_list_t *slist ) +{ + x264_pthread_mutex_destroy( &slist->mutex ); + x264_pthread_cond_destroy( &slist->cv_fill ); + x264_pthread_cond_destroy( &slist->cv_empty ); + x264_frame_delete_list( slist->list ); +} + +void x264_sync_frame_list_push( x264_sync_frame_list_t *slist, x264_frame_t *frame ) +{ + x264_pthread_mutex_lock( &slist->mutex ); + while( slist->i_size == slist->i_max_size ) + x264_pthread_cond_wait( &slist->cv_empty, &slist->mutex ); + slist->list[ slist->i_size++ ] = frame; + x264_pthread_mutex_unlock( &slist->mutex ); + x264_pthread_cond_broadcast( &slist->cv_fill ); +} + +x264_frame_t *x264_sync_frame_list_pop( x264_sync_frame_list_t *slist ) +{ + x264_frame_t *frame; + x264_pthread_mutex_lock( &slist->mutex ); + while( !slist->i_size ) + x264_pthread_cond_wait( &slist->cv_fill, &slist->mutex ); + frame = slist->list[ --slist->i_size ]; + slist->list[ slist->i_size ] = NULL; + x264_pthread_cond_broadcast( &slist->cv_empty ); + x264_pthread_mutex_unlock( &slist->mutex ); + return frame; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/frame.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/frame.h new file mode 100644 index 00000000..18eb427f --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/frame.h @@ -0,0 +1,262 @@ +/***************************************************************************** + * frame.h: frame handling + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_FRAME_H +#define X264_FRAME_H + +/* number of pixels past the edge of the frame, for motion estimation/compensation */ +#define PADH 32 +#define PADV 32 + +typedef struct x264_frame +{ + /* */ + uint8_t *base; /* Base pointer for all malloced data in this frame. */ + int i_poc; + int i_delta_poc[2]; + int i_type; + int i_forced_type; + int i_qpplus1; + int64_t i_pts; + int64_t i_dts; + int64_t i_reordered_pts; + int64_t i_duration; /* in SPS time_scale units (i.e 2 * timebase units) used for vfr */ + float f_duration; /* in seconds */ + int64_t i_cpb_duration; + int64_t i_cpb_delay; /* in SPS time_scale units (i.e 2 * timebase units) */ + int64_t i_dpb_output_delay; + x264_param_t *param; + + int i_frame; /* Presentation frame number */ + int i_coded; /* Coded frame number */ + int64_t i_field_cnt; /* Presentation field count */ + int i_frame_num; /* 7.4.3 frame_num */ + int b_kept_as_ref; + int i_pic_struct; + int b_keyframe; + uint8_t b_fdec; + uint8_t b_last_minigop_bframe; /* this frame is the last b in a sequence of bframes */ + uint8_t i_bframes; /* number of bframes following this nonb in coded order */ + float f_qp_avg_rc; /* QPs as decided by ratecontrol */ + float f_qp_avg_aq; /* QPs as decided by AQ in addition to ratecontrol */ + float f_crf_avg; /* Average effective CRF for this frame */ + int i_poc_l0ref0; /* poc of first refframe in L0, used to check if direct temporal is possible */ + + /* YUV buffer */ + int i_csp; /* Internal csp */ + int i_plane; + int i_stride[3]; + int i_width[3]; + int i_lines[3]; + int i_stride_lowres; + int i_width_lowres; + int i_lines_lowres; + pixel *plane[3]; + pixel *plane_fld[3]; + pixel *filtered[3][4]; /* plane[0], H, V, HV */ + pixel *filtered_fld[3][4]; + pixel *lowres[4]; /* half-size copy of input frame: Orig, H, V, HV */ + uint16_t *integral; + + /* for unrestricted mv we allocate more data than needed + * allocated data are stored in buffer */ + pixel *buffer[4]; + pixel *buffer_fld[4]; + pixel *buffer_lowres[4]; + + x264_weight_t weight[X264_REF_MAX][3]; /* [ref_index][plane] */ + pixel *weighted[X264_REF_MAX]; /* plane[0] weighted of the reference frames */ + int b_duplicate; + struct x264_frame *orig; + + /* motion data */ + int8_t *mb_type; + uint8_t *mb_partition; + int16_t (*mv[2])[2]; + int16_t (*mv16x16)[2]; + int16_t (*lowres_mvs[2][X264_BFRAME_MAX+1])[2]; + uint8_t *field; + uint8_t *effective_qp; + + /* Stored as (lists_used << LOWRES_COST_SHIFT) + (cost). + * Doesn't need special addressing for intra cost because + * lists_used is guaranteed to be zero in that cast. */ + uint16_t (*lowres_costs[X264_BFRAME_MAX+2][X264_BFRAME_MAX+2]); + #define LOWRES_COST_MASK ((1<<14)-1) + #define LOWRES_COST_SHIFT 14 + + int *lowres_mv_costs[2][X264_BFRAME_MAX+1]; + int8_t *ref[2]; + int i_ref[2]; + int ref_poc[2][X264_REF_MAX]; + int16_t inv_ref_poc[2]; // inverse values of ref0 poc to avoid divisions in temporal MV prediction + + /* for adaptive B-frame decision. + * contains the SATD cost of the lowres frame encoded in various modes + * FIXME: how big an array do we need? */ + int i_cost_est[X264_BFRAME_MAX+2][X264_BFRAME_MAX+2]; + int i_cost_est_aq[X264_BFRAME_MAX+2][X264_BFRAME_MAX+2]; + int i_satd; // the i_cost_est of the selected frametype + int i_intra_mbs[X264_BFRAME_MAX+2]; + int *i_row_satds[X264_BFRAME_MAX+2][X264_BFRAME_MAX+2]; + int *i_row_satd; + int *i_row_bits; + float *f_row_qp; + float *f_row_qscale; + float *f_qp_offset; + float *f_qp_offset_aq; + int b_intra_calculated; + uint16_t *i_intra_cost; + uint16_t *i_propagate_cost; + uint16_t *i_inv_qscale_factor; + int b_scenecut; /* Set to zero if the frame cannot possibly be part of a real scenecut. */ + float f_weighted_cost_delta[X264_BFRAME_MAX+2]; + uint32_t i_pixel_sum[3]; + uint64_t i_pixel_ssd[3]; + + /* hrd */ + x264_hrd_t hrd_timing; + + /* vbv */ + uint8_t i_planned_type[X264_LOOKAHEAD_MAX+1]; + int i_planned_satd[X264_LOOKAHEAD_MAX+1]; + double f_planned_cpb_duration[X264_LOOKAHEAD_MAX+1]; + int64_t i_coded_fields_lookahead; + int64_t i_cpb_delay_lookahead; + + /* threading */ + int i_lines_completed; /* in pixels */ + int i_lines_weighted; /* FIXME: this only supports weighting of one reference frame */ + int i_reference_count; /* number of threads using this frame (not necessarily the number of pointers) */ + x264_pthread_mutex_t mutex; + x264_pthread_cond_t cv; + int i_slice_count; /* Atomically written to/read from with slice threads */ + + /* periodic intra refresh */ + float f_pir_position; + int i_pir_start_col; + int i_pir_end_col; + int i_frames_since_pir; + + /* interactive encoder control */ + int b_corrupt; + + /* user sei */ + x264_sei_t extra_sei; + + /* user data */ + void *opaque; + + /* user frame properties */ + uint8_t *mb_info; + void (*mb_info_free)( void* ); + +#if HAVE_OPENCL + x264_frame_opencl_t opencl; +#endif +} x264_frame_t; + +/* synchronized frame list */ +typedef struct +{ + x264_frame_t **list; + int i_max_size; + int i_size; + x264_pthread_mutex_t mutex; + x264_pthread_cond_t cv_fill; /* event signaling that the list became fuller */ + x264_pthread_cond_t cv_empty; /* event signaling that the list became emptier */ +} x264_sync_frame_list_t; + +typedef void (*x264_deblock_inter_t)( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ); +typedef void (*x264_deblock_intra_t)( pixel *pix, intptr_t stride, int alpha, int beta ); +typedef struct +{ + x264_deblock_inter_t deblock_luma[2]; + x264_deblock_inter_t deblock_chroma[2]; + x264_deblock_inter_t deblock_h_chroma_420; + x264_deblock_inter_t deblock_h_chroma_422; + x264_deblock_intra_t deblock_luma_intra[2]; + x264_deblock_intra_t deblock_chroma_intra[2]; + x264_deblock_intra_t deblock_h_chroma_420_intra; + x264_deblock_intra_t deblock_h_chroma_422_intra; + x264_deblock_inter_t deblock_luma_mbaff; + x264_deblock_inter_t deblock_chroma_mbaff; + x264_deblock_inter_t deblock_chroma_420_mbaff; + x264_deblock_inter_t deblock_chroma_422_mbaff; + x264_deblock_intra_t deblock_luma_intra_mbaff; + x264_deblock_intra_t deblock_chroma_intra_mbaff; + x264_deblock_intra_t deblock_chroma_420_intra_mbaff; + x264_deblock_intra_t deblock_chroma_422_intra_mbaff; + void (*deblock_strength)( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE], + int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], int mvy_limit, + int bframe ); +} x264_deblock_function_t; + +void x264_frame_delete( x264_frame_t *frame ); + +int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src ); + +void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y ); +void x264_frame_expand_border_filtered( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ); +void x264_frame_expand_border_lowres( x264_frame_t *frame ); +void x264_frame_expand_border_chroma( x264_t *h, x264_frame_t *frame, int plane ); +void x264_frame_expand_border_mod16( x264_t *h, x264_frame_t *frame ); +void x264_expand_border_mbpair( x264_t *h, int mb_x, int mb_y ); + +void x264_frame_deblock_row( x264_t *h, int mb_y ); +void x264_macroblock_deblock( x264_t *h ); + +void x264_frame_filter( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ); +void x264_frame_init_lowres( x264_t *h, x264_frame_t *frame ); + +void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mbaff ); + +void x264_frame_cond_broadcast( x264_frame_t *frame, int i_lines_completed ); +void x264_frame_cond_wait( x264_frame_t *frame, int i_lines_completed ); +int x264_frame_new_slice( x264_t *h, x264_frame_t *frame ); + +void x264_threadslice_cond_broadcast( x264_t *h, int pass ); +void x264_threadslice_cond_wait( x264_t *h, int pass ); + +void x264_frame_push( x264_frame_t **list, x264_frame_t *frame ); +x264_frame_t *x264_frame_pop( x264_frame_t **list ); +void x264_frame_unshift( x264_frame_t **list, x264_frame_t *frame ); +x264_frame_t *x264_frame_shift( x264_frame_t **list ); +void x264_frame_push_unused( x264_t *h, x264_frame_t *frame ); +void x264_frame_push_blank_unused( x264_t *h, x264_frame_t *frame ); +x264_frame_t *x264_frame_pop_blank_unused( x264_t *h ); +void x264_weight_scale_plane( x264_t *h, pixel *dst, intptr_t i_dst_stride, pixel *src, intptr_t i_src_stride, + int i_width, int i_height, x264_weight_t *w ); +x264_frame_t *x264_frame_pop_unused( x264_t *h, int b_fdec ); +void x264_frame_delete_list( x264_frame_t **list ); + +int x264_sync_frame_list_init( x264_sync_frame_list_t *slist, int nelem ); +void x264_sync_frame_list_delete( x264_sync_frame_list_t *slist ); +void x264_sync_frame_list_push( x264_sync_frame_list_t *slist, x264_frame_t *frame ); +x264_frame_t *x264_sync_frame_list_pop( x264_sync_frame_list_t *slist ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/macroblock.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/macroblock.c new file mode 100644 index 00000000..61686715 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/macroblock.c @@ -0,0 +1,1914 @@ +/***************************************************************************** + * macroblock.c: macroblock common functions + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Fiona Glaser + * Laurent Aimar + * Loren Merritt + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#define MC_LUMA(list,p) \ + h->mc.mc_luma( &h->mb.pic.p_fdec[p][4*y*FDEC_STRIDE+4*x], FDEC_STRIDE, \ + &h->mb.pic.p_fref[list][i_ref][p*4], h->mb.pic.i_stride[p], \ + mvx, mvy, 4*width, 4*height, \ + list ? x264_weight_none : &h->sh.weight[i_ref][p] ); + +static NOINLINE void x264_mb_mc_0xywh( x264_t *h, int x, int y, int width, int height ) +{ + int i8 = x264_scan8[0]+x+8*y; + int i_ref = h->mb.cache.ref[0][i8]; + int mvx = x264_clip3( h->mb.cache.mv[0][i8][0], h->mb.mv_min[0], h->mb.mv_max[0] ) + 4*4*x; + int mvy = x264_clip3( h->mb.cache.mv[0][i8][1], h->mb.mv_min[1], h->mb.mv_max[1] ) + 4*4*y; + + MC_LUMA( 0, 0 ); + + if( CHROMA444 ) + { + MC_LUMA( 0, 1 ); + MC_LUMA( 0, 2 ); + } + else + { + int v_shift = CHROMA_V_SHIFT; + // Chroma in 4:2:0 is offset if MCing from a field of opposite parity + if( v_shift & MB_INTERLACED & i_ref ) + mvy += (h->mb.i_mb_y & 1)*4 - 2; + + int offset = (4*FDEC_STRIDE>>v_shift)*y + 2*x; + height = 4*height >> v_shift; + + h->mc.mc_chroma( &h->mb.pic.p_fdec[1][offset], + &h->mb.pic.p_fdec[2][offset], FDEC_STRIDE, + h->mb.pic.p_fref[0][i_ref][4], h->mb.pic.i_stride[1], + mvx, 2*mvy>>v_shift, 2*width, height ); + + if( h->sh.weight[i_ref][1].weightfn ) + h->sh.weight[i_ref][1].weightfn[width>>1]( &h->mb.pic.p_fdec[1][offset], FDEC_STRIDE, + &h->mb.pic.p_fdec[1][offset], FDEC_STRIDE, + &h->sh.weight[i_ref][1], height ); + if( h->sh.weight[i_ref][2].weightfn ) + h->sh.weight[i_ref][2].weightfn[width>>1]( &h->mb.pic.p_fdec[2][offset], FDEC_STRIDE, + &h->mb.pic.p_fdec[2][offset], FDEC_STRIDE, + &h->sh.weight[i_ref][2], height ); + } +} +static NOINLINE void x264_mb_mc_1xywh( x264_t *h, int x, int y, int width, int height ) +{ + int i8 = x264_scan8[0]+x+8*y; + int i_ref = h->mb.cache.ref[1][i8]; + int mvx = x264_clip3( h->mb.cache.mv[1][i8][0], h->mb.mv_min[0], h->mb.mv_max[0] ) + 4*4*x; + int mvy = x264_clip3( h->mb.cache.mv[1][i8][1], h->mb.mv_min[1], h->mb.mv_max[1] ) + 4*4*y; + + MC_LUMA( 1, 0 ); + + if( CHROMA444 ) + { + MC_LUMA( 1, 1 ); + MC_LUMA( 1, 2 ); + } + else + { + int v_shift = CHROMA_V_SHIFT; + if( v_shift & MB_INTERLACED & i_ref ) + mvy += (h->mb.i_mb_y & 1)*4 - 2; + + int offset = (4*FDEC_STRIDE>>v_shift)*y + 2*x; + h->mc.mc_chroma( &h->mb.pic.p_fdec[1][offset], + &h->mb.pic.p_fdec[2][offset], FDEC_STRIDE, + h->mb.pic.p_fref[1][i_ref][4], h->mb.pic.i_stride[1], + mvx, 2*mvy>>v_shift, 2*width, 4*height>>v_shift ); + } +} + +#define MC_LUMA_BI(p) \ + src0 = h->mc.get_ref( tmp0, &i_stride0, &h->mb.pic.p_fref[0][i_ref0][p*4], h->mb.pic.i_stride[p], \ + mvx0, mvy0, 4*width, 4*height, x264_weight_none ); \ + src1 = h->mc.get_ref( tmp1, &i_stride1, &h->mb.pic.p_fref[1][i_ref1][p*4], h->mb.pic.i_stride[p], \ + mvx1, mvy1, 4*width, 4*height, x264_weight_none ); \ + h->mc.avg[i_mode]( &h->mb.pic.p_fdec[p][4*y*FDEC_STRIDE+4*x], FDEC_STRIDE, \ + src0, i_stride0, src1, i_stride1, weight ); + +static NOINLINE void x264_mb_mc_01xywh( x264_t *h, int x, int y, int width, int height ) +{ + int i8 = x264_scan8[0]+x+8*y; + int i_ref0 = h->mb.cache.ref[0][i8]; + int i_ref1 = h->mb.cache.ref[1][i8]; + int weight = h->mb.bipred_weight[i_ref0][i_ref1]; + int mvx0 = x264_clip3( h->mb.cache.mv[0][i8][0], h->mb.mv_min[0], h->mb.mv_max[0] ) + 4*4*x; + int mvx1 = x264_clip3( h->mb.cache.mv[1][i8][0], h->mb.mv_min[0], h->mb.mv_max[0] ) + 4*4*x; + int mvy0 = x264_clip3( h->mb.cache.mv[0][i8][1], h->mb.mv_min[1], h->mb.mv_max[1] ) + 4*4*y; + int mvy1 = x264_clip3( h->mb.cache.mv[1][i8][1], h->mb.mv_min[1], h->mb.mv_max[1] ) + 4*4*y; + int i_mode = x264_size2pixel[height][width]; + intptr_t i_stride0 = 16, i_stride1 = 16; + ALIGNED_ARRAY_32( pixel, tmp0,[16*16] ); + ALIGNED_ARRAY_32( pixel, tmp1,[16*16] ); + pixel *src0, *src1; + + MC_LUMA_BI( 0 ); + + if( CHROMA444 ) + { + MC_LUMA_BI( 1 ); + MC_LUMA_BI( 2 ); + } + else + { + int v_shift = CHROMA_V_SHIFT; + if( v_shift & MB_INTERLACED & i_ref0 ) + mvy0 += (h->mb.i_mb_y & 1)*4 - 2; + if( v_shift & MB_INTERLACED & i_ref1 ) + mvy1 += (h->mb.i_mb_y & 1)*4 - 2; + + h->mc.mc_chroma( tmp0, tmp0+8, 16, h->mb.pic.p_fref[0][i_ref0][4], h->mb.pic.i_stride[1], + mvx0, 2*mvy0>>v_shift, 2*width, 4*height>>v_shift ); + h->mc.mc_chroma( tmp1, tmp1+8, 16, h->mb.pic.p_fref[1][i_ref1][4], h->mb.pic.i_stride[1], + mvx1, 2*mvy1>>v_shift, 2*width, 4*height>>v_shift ); + + int chromapix = h->luma2chroma_pixel[i_mode]; + int offset = (4*FDEC_STRIDE>>v_shift)*y + 2*x; + h->mc.avg[chromapix]( &h->mb.pic.p_fdec[1][offset], FDEC_STRIDE, tmp0, 16, tmp1, 16, weight ); + h->mc.avg[chromapix]( &h->mb.pic.p_fdec[2][offset], FDEC_STRIDE, tmp0+8, 16, tmp1+8, 16, weight ); + } +} + +#undef MC_LUMA +#undef MC_LUMA_BI + +void x264_mb_mc_8x8( x264_t *h, int i8 ) +{ + int x = 2*(i8&1); + int y = 2*(i8>>1); + + if( h->sh.i_type == SLICE_TYPE_P ) + { + switch( h->mb.i_sub_partition[i8] ) + { + case D_L0_8x8: + x264_mb_mc_0xywh( h, x, y, 2, 2 ); + break; + case D_L0_8x4: + x264_mb_mc_0xywh( h, x, y+0, 2, 1 ); + x264_mb_mc_0xywh( h, x, y+1, 2, 1 ); + break; + case D_L0_4x8: + x264_mb_mc_0xywh( h, x+0, y, 1, 2 ); + x264_mb_mc_0xywh( h, x+1, y, 1, 2 ); + break; + case D_L0_4x4: + x264_mb_mc_0xywh( h, x+0, y+0, 1, 1 ); + x264_mb_mc_0xywh( h, x+1, y+0, 1, 1 ); + x264_mb_mc_0xywh( h, x+0, y+1, 1, 1 ); + x264_mb_mc_0xywh( h, x+1, y+1, 1, 1 ); + break; + } + } + else + { + int scan8 = x264_scan8[0] + x + 8*y; + + if( h->mb.cache.ref[0][scan8] >= 0 ) + if( h->mb.cache.ref[1][scan8] >= 0 ) + x264_mb_mc_01xywh( h, x, y, 2, 2 ); + else + x264_mb_mc_0xywh( h, x, y, 2, 2 ); + else + x264_mb_mc_1xywh( h, x, y, 2, 2 ); + } +} + +void x264_mb_mc( x264_t *h ) +{ + if( h->mb.i_partition == D_8x8 ) + { + for( int i = 0; i < 4; i++ ) + x264_mb_mc_8x8( h, i ); + } + else + { + int ref0a = h->mb.cache.ref[0][x264_scan8[ 0]]; + int ref0b = h->mb.cache.ref[0][x264_scan8[12]]; + int ref1a = h->mb.cache.ref[1][x264_scan8[ 0]]; + int ref1b = h->mb.cache.ref[1][x264_scan8[12]]; + + if( h->mb.i_partition == D_16x16 ) + { + if( ref0a >= 0 ) + if( ref1a >= 0 ) x264_mb_mc_01xywh( h, 0, 0, 4, 4 ); + else x264_mb_mc_0xywh ( h, 0, 0, 4, 4 ); + else x264_mb_mc_1xywh ( h, 0, 0, 4, 4 ); + } + else if( h->mb.i_partition == D_16x8 ) + { + if( ref0a >= 0 ) + if( ref1a >= 0 ) x264_mb_mc_01xywh( h, 0, 0, 4, 2 ); + else x264_mb_mc_0xywh ( h, 0, 0, 4, 2 ); + else x264_mb_mc_1xywh ( h, 0, 0, 4, 2 ); + + if( ref0b >= 0 ) + if( ref1b >= 0 ) x264_mb_mc_01xywh( h, 0, 2, 4, 2 ); + else x264_mb_mc_0xywh ( h, 0, 2, 4, 2 ); + else x264_mb_mc_1xywh ( h, 0, 2, 4, 2 ); + } + else if( h->mb.i_partition == D_8x16 ) + { + if( ref0a >= 0 ) + if( ref1a >= 0 ) x264_mb_mc_01xywh( h, 0, 0, 2, 4 ); + else x264_mb_mc_0xywh ( h, 0, 0, 2, 4 ); + else x264_mb_mc_1xywh ( h, 0, 0, 2, 4 ); + + if( ref0b >= 0 ) + if( ref1b >= 0 ) x264_mb_mc_01xywh( h, 2, 0, 2, 4 ); + else x264_mb_mc_0xywh ( h, 2, 0, 2, 4 ); + else x264_mb_mc_1xywh ( h, 2, 0, 2, 4 ); + } + } +} + +int x264_macroblock_cache_allocate( x264_t *h ) +{ + int i_mb_count = h->mb.i_mb_count; + + h->mb.i_mb_stride = h->mb.i_mb_width; + h->mb.i_b8_stride = h->mb.i_mb_width * 2; + h->mb.i_b4_stride = h->mb.i_mb_width * 4; + + h->mb.b_interlaced = PARAM_INTERLACED; + + PREALLOC_INIT + + PREALLOC( h->mb.qp, i_mb_count * sizeof(int8_t) ); + PREALLOC( h->mb.cbp, i_mb_count * sizeof(int16_t) ); + PREALLOC( h->mb.mb_transform_size, i_mb_count * sizeof(int8_t) ); + PREALLOC( h->mb.slice_table, i_mb_count * sizeof(uint32_t) ); + + /* 0 -> 3 top(4), 4 -> 6 : left(3) */ + PREALLOC( h->mb.intra4x4_pred_mode, i_mb_count * 8 * sizeof(int8_t) ); + + /* all coeffs */ + PREALLOC( h->mb.non_zero_count, i_mb_count * 48 * sizeof(uint8_t) ); + + if( h->param.b_cabac ) + { + PREALLOC( h->mb.skipbp, i_mb_count * sizeof(int8_t) ); + PREALLOC( h->mb.chroma_pred_mode, i_mb_count * sizeof(int8_t) ); + PREALLOC( h->mb.mvd[0], i_mb_count * sizeof( **h->mb.mvd ) ); + if( h->param.i_bframe ) + PREALLOC( h->mb.mvd[1], i_mb_count * sizeof( **h->mb.mvd ) ); + } + + for( int i = 0; i < 2; i++ ) + { + int i_refs = X264_MIN(X264_REF_MAX, (i ? 1 + !!h->param.i_bframe_pyramid : h->param.i_frame_reference) ) << PARAM_INTERLACED; + if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_SMART ) + i_refs = X264_MIN(X264_REF_MAX, i_refs + 1 + (BIT_DEPTH == 8)); //smart weights add two duplicate frames, one in >8-bit + + for( int j = !i; j < i_refs; j++ ) + PREALLOC( h->mb.mvr[i][j], 2 * (i_mb_count + 1) * sizeof(int16_t) ); + } + + if( h->param.analyse.i_weighted_pred ) + { + int i_padv = PADV << PARAM_INTERLACED; + int luma_plane_size = 0; + int numweightbuf; + + if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_FAKE ) + { + // only need buffer for lookahead + if( !h->param.i_sync_lookahead || h == h->thread[h->param.i_threads] ) + { + // Fake analysis only works on lowres + luma_plane_size = h->fdec->i_stride_lowres * (h->mb.i_mb_height*8+2*i_padv); + // Only need 1 buffer for analysis + numweightbuf = 1; + } + else + numweightbuf = 0; + } + else + { + /* Both ref and fenc is stored for 4:2:0 and 4:2:2 which means that 4:2:0 and 4:4:4 + * needs the same amount of space and 4:2:2 needs twice that much */ + luma_plane_size = h->fdec->i_stride[0] * (h->mb.i_mb_height*(16<<(CHROMA_FORMAT==CHROMA_422))+2*i_padv); + + if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_SMART ) + //smart can weight one ref and one offset -1 in 8-bit + numweightbuf = 1 + (BIT_DEPTH == 8); + else + //simple only has one weighted ref + numweightbuf = 1; + } + + for( int i = 0; i < numweightbuf; i++ ) + PREALLOC( h->mb.p_weight_buf[i], luma_plane_size * sizeof(pixel) ); + } + + PREALLOC_END( h->mb.base ); + + memset( h->mb.slice_table, -1, i_mb_count * sizeof(uint32_t) ); + + for( int i = 0; i < 2; i++ ) + { + int i_refs = X264_MIN(X264_REF_MAX, (i ? 1 + !!h->param.i_bframe_pyramid : h->param.i_frame_reference) ) << PARAM_INTERLACED; + if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_SMART ) + i_refs = X264_MIN(X264_REF_MAX, i_refs + 1 + (BIT_DEPTH == 8)); //smart weights add two duplicate frames, one in >8-bit + + for( int j = !i; j < i_refs; j++ ) + { + M32( h->mb.mvr[i][j][0] ) = 0; + h->mb.mvr[i][j]++; + } + } + + return 0; +fail: + return -1; +} +void x264_macroblock_cache_free( x264_t *h ) +{ + x264_free( h->mb.base ); +} + +int x264_macroblock_thread_allocate( x264_t *h, int b_lookahead ) +{ + if( !b_lookahead ) + { + for( int i = 0; i < (PARAM_INTERLACED ? 5 : 2); i++ ) + for( int j = 0; j < (CHROMA444 ? 3 : 2); j++ ) + { + CHECKED_MALLOC( h->intra_border_backup[i][j], (h->sps->i_mb_width*16+32) * sizeof(pixel) ); + h->intra_border_backup[i][j] += 16; + } + for( int i = 0; i <= PARAM_INTERLACED; i++ ) + { + if( h->param.b_sliced_threads ) + { + /* Only allocate the first one, and allocate it for the whole frame, because we + * won't be deblocking until after the frame is fully encoded. */ + if( h == h->thread[0] && !i ) + CHECKED_MALLOC( h->deblock_strength[0], sizeof(**h->deblock_strength) * h->mb.i_mb_count ); + else + h->deblock_strength[i] = h->thread[0]->deblock_strength[0]; + } + else + CHECKED_MALLOC( h->deblock_strength[i], sizeof(**h->deblock_strength) * h->mb.i_mb_width ); + h->deblock_strength[1] = h->deblock_strength[i]; + } + } + + /* Allocate scratch buffer */ + int scratch_size = 0; + if( !b_lookahead ) + { + int buf_hpel = (h->thread[0]->fdec->i_width[0]+48+32) * sizeof(int16_t); + int buf_ssim = h->param.analyse.b_ssim * 8 * (h->param.i_width/4+3) * sizeof(int); + int me_range = X264_MIN(h->param.analyse.i_me_range, h->param.analyse.i_mv_range); + int buf_tesa = (h->param.analyse.i_me_method >= X264_ME_ESA) * + ((me_range*2+24) * sizeof(int16_t) + (me_range+4) * (me_range+1) * 4 * sizeof(mvsad_t)); + scratch_size = X264_MAX3( buf_hpel, buf_ssim, buf_tesa ); + } + int buf_mbtree = h->param.rc.b_mb_tree * ((h->mb.i_mb_width+15)&~15) * sizeof(int16_t); + scratch_size = X264_MAX( scratch_size, buf_mbtree ); + if( scratch_size ) + CHECKED_MALLOC( h->scratch_buffer, scratch_size ); + else + h->scratch_buffer = NULL; + + int buf_lookahead_threads = (h->mb.i_mb_height + (4 + 32) * h->param.i_lookahead_threads) * sizeof(int) * 2; + int buf_mbtree2 = buf_mbtree * 12; /* size of the internal propagate_list asm buffer */ + scratch_size = X264_MAX( buf_lookahead_threads, buf_mbtree2 ); + CHECKED_MALLOC( h->scratch_buffer2, scratch_size ); + + return 0; +fail: + return -1; +} + +void x264_macroblock_thread_free( x264_t *h, int b_lookahead ) +{ + if( !b_lookahead ) + { + for( int i = 0; i <= PARAM_INTERLACED; i++ ) + if( !h->param.b_sliced_threads || (h == h->thread[0] && !i) ) + x264_free( h->deblock_strength[i] ); + for( int i = 0; i < (PARAM_INTERLACED ? 5 : 2); i++ ) + for( int j = 0; j < (CHROMA444 ? 3 : 2); j++ ) + x264_free( h->intra_border_backup[i][j] - 16 ); + } + x264_free( h->scratch_buffer ); + x264_free( h->scratch_buffer2 ); +} + +void x264_macroblock_slice_init( x264_t *h ) +{ + h->mb.mv[0] = h->fdec->mv[0]; + h->mb.mv[1] = h->fdec->mv[1]; + h->mb.mvr[0][0] = h->fdec->mv16x16; + h->mb.ref[0] = h->fdec->ref[0]; + h->mb.ref[1] = h->fdec->ref[1]; + h->mb.type = h->fdec->mb_type; + h->mb.partition = h->fdec->mb_partition; + h->mb.field = h->fdec->field; + + h->fdec->i_ref[0] = h->i_ref[0]; + h->fdec->i_ref[1] = h->i_ref[1]; + for( int i = 0; i < h->i_ref[0]; i++ ) + h->fdec->ref_poc[0][i] = h->fref[0][i]->i_poc; + if( h->sh.i_type == SLICE_TYPE_B ) + { + for( int i = 0; i < h->i_ref[1]; i++ ) + h->fdec->ref_poc[1][i] = h->fref[1][i]->i_poc; + + map_col_to_list0(-1) = -1; + map_col_to_list0(-2) = -2; + for( int i = 0; i < h->fref[1][0]->i_ref[0]; i++ ) + { + int poc = h->fref[1][0]->ref_poc[0][i]; + map_col_to_list0(i) = -2; + for( int j = 0; j < h->i_ref[0]; j++ ) + if( h->fref[0][j]->i_poc == poc ) + { + map_col_to_list0(i) = j; + break; + } + } + } + else if( h->sh.i_type == SLICE_TYPE_P ) + { + if( h->sh.i_disable_deblocking_filter_idc != 1 && h->param.analyse.i_weighted_pred == X264_WEIGHTP_SMART ) + { + deblock_ref_table(-2) = -2; + deblock_ref_table(-1) = -1; + for( int i = 0; i < h->i_ref[0] << SLICE_MBAFF; i++ ) + { + /* Mask off high bits to avoid frame num collisions with -1/-2. + * In current x264 frame num values don't cover a range of more + * than 32, so 6 bits is enough for uniqueness. */ + if( !MB_INTERLACED ) + deblock_ref_table(i) = h->fref[0][i]->i_frame_num&63; + else + deblock_ref_table(i) = ((h->fref[0][i>>1]->i_frame_num&63)<<1) + (i&1); + } + } + } + + /* init with not available (for top right idx=7,15) */ + memset( h->mb.cache.ref, -2, sizeof( h->mb.cache.ref ) ); + + if( h->i_ref[0] > 0 ) + for( int field = 0; field <= SLICE_MBAFF; field++ ) + { + int curpoc = h->fdec->i_poc + h->fdec->i_delta_poc[field]; + int refpoc = h->fref[0][0]->i_poc + h->fref[0][0]->i_delta_poc[field]; + int delta = curpoc - refpoc; + + h->fdec->inv_ref_poc[field] = (256 + delta/2) / delta; + } + + h->mb.i_neighbour4[6] = + h->mb.i_neighbour4[9] = + h->mb.i_neighbour4[12] = + h->mb.i_neighbour4[14] = MB_LEFT|MB_TOP|MB_TOPLEFT|MB_TOPRIGHT; + h->mb.i_neighbour4[3] = + h->mb.i_neighbour4[7] = + h->mb.i_neighbour4[11] = + h->mb.i_neighbour4[13] = + h->mb.i_neighbour4[15] = + h->mb.i_neighbour8[3] = MB_LEFT|MB_TOP|MB_TOPLEFT; +} + +void x264_macroblock_thread_init( x264_t *h ) +{ + h->mb.i_me_method = h->param.analyse.i_me_method; + h->mb.i_subpel_refine = h->param.analyse.i_subpel_refine; + if( h->sh.i_type == SLICE_TYPE_B && (h->mb.i_subpel_refine == 6 || h->mb.i_subpel_refine == 8) ) + h->mb.i_subpel_refine--; + h->mb.b_chroma_me = h->param.analyse.b_chroma_me && + ((h->sh.i_type == SLICE_TYPE_P && h->mb.i_subpel_refine >= 5) || + (h->sh.i_type == SLICE_TYPE_B && h->mb.i_subpel_refine >= 9)); + h->mb.b_dct_decimate = h->sh.i_type == SLICE_TYPE_B || + (h->param.analyse.b_dct_decimate && h->sh.i_type != SLICE_TYPE_I); + h->mb.i_mb_prev_xy = -1; + + /* 4:2:0 4:2:2 4:4:4 + * fdec fenc fdec fenc fdec fenc + * y y y y y y y Y Y Y Y y y y y y y y Y Y Y Y y y y y y y y Y Y Y Y + * y Y Y Y Y Y Y Y Y y Y Y Y Y Y Y Y Y y Y Y Y Y Y Y Y Y + * y Y Y Y Y Y Y Y Y y Y Y Y Y Y Y Y Y y Y Y Y Y Y Y Y Y + * y Y Y Y Y Y Y Y Y y Y Y Y Y Y Y Y Y y Y Y Y Y Y Y Y Y + * y Y Y Y Y U U V V y Y Y Y Y U U V V y Y Y Y Y U U U U + * u u u v v v U U V V u u u v v v U U V V u u u u u u u U U U U + * u U U v V V u U U v V V U U V V u U U U U U U U U + * u U U v V V u U U v V V U U V V u U U U U U U U U + * u U U v V V u U U U U V V V V + * u U U v V V u U U U U V V V V + * v v v v v v v V V V V + * v V V V V V V V V + * v V V V V + * v V V V V + * v V V V V + */ + h->mb.pic.p_fenc[0] = h->mb.pic.fenc_buf; + h->mb.pic.p_fdec[0] = h->mb.pic.fdec_buf + 2*FDEC_STRIDE; + h->mb.pic.p_fenc[1] = h->mb.pic.fenc_buf + 16*FENC_STRIDE; + h->mb.pic.p_fdec[1] = h->mb.pic.fdec_buf + 20*FDEC_STRIDE; + if( CHROMA444 ) + { + h->mb.pic.p_fenc[2] = h->mb.pic.fenc_buf + 32*FENC_STRIDE; + h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 38*FDEC_STRIDE; + } + else + { + h->mb.pic.p_fenc[2] = h->mb.pic.fenc_buf + 16*FENC_STRIDE + 8; + h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 20*FDEC_STRIDE + 16; + } +} + +void x264_prefetch_fenc( x264_t *h, x264_frame_t *fenc, int i_mb_x, int i_mb_y ) +{ + int stride_y = fenc->i_stride[0]; + int stride_uv = fenc->i_stride[1]; + int off_y = 16 * i_mb_x + 16 * i_mb_y * stride_y; + int off_uv = 16 * i_mb_x + (16 * i_mb_y * stride_uv >> CHROMA_V_SHIFT); + h->mc.prefetch_fenc( fenc->plane[0]+off_y, stride_y, + fenc->plane[1]+off_uv, stride_uv, i_mb_x ); +} + +NOINLINE void x264_copy_column8( pixel *dst, pixel *src ) +{ + // input pointers are offset by 4 rows because that's faster (smaller instruction size on x86) + for( int i = -4; i < 4; i++ ) + dst[i*FDEC_STRIDE] = src[i*FDEC_STRIDE]; +} + +static void ALWAYS_INLINE x264_macroblock_load_pic_pointers( x264_t *h, int mb_x, int mb_y, int i, int b_chroma, int b_mbaff ) +{ + int mb_interlaced = b_mbaff && MB_INTERLACED; + int height = b_chroma ? 16 >> CHROMA_V_SHIFT : 16; + int i_stride = h->fdec->i_stride[i]; + int i_stride2 = i_stride << mb_interlaced; + int i_pix_offset = mb_interlaced + ? 16 * mb_x + height * (mb_y&~1) * i_stride + (mb_y&1) * i_stride + : 16 * mb_x + height * mb_y * i_stride; + pixel *plane_fdec = &h->fdec->plane[i][i_pix_offset]; + int fdec_idx = b_mbaff ? (mb_interlaced ? (3 + (mb_y&1)) : (mb_y&1) ? 2 : 4) : !(mb_y&1); + pixel *intra_fdec = &h->intra_border_backup[fdec_idx][i][mb_x*16]; + int ref_pix_offset[2] = { i_pix_offset, i_pix_offset }; + /* ref_pix_offset[0] references the current field and [1] the opposite field. */ + if( mb_interlaced ) + ref_pix_offset[1] += (1-2*(mb_y&1)) * i_stride; + h->mb.pic.i_stride[i] = i_stride2; + h->mb.pic.p_fenc_plane[i] = &h->fenc->plane[i][i_pix_offset]; + if( b_chroma ) + { + h->mc.load_deinterleave_chroma_fenc( h->mb.pic.p_fenc[1], h->mb.pic.p_fenc_plane[1], i_stride2, height ); + memcpy( h->mb.pic.p_fdec[1]-FDEC_STRIDE, intra_fdec, 8*sizeof(pixel) ); + memcpy( h->mb.pic.p_fdec[2]-FDEC_STRIDE, intra_fdec+8, 8*sizeof(pixel) ); + h->mb.pic.p_fdec[1][-FDEC_STRIDE-1] = intra_fdec[-1-8]; + h->mb.pic.p_fdec[2][-FDEC_STRIDE-1] = intra_fdec[-1]; + } + else + { + h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fenc[i], FENC_STRIDE, h->mb.pic.p_fenc_plane[i], i_stride2, 16 ); + memcpy( h->mb.pic.p_fdec[i]-FDEC_STRIDE, intra_fdec, 24*sizeof(pixel) ); + h->mb.pic.p_fdec[i][-FDEC_STRIDE-1] = intra_fdec[-1]; + } + if( b_mbaff || h->mb.b_reencode_mb ) + { + for( int j = 0; j < height; j++ ) + if( b_chroma ) + { + h->mb.pic.p_fdec[1][-1+j*FDEC_STRIDE] = plane_fdec[-2+j*i_stride2]; + h->mb.pic.p_fdec[2][-1+j*FDEC_STRIDE] = plane_fdec[-1+j*i_stride2]; + } + else + h->mb.pic.p_fdec[i][-1+j*FDEC_STRIDE] = plane_fdec[-1+j*i_stride2]; + } + pixel *plane_src, **filtered_src; + for( int j = 0; j < h->mb.pic.i_fref[0]; j++ ) + { + // Interpolate between pixels in same field. + if( mb_interlaced ) + { + plane_src = h->fref[0][j>>1]->plane_fld[i]; + filtered_src = h->fref[0][j>>1]->filtered_fld[i]; + } + else + { + plane_src = h->fref[0][j]->plane[i]; + filtered_src = h->fref[0][j]->filtered[i]; + } + h->mb.pic.p_fref[0][j][i*4] = plane_src + ref_pix_offset[j&1]; + + if( !b_chroma ) + { + for( int k = 1; k < 4; k++ ) + h->mb.pic.p_fref[0][j][i*4+k] = filtered_src[k] + ref_pix_offset[j&1]; + if( !i ) + { + if( h->sh.weight[j][0].weightfn ) + h->mb.pic.p_fref_w[j] = &h->fenc->weighted[j >> mb_interlaced][ref_pix_offset[j&1]]; + else + h->mb.pic.p_fref_w[j] = h->mb.pic.p_fref[0][j][0]; + } + } + } + if( h->sh.i_type == SLICE_TYPE_B ) + for( int j = 0; j < h->mb.pic.i_fref[1]; j++ ) + { + if( mb_interlaced ) + { + plane_src = h->fref[1][j>>1]->plane_fld[i]; + filtered_src = h->fref[1][j>>1]->filtered_fld[i]; + } + else + { + plane_src = h->fref[1][j]->plane[i]; + filtered_src = h->fref[1][j]->filtered[i]; + } + h->mb.pic.p_fref[1][j][i*4] = plane_src + ref_pix_offset[j&1]; + + if( !b_chroma ) + for( int k = 1; k < 4; k++ ) + h->mb.pic.p_fref[1][j][i*4+k] = filtered_src[k] + ref_pix_offset[j&1]; + } +} + +static const x264_left_table_t left_indices[4] = +{ + /* Current is progressive */ + {{ 4, 4, 5, 5}, { 3, 3, 7, 7}, {16+1, 16+1, 32+1, 32+1}, {0, 0, 1, 1}, {0, 0, 0, 0}}, + {{ 6, 6, 3, 3}, {11, 11, 15, 15}, {16+5, 16+5, 32+5, 32+5}, {2, 2, 3, 3}, {1, 1, 1, 1}}, + /* Current is interlaced */ + {{ 4, 6, 4, 6}, { 3, 11, 3, 11}, {16+1, 16+1, 32+1, 32+1}, {0, 2, 0, 2}, {0, 1, 0, 1}}, + /* Both same */ + {{ 4, 5, 6, 3}, { 3, 7, 11, 15}, {16+1, 16+5, 32+1, 32+5}, {0, 1, 2, 3}, {0, 0, 1, 1}} +}; + +static void ALWAYS_INLINE x264_macroblock_cache_load_neighbours( x264_t *h, int mb_x, int mb_y, int b_interlaced ) +{ + const int mb_interlaced = b_interlaced && MB_INTERLACED; + int top_y = mb_y - (1 << mb_interlaced); + int top = top_y * h->mb.i_mb_stride + mb_x; + + h->mb.i_mb_x = mb_x; + h->mb.i_mb_y = mb_y; + h->mb.i_mb_xy = mb_y * h->mb.i_mb_stride + mb_x; + h->mb.i_b8_xy = 2*(mb_y * h->mb.i_b8_stride + mb_x); + h->mb.i_b4_xy = 4*(mb_y * h->mb.i_b4_stride + mb_x); + h->mb.left_b8[0] = + h->mb.left_b8[1] = -1; + h->mb.left_b4[0] = + h->mb.left_b4[1] = -1; + h->mb.i_neighbour = 0; + h->mb.i_neighbour_intra = 0; + h->mb.i_neighbour_frame = 0; + h->mb.i_mb_top_xy = -1; + h->mb.i_mb_top_y = -1; + h->mb.i_mb_left_xy[0] = h->mb.i_mb_left_xy[1] = -1; + h->mb.i_mb_topleft_xy = -1; + h->mb.i_mb_topright_xy = -1; + h->mb.i_mb_type_top = -1; + h->mb.i_mb_type_left[0] = h->mb.i_mb_type_left[1] = -1; + h->mb.i_mb_type_topleft = -1; + h->mb.i_mb_type_topright = -1; + h->mb.left_index_table = &left_indices[3]; + h->mb.topleft_partition = 0; + + int topleft_y = top_y; + int topright_y = top_y; + int left[2]; + + left[0] = left[1] = h->mb.i_mb_xy - 1; + h->mb.left_b8[0] = h->mb.left_b8[1] = h->mb.i_b8_xy - 2; + h->mb.left_b4[0] = h->mb.left_b4[1] = h->mb.i_b4_xy - 4; + + if( b_interlaced ) + { + h->mb.i_mb_top_mbpair_xy = h->mb.i_mb_xy - 2*h->mb.i_mb_stride; + h->mb.i_mb_topleft_y = -1; + h->mb.i_mb_topright_y = -1; + + if( mb_y&1 ) + { + if( mb_x && mb_interlaced != h->mb.field[h->mb.i_mb_xy-1] ) + { + left[0] = left[1] = h->mb.i_mb_xy - 1 - h->mb.i_mb_stride; + h->mb.left_b8[0] = h->mb.left_b8[1] = h->mb.i_b8_xy - 2 - 2*h->mb.i_b8_stride; + h->mb.left_b4[0] = h->mb.left_b4[1] = h->mb.i_b4_xy - 4 - 4*h->mb.i_b4_stride; + + if( mb_interlaced ) + { + h->mb.left_index_table = &left_indices[2]; + left[1] += h->mb.i_mb_stride; + h->mb.left_b8[1] += 2*h->mb.i_b8_stride; + h->mb.left_b4[1] += 4*h->mb.i_b4_stride; + } + else + { + h->mb.left_index_table = &left_indices[1]; + topleft_y++; + h->mb.topleft_partition = 1; + } + } + if( !mb_interlaced ) + topright_y = -1; + } + else + { + if( mb_interlaced && top >= 0 ) + { + if( !h->mb.field[top] ) + { + top += h->mb.i_mb_stride; + top_y++; + } + if( mb_x ) + topleft_y += !h->mb.field[h->mb.i_mb_stride*topleft_y + mb_x - 1]; + if( mb_x < h->mb.i_mb_width-1 ) + topright_y += !h->mb.field[h->mb.i_mb_stride*topright_y + mb_x + 1]; + } + if( mb_x && mb_interlaced != h->mb.field[h->mb.i_mb_xy-1] ) + { + if( mb_interlaced ) + { + h->mb.left_index_table = &left_indices[2]; + left[1] += h->mb.i_mb_stride; + h->mb.left_b8[1] += 2*h->mb.i_b8_stride; + h->mb.left_b4[1] += 4*h->mb.i_b4_stride; + } + else + h->mb.left_index_table = &left_indices[0]; + } + } + } + + if( mb_x > 0 ) + { + h->mb.i_neighbour_frame |= MB_LEFT; + h->mb.i_mb_left_xy[0] = left[0]; + h->mb.i_mb_left_xy[1] = left[1]; + h->mb.i_mb_type_left[0] = h->mb.type[h->mb.i_mb_left_xy[0]]; + h->mb.i_mb_type_left[1] = h->mb.type[h->mb.i_mb_left_xy[1]]; + if( h->mb.slice_table[left[0]] == h->sh.i_first_mb ) + { + h->mb.i_neighbour |= MB_LEFT; + + // FIXME: We don't currently support constrained intra + mbaff. + if( !h->param.b_constrained_intra || IS_INTRA( h->mb.i_mb_type_left[0] ) ) + h->mb.i_neighbour_intra |= MB_LEFT; + } + } + + /* We can't predict from the previous threadslice since it hasn't been encoded yet. */ + if( (h->i_threadslice_start >> mb_interlaced) != (mb_y >> mb_interlaced) ) + { + if( top >= 0 ) + { + h->mb.i_neighbour_frame |= MB_TOP; + h->mb.i_mb_top_xy = top; + h->mb.i_mb_top_y = top_y; + h->mb.i_mb_type_top = h->mb.type[h->mb.i_mb_top_xy]; + if( h->mb.slice_table[top] == h->sh.i_first_mb ) + { + h->mb.i_neighbour |= MB_TOP; + + if( !h->param.b_constrained_intra || IS_INTRA( h->mb.i_mb_type_top ) ) + h->mb.i_neighbour_intra |= MB_TOP; + + /* We only need to prefetch the top blocks because the left was just written + * to as part of the previous cache_save. Since most target CPUs use write-allocate + * caches, left blocks are near-guaranteed to be in L1 cache. Top--not so much. */ + x264_prefetch( &h->mb.cbp[top] ); + x264_prefetch( h->mb.intra4x4_pred_mode[top] ); + x264_prefetch( &h->mb.non_zero_count[top][12] ); + /* These aren't always allocated, but prefetching an invalid address can't hurt. */ + x264_prefetch( &h->mb.mb_transform_size[top] ); + x264_prefetch( &h->mb.skipbp[top] ); + } + } + + if( mb_x > 0 && topleft_y >= 0 ) + { + h->mb.i_neighbour_frame |= MB_TOPLEFT; + h->mb.i_mb_topleft_xy = h->mb.i_mb_stride*topleft_y + mb_x - 1; + h->mb.i_mb_topleft_y = topleft_y; + h->mb.i_mb_type_topleft = h->mb.type[h->mb.i_mb_topleft_xy]; + if( h->mb.slice_table[h->mb.i_mb_topleft_xy] == h->sh.i_first_mb ) + { + h->mb.i_neighbour |= MB_TOPLEFT; + + if( !h->param.b_constrained_intra || IS_INTRA( h->mb.i_mb_type_topleft ) ) + h->mb.i_neighbour_intra |= MB_TOPLEFT; + } + } + + if( mb_x < h->mb.i_mb_width - 1 && topright_y >= 0 ) + { + h->mb.i_neighbour_frame |= MB_TOPRIGHT; + h->mb.i_mb_topright_xy = h->mb.i_mb_stride*topright_y + mb_x + 1; + h->mb.i_mb_topright_y = topright_y; + h->mb.i_mb_type_topright = h->mb.type[h->mb.i_mb_topright_xy]; + if( h->mb.slice_table[h->mb.i_mb_topright_xy] == h->sh.i_first_mb ) + { + h->mb.i_neighbour |= MB_TOPRIGHT; + + if( !h->param.b_constrained_intra || IS_INTRA( h->mb.i_mb_type_topright ) ) + h->mb.i_neighbour_intra |= MB_TOPRIGHT; + } + } + } +} + +#define LTOP 0 +#if HAVE_INTERLACED +# define LBOT 1 +#else +# define LBOT 0 +#endif + +static void ALWAYS_INLINE x264_macroblock_cache_load( x264_t *h, int mb_x, int mb_y, int b_mbaff ) +{ + x264_macroblock_cache_load_neighbours( h, mb_x, mb_y, b_mbaff ); + + int *left = h->mb.i_mb_left_xy; + int top = h->mb.i_mb_top_xy; + int top_y = h->mb.i_mb_top_y; + int s8x8 = h->mb.i_b8_stride; + int s4x4 = h->mb.i_b4_stride; + int top_8x8 = (2*top_y+1) * s8x8 + 2*mb_x; + int top_4x4 = (4*top_y+3) * s4x4 + 4*mb_x; + int lists = (1 << h->sh.i_type) & 3; + + /* GCC pessimizes direct loads from heap-allocated arrays due to aliasing. */ + /* By only dereferencing them once, we avoid this issue. */ + int8_t (*i4x4)[8] = h->mb.intra4x4_pred_mode; + uint8_t (*nnz)[48] = h->mb.non_zero_count; + int16_t *cbp = h->mb.cbp; + + const x264_left_table_t *left_index_table = h->mb.left_index_table; + + h->mb.cache.deblock_strength = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?h->mb.i_mb_xy:mb_x]; + + /* load cache */ + if( h->mb.i_neighbour & MB_TOP ) + { + h->mb.cache.i_cbp_top = cbp[top]; + /* load intra4x4 */ + CP32( &h->mb.cache.intra4x4_pred_mode[x264_scan8[0] - 8], &i4x4[top][0] ); + + /* load non_zero_count */ + CP32( &h->mb.cache.non_zero_count[x264_scan8[ 0] - 8], &nnz[top][12] ); + CP32( &h->mb.cache.non_zero_count[x264_scan8[16] - 8], &nnz[top][16-4 + (16>>CHROMA_V_SHIFT)] ); + CP32( &h->mb.cache.non_zero_count[x264_scan8[32] - 8], &nnz[top][32-4 + (16>>CHROMA_V_SHIFT)] ); + + /* Finish the prefetching */ + for( int l = 0; l < lists; l++ ) + { + x264_prefetch( &h->mb.mv[l][top_4x4-1] ); + /* Top right being not in the same cacheline as top left will happen + * once every 4 MBs, so one extra prefetch is worthwhile */ + x264_prefetch( &h->mb.mv[l][top_4x4+4] ); + x264_prefetch( &h->mb.ref[l][top_8x8-1] ); + x264_prefetch( &h->mb.mvd[l][top] ); + } + } + else + { + h->mb.cache.i_cbp_top = -1; + + /* load intra4x4 */ + M32( &h->mb.cache.intra4x4_pred_mode[x264_scan8[0] - 8] ) = 0xFFFFFFFFU; + + /* load non_zero_count */ + M32( &h->mb.cache.non_zero_count[x264_scan8[ 0] - 8] ) = 0x80808080U; + M32( &h->mb.cache.non_zero_count[x264_scan8[16] - 8] ) = 0x80808080U; + M32( &h->mb.cache.non_zero_count[x264_scan8[32] - 8] ) = 0x80808080U; + } + + if( h->mb.i_neighbour & MB_LEFT ) + { + int ltop = left[LTOP]; + int lbot = b_mbaff ? left[LBOT] : ltop; + if( b_mbaff ) + { + const int16_t top_luma = (cbp[ltop] >> (left_index_table->mv[0]&(~1))) & 2; + const int16_t bot_luma = (cbp[lbot] >> (left_index_table->mv[2]&(~1))) & 2; + h->mb.cache.i_cbp_left = (cbp[ltop] & 0xfff0) | (bot_luma<<2) | top_luma; + } + else + h->mb.cache.i_cbp_left = cbp[ltop]; + + /* load intra4x4 */ + h->mb.cache.intra4x4_pred_mode[x264_scan8[ 0] - 1] = i4x4[ltop][left_index_table->intra[0]]; + h->mb.cache.intra4x4_pred_mode[x264_scan8[ 2] - 1] = i4x4[ltop][left_index_table->intra[1]]; + h->mb.cache.intra4x4_pred_mode[x264_scan8[ 8] - 1] = i4x4[lbot][left_index_table->intra[2]]; + h->mb.cache.intra4x4_pred_mode[x264_scan8[10] - 1] = i4x4[lbot][left_index_table->intra[3]]; + + /* load non_zero_count */ + h->mb.cache.non_zero_count[x264_scan8[ 0] - 1] = nnz[ltop][left_index_table->nnz[0]]; + h->mb.cache.non_zero_count[x264_scan8[ 2] - 1] = nnz[ltop][left_index_table->nnz[1]]; + h->mb.cache.non_zero_count[x264_scan8[ 8] - 1] = nnz[lbot][left_index_table->nnz[2]]; + h->mb.cache.non_zero_count[x264_scan8[10] - 1] = nnz[lbot][left_index_table->nnz[3]]; + + if( CHROMA_FORMAT >= CHROMA_422 ) + { + int offset = (4>>CHROMA_H_SHIFT) - 4; + h->mb.cache.non_zero_count[x264_scan8[16+ 0] - 1] = nnz[ltop][left_index_table->nnz[0]+16+offset]; + h->mb.cache.non_zero_count[x264_scan8[16+ 2] - 1] = nnz[ltop][left_index_table->nnz[1]+16+offset]; + h->mb.cache.non_zero_count[x264_scan8[16+ 8] - 1] = nnz[lbot][left_index_table->nnz[2]+16+offset]; + h->mb.cache.non_zero_count[x264_scan8[16+10] - 1] = nnz[lbot][left_index_table->nnz[3]+16+offset]; + h->mb.cache.non_zero_count[x264_scan8[32+ 0] - 1] = nnz[ltop][left_index_table->nnz[0]+32+offset]; + h->mb.cache.non_zero_count[x264_scan8[32+ 2] - 1] = nnz[ltop][left_index_table->nnz[1]+32+offset]; + h->mb.cache.non_zero_count[x264_scan8[32+ 8] - 1] = nnz[lbot][left_index_table->nnz[2]+32+offset]; + h->mb.cache.non_zero_count[x264_scan8[32+10] - 1] = nnz[lbot][left_index_table->nnz[3]+32+offset]; + } + else + { + h->mb.cache.non_zero_count[x264_scan8[16+ 0] - 1] = nnz[ltop][left_index_table->nnz_chroma[0]]; + h->mb.cache.non_zero_count[x264_scan8[16+ 2] - 1] = nnz[lbot][left_index_table->nnz_chroma[1]]; + h->mb.cache.non_zero_count[x264_scan8[32+ 0] - 1] = nnz[ltop][left_index_table->nnz_chroma[2]]; + h->mb.cache.non_zero_count[x264_scan8[32+ 2] - 1] = nnz[lbot][left_index_table->nnz_chroma[3]]; + } + } + else + { + h->mb.cache.i_cbp_left = -1; + + h->mb.cache.intra4x4_pred_mode[x264_scan8[ 0] - 1] = + h->mb.cache.intra4x4_pred_mode[x264_scan8[ 2] - 1] = + h->mb.cache.intra4x4_pred_mode[x264_scan8[ 8] - 1] = + h->mb.cache.intra4x4_pred_mode[x264_scan8[10] - 1] = -1; + + /* load non_zero_count */ + h->mb.cache.non_zero_count[x264_scan8[ 0] - 1] = + h->mb.cache.non_zero_count[x264_scan8[ 2] - 1] = + h->mb.cache.non_zero_count[x264_scan8[ 8] - 1] = + h->mb.cache.non_zero_count[x264_scan8[10] - 1] = + h->mb.cache.non_zero_count[x264_scan8[16+ 0] - 1] = + h->mb.cache.non_zero_count[x264_scan8[16+ 2] - 1] = + h->mb.cache.non_zero_count[x264_scan8[32+ 0] - 1] = + h->mb.cache.non_zero_count[x264_scan8[32+ 2] - 1] = 0x80; + if( CHROMA_FORMAT >= CHROMA_422 ) + { + h->mb.cache.non_zero_count[x264_scan8[16+ 8] - 1] = + h->mb.cache.non_zero_count[x264_scan8[16+10] - 1] = + h->mb.cache.non_zero_count[x264_scan8[32+ 8] - 1] = + h->mb.cache.non_zero_count[x264_scan8[32+10] - 1] = 0x80; + } + } + + if( h->pps->b_transform_8x8_mode ) + { + h->mb.cache.i_neighbour_transform_size = + ( (h->mb.i_neighbour & MB_LEFT) && h->mb.mb_transform_size[left[0]] ) + + ( (h->mb.i_neighbour & MB_TOP) && h->mb.mb_transform_size[top] ); + } + + if( b_mbaff ) + { + h->mb.pic.i_fref[0] = h->i_ref[0] << MB_INTERLACED; + h->mb.pic.i_fref[1] = h->i_ref[1] << MB_INTERLACED; + } + + if( !b_mbaff ) + { + x264_copy_column8( h->mb.pic.p_fdec[0]-1+ 4*FDEC_STRIDE, h->mb.pic.p_fdec[0]+15+ 4*FDEC_STRIDE ); + x264_copy_column8( h->mb.pic.p_fdec[0]-1+12*FDEC_STRIDE, h->mb.pic.p_fdec[0]+15+12*FDEC_STRIDE ); + x264_macroblock_load_pic_pointers( h, mb_x, mb_y, 0, 0, 0 ); + if( CHROMA444 ) + { + x264_copy_column8( h->mb.pic.p_fdec[1]-1+ 4*FDEC_STRIDE, h->mb.pic.p_fdec[1]+15+ 4*FDEC_STRIDE ); + x264_copy_column8( h->mb.pic.p_fdec[1]-1+12*FDEC_STRIDE, h->mb.pic.p_fdec[1]+15+12*FDEC_STRIDE ); + x264_copy_column8( h->mb.pic.p_fdec[2]-1+ 4*FDEC_STRIDE, h->mb.pic.p_fdec[2]+15+ 4*FDEC_STRIDE ); + x264_copy_column8( h->mb.pic.p_fdec[2]-1+12*FDEC_STRIDE, h->mb.pic.p_fdec[2]+15+12*FDEC_STRIDE ); + x264_macroblock_load_pic_pointers( h, mb_x, mb_y, 1, 0, 0 ); + x264_macroblock_load_pic_pointers( h, mb_x, mb_y, 2, 0, 0 ); + } + else + { + x264_copy_column8( h->mb.pic.p_fdec[1]-1+ 4*FDEC_STRIDE, h->mb.pic.p_fdec[1]+ 7+ 4*FDEC_STRIDE ); + x264_copy_column8( h->mb.pic.p_fdec[2]-1+ 4*FDEC_STRIDE, h->mb.pic.p_fdec[2]+ 7+ 4*FDEC_STRIDE ); + if( CHROMA_FORMAT == CHROMA_422 ) + { + x264_copy_column8( h->mb.pic.p_fdec[1]-1+12*FDEC_STRIDE, h->mb.pic.p_fdec[1]+ 7+12*FDEC_STRIDE ); + x264_copy_column8( h->mb.pic.p_fdec[2]-1+12*FDEC_STRIDE, h->mb.pic.p_fdec[2]+ 7+12*FDEC_STRIDE ); + } + x264_macroblock_load_pic_pointers( h, mb_x, mb_y, 1, 1, 0 ); + } + } + else + { + x264_macroblock_load_pic_pointers( h, mb_x, mb_y, 0, 0, 1 ); + if( CHROMA444 ) + { + x264_macroblock_load_pic_pointers( h, mb_x, mb_y, 1, 0, 1 ); + x264_macroblock_load_pic_pointers( h, mb_x, mb_y, 2, 0, 1 ); + } + else + x264_macroblock_load_pic_pointers( h, mb_x, mb_y, 1, 1, 1 ); + } + + if( h->fdec->integral ) + { + int offset = 16 * (mb_x + mb_y * h->fdec->i_stride[0]); + for( int list = 0; list < 2; list++ ) + for( int i = 0; i < h->mb.pic.i_fref[list]; i++ ) + h->mb.pic.p_integral[list][i] = &h->fref[list][i]->integral[offset]; + } + + x264_prefetch_fenc( h, h->fenc, mb_x, mb_y ); + + /* load ref/mv/mvd */ + for( int l = 0; l < lists; l++ ) + { + int16_t (*mv)[2] = h->mb.mv[l]; + int8_t *ref = h->mb.ref[l]; + + int i8 = x264_scan8[0] - 1 - 1*8; + if( h->mb.i_neighbour & MB_TOPLEFT ) + { + int ir = b_mbaff ? 2*(s8x8*h->mb.i_mb_topleft_y + mb_x-1)+1+s8x8 : top_8x8 - 1; + int iv = b_mbaff ? 4*(s4x4*h->mb.i_mb_topleft_y + mb_x-1)+3+3*s4x4 : top_4x4 - 1; + if( b_mbaff && h->mb.topleft_partition ) + { + /* Take motion vector from the middle of macroblock instead of + * the bottom right as usual. */ + iv -= 2*s4x4; + ir -= s8x8; + } + h->mb.cache.ref[l][i8] = ref[ir]; + CP32( h->mb.cache.mv[l][i8], mv[iv] ); + } + else + { + h->mb.cache.ref[l][i8] = -2; + M32( h->mb.cache.mv[l][i8] ) = 0; + } + + i8 = x264_scan8[0] - 8; + if( h->mb.i_neighbour & MB_TOP ) + { + h->mb.cache.ref[l][i8+0] = + h->mb.cache.ref[l][i8+1] = ref[top_8x8 + 0]; + h->mb.cache.ref[l][i8+2] = + h->mb.cache.ref[l][i8+3] = ref[top_8x8 + 1]; + CP128( h->mb.cache.mv[l][i8], mv[top_4x4] ); + } + else + { + M128( h->mb.cache.mv[l][i8] ) = M128_ZERO; + M32( &h->mb.cache.ref[l][i8] ) = (uint8_t)(-2) * 0x01010101U; + } + + i8 = x264_scan8[0] + 4 - 1*8; + if( h->mb.i_neighbour & MB_TOPRIGHT ) + { + int ir = b_mbaff ? 2*(s8x8*h->mb.i_mb_topright_y + (mb_x+1))+s8x8 : top_8x8 + 2; + int iv = b_mbaff ? 4*(s4x4*h->mb.i_mb_topright_y + (mb_x+1))+3*s4x4 : top_4x4 + 4; + h->mb.cache.ref[l][i8] = ref[ir]; + CP32( h->mb.cache.mv[l][i8], mv[iv] ); + } + else + h->mb.cache.ref[l][i8] = -2; + + i8 = x264_scan8[0] - 1; + if( h->mb.i_neighbour & MB_LEFT ) + { + if( b_mbaff ) + { + h->mb.cache.ref[l][i8+0*8] = ref[h->mb.left_b8[LTOP] + 1 + s8x8*left_index_table->ref[0]]; + h->mb.cache.ref[l][i8+1*8] = ref[h->mb.left_b8[LTOP] + 1 + s8x8*left_index_table->ref[1]]; + h->mb.cache.ref[l][i8+2*8] = ref[h->mb.left_b8[LBOT] + 1 + s8x8*left_index_table->ref[2]]; + h->mb.cache.ref[l][i8+3*8] = ref[h->mb.left_b8[LBOT] + 1 + s8x8*left_index_table->ref[3]]; + + CP32( h->mb.cache.mv[l][i8+0*8], mv[h->mb.left_b4[LTOP] + 3 + s4x4*left_index_table->mv[0]] ); + CP32( h->mb.cache.mv[l][i8+1*8], mv[h->mb.left_b4[LTOP] + 3 + s4x4*left_index_table->mv[1]] ); + CP32( h->mb.cache.mv[l][i8+2*8], mv[h->mb.left_b4[LBOT] + 3 + s4x4*left_index_table->mv[2]] ); + CP32( h->mb.cache.mv[l][i8+3*8], mv[h->mb.left_b4[LBOT] + 3 + s4x4*left_index_table->mv[3]] ); + } + else + { + const int ir = h->mb.i_b8_xy - 1; + const int iv = h->mb.i_b4_xy - 1; + h->mb.cache.ref[l][i8+0*8] = + h->mb.cache.ref[l][i8+1*8] = ref[ir + 0*s8x8]; + h->mb.cache.ref[l][i8+2*8] = + h->mb.cache.ref[l][i8+3*8] = ref[ir + 1*s8x8]; + + CP32( h->mb.cache.mv[l][i8+0*8], mv[iv + 0*s4x4] ); + CP32( h->mb.cache.mv[l][i8+1*8], mv[iv + 1*s4x4] ); + CP32( h->mb.cache.mv[l][i8+2*8], mv[iv + 2*s4x4] ); + CP32( h->mb.cache.mv[l][i8+3*8], mv[iv + 3*s4x4] ); + } + } + else + { + for( int i = 0; i < 4; i++ ) + { + h->mb.cache.ref[l][i8+i*8] = -2; + M32( h->mb.cache.mv[l][i8+i*8] ) = 0; + } + } + + /* Extra logic for top right mv in mbaff. + * . . . d . . a . + * . . . e . . . . + * . . . f b . c . + * . . . . . . . . + * + * If the top right of the 4x4 partitions labeled a, b and c in the + * above diagram do not exist, but the entries d, e and f exist (in + * the macroblock to the left) then use those instead. + */ + if( b_mbaff && (h->mb.i_neighbour & MB_LEFT) ) + { + if( MB_INTERLACED && !h->mb.field[h->mb.i_mb_xy-1] ) + { + h->mb.cache.topright_ref[l][0] = ref[h->mb.left_b8[0] + 1 + s8x8*0]; + h->mb.cache.topright_ref[l][1] = ref[h->mb.left_b8[0] + 1 + s8x8*1]; + h->mb.cache.topright_ref[l][2] = ref[h->mb.left_b8[1] + 1 + s8x8*0]; + CP32( h->mb.cache.topright_mv[l][0], mv[h->mb.left_b4[0] + 3 + s4x4*(left_index_table->mv[0]+1)] ); + CP32( h->mb.cache.topright_mv[l][1], mv[h->mb.left_b4[0] + 3 + s4x4*(left_index_table->mv[1]+1)] ); + CP32( h->mb.cache.topright_mv[l][2], mv[h->mb.left_b4[1] + 3 + s4x4*(left_index_table->mv[2]+1)] ); + } + else if( !MB_INTERLACED && h->mb.field[h->mb.i_mb_xy-1] ) + { + // Looking at the bottom field so always take the bottom macroblock of the pair. + h->mb.cache.topright_ref[l][0] = ref[h->mb.left_b8[0] + 1 + s8x8*2 + s8x8*left_index_table->ref[0]]; + h->mb.cache.topright_ref[l][1] = ref[h->mb.left_b8[0] + 1 + s8x8*2 + s8x8*left_index_table->ref[1]]; + h->mb.cache.topright_ref[l][2] = ref[h->mb.left_b8[0] + 1 + s8x8*2 + s8x8*left_index_table->ref[2]]; + CP32( h->mb.cache.topright_mv[l][0], mv[h->mb.left_b4[0] + 3 + s4x4*4 + s4x4*left_index_table->mv[0]] ); + CP32( h->mb.cache.topright_mv[l][1], mv[h->mb.left_b4[0] + 3 + s4x4*4 + s4x4*left_index_table->mv[1]] ); + CP32( h->mb.cache.topright_mv[l][2], mv[h->mb.left_b4[0] + 3 + s4x4*4 + s4x4*left_index_table->mv[2]] ); + } + } + + if( h->param.b_cabac ) + { + uint8_t (*mvd)[8][2] = h->mb.mvd[l]; + if( h->mb.i_neighbour & MB_TOP ) + CP64( h->mb.cache.mvd[l][x264_scan8[0] - 8], mvd[top][0] ); + else + M64( h->mb.cache.mvd[l][x264_scan8[0] - 8] ) = 0; + + if( h->mb.i_neighbour & MB_LEFT && (!b_mbaff || h->mb.cache.ref[l][x264_scan8[0]-1] >= 0) ) + { + CP16( h->mb.cache.mvd[l][x264_scan8[0 ] - 1], mvd[left[LTOP]][left_index_table->intra[0]] ); + CP16( h->mb.cache.mvd[l][x264_scan8[2 ] - 1], mvd[left[LTOP]][left_index_table->intra[1]] ); + } + else + { + M16( h->mb.cache.mvd[l][x264_scan8[0]-1+0*8] ) = 0; + M16( h->mb.cache.mvd[l][x264_scan8[0]-1+1*8] ) = 0; + } + if( h->mb.i_neighbour & MB_LEFT && (!b_mbaff || h->mb.cache.ref[l][x264_scan8[0]-1+2*8] >= 0) ) + { + CP16( h->mb.cache.mvd[l][x264_scan8[8 ] - 1], mvd[left[LBOT]][left_index_table->intra[2]] ); + CP16( h->mb.cache.mvd[l][x264_scan8[10] - 1], mvd[left[LBOT]][left_index_table->intra[3]] ); + } + else + { + M16( h->mb.cache.mvd[l][x264_scan8[0]-1+2*8] ) = 0; + M16( h->mb.cache.mvd[l][x264_scan8[0]-1+3*8] ) = 0; + } + } + + /* If motion vectors are cached from frame macroblocks but this + * macroblock is a field macroblock then the motion vector must be + * halved. Similarly, motion vectors from field macroblocks are doubled. */ + if( b_mbaff ) + { +#define MAP_MVS\ + if( FIELD_DIFFERENT(h->mb.i_mb_topleft_xy) )\ + MAP_F2F(mv, ref, x264_scan8[0] - 1 - 1*8)\ + if( FIELD_DIFFERENT(top) )\ + {\ + MAP_F2F(mv, ref, x264_scan8[0] + 0 - 1*8)\ + MAP_F2F(mv, ref, x264_scan8[0] + 1 - 1*8)\ + MAP_F2F(mv, ref, x264_scan8[0] + 2 - 1*8)\ + MAP_F2F(mv, ref, x264_scan8[0] + 3 - 1*8)\ + }\ + if( FIELD_DIFFERENT(h->mb.i_mb_topright_xy) )\ + MAP_F2F(mv, ref, x264_scan8[0] + 4 - 1*8)\ + if( FIELD_DIFFERENT(left[0]) )\ + {\ + MAP_F2F(mv, ref, x264_scan8[0] - 1 + 0*8)\ + MAP_F2F(mv, ref, x264_scan8[0] - 1 + 1*8)\ + MAP_F2F(mv, ref, x264_scan8[0] - 1 + 2*8)\ + MAP_F2F(mv, ref, x264_scan8[0] - 1 + 3*8)\ + MAP_F2F(topright_mv, topright_ref, 0)\ + MAP_F2F(topright_mv, topright_ref, 1)\ + MAP_F2F(topright_mv, topright_ref, 2)\ + } + + if( MB_INTERLACED ) + { +#define FIELD_DIFFERENT(macroblock) (macroblock >= 0 && !h->mb.field[macroblock]) +#define MAP_F2F(varmv, varref, index)\ + if( h->mb.cache.varref[l][index] >= 0 )\ + {\ + h->mb.cache.varref[l][index] <<= 1;\ + h->mb.cache.varmv[l][index][1] /= 2;\ + h->mb.cache.mvd[l][index][1] >>= 1;\ + } + MAP_MVS +#undef MAP_F2F +#undef FIELD_DIFFERENT + } + else + { +#define FIELD_DIFFERENT(macroblock) (macroblock >= 0 && h->mb.field[macroblock]) +#define MAP_F2F(varmv, varref, index)\ + if( h->mb.cache.varref[l][index] >= 0 )\ + {\ + h->mb.cache.varref[l][index] >>= 1;\ + h->mb.cache.varmv[l][index][1] <<= 1;\ + h->mb.cache.mvd[l][index][1] <<= 1;\ + } + MAP_MVS +#undef MAP_F2F +#undef FIELD_DIFFERENT + } + } + } + + if( b_mbaff && mb_x == 0 && !(mb_y&1) ) + { + if( h->mb.i_mb_top_xy >= h->sh.i_first_mb ) + h->mb.field_decoding_flag = h->mb.field[h->mb.i_mb_top_xy]; + else + h->mb.field_decoding_flag = 0; + } + + /* Check whether skip here would cause decoder to predict interlace mode incorrectly. + * FIXME: It might be better to change the interlace type rather than forcing a skip to be non-skip. */ + h->mb.b_allow_skip = 1; + if( b_mbaff ) + { + if( MB_INTERLACED != h->mb.field_decoding_flag && + (mb_y&1) && IS_SKIP(h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride]) ) + h->mb.b_allow_skip = 0; + } + + if( h->param.b_cabac ) + { + if( b_mbaff ) + { + int left_xy, top_xy; + /* Neighbours here are calculated based on field_decoding_flag */ + int mb_xy = mb_x + (mb_y&~1)*h->mb.i_mb_stride; + left_xy = mb_xy - 1; + if( (mb_y&1) && mb_x > 0 && h->mb.field_decoding_flag == h->mb.field[left_xy] ) + left_xy += h->mb.i_mb_stride; + if( h->mb.field_decoding_flag ) + { + top_xy = mb_xy - h->mb.i_mb_stride; + if( !(mb_y&1) && top_xy >= 0 && h->mb.slice_table[top_xy] == h->sh.i_first_mb && h->mb.field[top_xy] ) + top_xy -= h->mb.i_mb_stride; + } + else + top_xy = mb_x + (mb_y-1)*h->mb.i_mb_stride; + + h->mb.cache.i_neighbour_skip = (mb_x > 0 && h->mb.slice_table[left_xy] == h->sh.i_first_mb && !IS_SKIP( h->mb.type[left_xy] )) + + (top_xy >= 0 && h->mb.slice_table[top_xy] == h->sh.i_first_mb && !IS_SKIP( h->mb.type[top_xy] )); + } + else + { + h->mb.cache.i_neighbour_skip = ((h->mb.i_neighbour & MB_LEFT) && !IS_SKIP( h->mb.i_mb_type_left[0] )) + + ((h->mb.i_neighbour & MB_TOP) && !IS_SKIP( h->mb.i_mb_type_top )); + } + } + + /* load skip */ + if( h->sh.i_type == SLICE_TYPE_B ) + { + h->mb.bipred_weight = h->mb.bipred_weight_buf[MB_INTERLACED][MB_INTERLACED&(mb_y&1)]; + h->mb.dist_scale_factor = h->mb.dist_scale_factor_buf[MB_INTERLACED][MB_INTERLACED&(mb_y&1)]; + if( h->param.b_cabac ) + { + uint8_t skipbp; + x264_macroblock_cache_skip( h, 0, 0, 4, 4, 0 ); + if( b_mbaff ) + { + skipbp = (h->mb.i_neighbour & MB_LEFT) ? h->mb.skipbp[left[LTOP]] : 0; + h->mb.cache.skip[x264_scan8[0] - 1] = (skipbp >> (1+(left_index_table->mv[0]&~1))) & 1; + skipbp = (h->mb.i_neighbour & MB_LEFT) ? h->mb.skipbp[left[LBOT]] : 0; + h->mb.cache.skip[x264_scan8[8] - 1] = (skipbp >> (1+(left_index_table->mv[2]&~1))) & 1; + } + else + { + skipbp = (h->mb.i_neighbour & MB_LEFT) ? h->mb.skipbp[left[0]] : 0; + h->mb.cache.skip[x264_scan8[0] - 1] = skipbp & 0x2; + h->mb.cache.skip[x264_scan8[8] - 1] = skipbp & 0x8; + } + skipbp = (h->mb.i_neighbour & MB_TOP) ? h->mb.skipbp[top] : 0; + h->mb.cache.skip[x264_scan8[0] - 8] = skipbp & 0x4; + h->mb.cache.skip[x264_scan8[4] - 8] = skipbp & 0x8; + } + } + + if( h->sh.i_type == SLICE_TYPE_P ) + x264_mb_predict_mv_pskip( h, h->mb.cache.pskip_mv ); + + h->mb.i_neighbour4[0] = + h->mb.i_neighbour8[0] = (h->mb.i_neighbour_intra & (MB_TOP|MB_LEFT|MB_TOPLEFT)) + | ((h->mb.i_neighbour_intra & MB_TOP) ? MB_TOPRIGHT : 0); + h->mb.i_neighbour4[4] = + h->mb.i_neighbour4[1] = MB_LEFT | ((h->mb.i_neighbour_intra & MB_TOP) ? (MB_TOP|MB_TOPLEFT|MB_TOPRIGHT) : 0); + h->mb.i_neighbour4[2] = + h->mb.i_neighbour4[8] = + h->mb.i_neighbour4[10] = + h->mb.i_neighbour8[2] = MB_TOP|MB_TOPRIGHT | ((h->mb.i_neighbour_intra & MB_LEFT) ? (MB_LEFT|MB_TOPLEFT) : 0); + h->mb.i_neighbour4[5] = + h->mb.i_neighbour8[1] = MB_LEFT | (h->mb.i_neighbour_intra & MB_TOPRIGHT) + | ((h->mb.i_neighbour_intra & MB_TOP) ? MB_TOP|MB_TOPLEFT : 0); +} + +void x264_macroblock_cache_load_progressive( x264_t *h, int mb_x, int mb_y ) +{ + x264_macroblock_cache_load( h, mb_x, mb_y, 0 ); +} + +void x264_macroblock_cache_load_interlaced( x264_t *h, int mb_x, int mb_y ) +{ + x264_macroblock_cache_load( h, mb_x, mb_y, 1 ); +} + +static void x264_macroblock_deblock_strength_mbaff( x264_t *h, uint8_t (*bs)[8][4] ) +{ + if( (h->mb.i_neighbour & MB_LEFT) && h->mb.field[h->mb.i_mb_left_xy[0]] != MB_INTERLACED ) + { + static const uint8_t offset[2][2][8] = + { { { 0, 0, 0, 0, 1, 1, 1, 1 }, + { 2, 2, 2, 2, 3, 3, 3, 3 }, }, + { { 0, 1, 2, 3, 0, 1, 2, 3 }, + { 0, 1, 2, 3, 0, 1, 2, 3 }, } + }; + ALIGNED_ARRAY_8( uint8_t, tmpbs, [8] ); + + const uint8_t *off = offset[MB_INTERLACED][h->mb.i_mb_y&1]; + uint8_t (*nnz)[48] = h->mb.non_zero_count; + + for( int i = 0; i < 8; i++ ) + { + int left = h->mb.i_mb_left_xy[MB_INTERLACED ? i>>2 : i&1]; + int nnz_this = h->mb.cache.non_zero_count[x264_scan8[0]+8*(i>>1)]; + int nnz_left = nnz[left][3 + 4*off[i]]; + if( !h->param.b_cabac && h->pps->b_transform_8x8_mode ) + { + int j = off[i]&~1; + if( h->mb.mb_transform_size[left] ) + nnz_left = !!(M16( &nnz[left][2+4*j] ) | M16( &nnz[left][2+4*(1+j)] )); + } + tmpbs[i] = (nnz_left || nnz_this) ? 2 : 1; + } + + if( MB_INTERLACED ) + { + CP32( bs[0][0], &tmpbs[0] ); + CP32( bs[0][4], &tmpbs[4] ); + } + else + { + for( int i = 0; i < 4; i++ ) bs[0][0][i] = tmpbs[2*i]; + for( int i = 0; i < 4; i++ ) bs[0][4][i] = tmpbs[1+2*i]; + } + } + + if( (h->mb.i_neighbour & MB_TOP) && MB_INTERLACED != h->mb.field[h->mb.i_mb_top_xy] ) + { + if( !(h->mb.i_mb_y&1) && !MB_INTERLACED ) + { + /* Need to filter both fields (even for frame macroblocks). + * Filter top two rows using the top macroblock of the above + * pair and then the bottom one. */ + int mbn_xy = h->mb.i_mb_xy - 2 * h->mb.i_mb_stride; + uint8_t *nnz_cur = &h->mb.cache.non_zero_count[x264_scan8[0]]; + + for( int j = 0; j < 2; j++, mbn_xy += h->mb.i_mb_stride ) + { + uint8_t (*nnz)[48] = h->mb.non_zero_count; + + ALIGNED_4( uint8_t nnz_top[4] ); + CP32( nnz_top, &nnz[mbn_xy][3*4] ); + + if( !h->param.b_cabac && h->pps->b_transform_8x8_mode && h->mb.mb_transform_size[mbn_xy] ) + { + nnz_top[0] = nnz_top[1] = M16( &nnz[mbn_xy][ 8] ) || M16( &nnz[mbn_xy][12] ); + nnz_top[2] = nnz_top[3] = M16( &nnz[mbn_xy][10] ) || M16( &nnz[mbn_xy][14] ); + } + + for( int i = 0; i < 4; i++ ) + bs[1][4*j][i] = (nnz_cur[i] || nnz_top[i]) ? 2 : 1; + } + } + else + for( int i = 0; i < 4; i++ ) + bs[1][0][i] = X264_MAX( bs[1][0][i], 1 ); + } +} + +void x264_macroblock_deblock_strength( x264_t *h ) +{ + uint8_t (*bs)[8][4] = h->mb.cache.deblock_strength; + if( IS_INTRA( h->mb.i_type ) ) + { + M32( bs[0][1] ) = 0x03030303; + M64( bs[0][2] ) = 0x0303030303030303ULL; + M32( bs[1][1] ) = 0x03030303; + M64( bs[1][2] ) = 0x0303030303030303ULL; + return; + } + + /* Early termination: in this case, nnz guarantees all edges use strength 2.*/ + if( h->mb.b_transform_8x8 && !CHROMA444 ) + { + int cbp_mask = 0xf >> CHROMA_V_SHIFT; + if( (h->mb.i_cbp_luma&cbp_mask) == cbp_mask ) + { + M32( bs[0][0] ) = 0x02020202; + M32( bs[0][2] ) = 0x02020202; + M32( bs[0][4] ) = 0x02020202; + M64( bs[1][0] ) = 0x0202020202020202ULL; /* [1][1] and [1][3] has to be set for 4:2:2 */ + M64( bs[1][2] ) = 0x0202020202020202ULL; + M32( bs[1][4] ) = 0x02020202; + return; + } + } + + int neighbour_changed = 0; + if( h->sh.i_disable_deblocking_filter_idc != 2 ) + { + neighbour_changed = h->mb.i_neighbour_frame&~h->mb.i_neighbour; + h->mb.i_neighbour = h->mb.i_neighbour_frame; + } + + /* MBAFF deblock uses different left neighbors from encoding */ + if( SLICE_MBAFF && (h->mb.i_neighbour & MB_LEFT) && (h->mb.field[h->mb.i_mb_xy - 1] != MB_INTERLACED) ) + { + h->mb.i_mb_left_xy[1] = + h->mb.i_mb_left_xy[0] = h->mb.i_mb_xy - 1; + if( h->mb.i_mb_y&1 ) + h->mb.i_mb_left_xy[0] -= h->mb.i_mb_stride; + else + h->mb.i_mb_left_xy[1] += h->mb.i_mb_stride; + } + + /* If we have multiple slices and we're deblocking on slice edges, we + * have to reload neighbour data. */ + if( neighbour_changed ) + { + int top_y = h->mb.i_mb_top_y; + int top_8x8 = (2*top_y+1) * h->mb.i_b8_stride + 2*h->mb.i_mb_x; + int top_4x4 = (4*top_y+3) * h->mb.i_b4_stride + 4*h->mb.i_mb_x; + int s8x8 = h->mb.i_b8_stride; + int s4x4 = h->mb.i_b4_stride; + + uint8_t (*nnz)[48] = h->mb.non_zero_count; + const x264_left_table_t *left_index_table = SLICE_MBAFF ? h->mb.left_index_table : &left_indices[3]; + + if( neighbour_changed & MB_TOP ) + CP32( &h->mb.cache.non_zero_count[x264_scan8[0] - 8], &nnz[h->mb.i_mb_top_xy][12] ); + + if( neighbour_changed & MB_LEFT ) + { + int *left = h->mb.i_mb_left_xy; + h->mb.cache.non_zero_count[x264_scan8[0 ] - 1] = nnz[left[0]][left_index_table->nnz[0]]; + h->mb.cache.non_zero_count[x264_scan8[2 ] - 1] = nnz[left[0]][left_index_table->nnz[1]]; + h->mb.cache.non_zero_count[x264_scan8[8 ] - 1] = nnz[left[1]][left_index_table->nnz[2]]; + h->mb.cache.non_zero_count[x264_scan8[10] - 1] = nnz[left[1]][left_index_table->nnz[3]]; + } + + for( int l = 0; l <= (h->sh.i_type == SLICE_TYPE_B); l++ ) + { + int16_t (*mv)[2] = h->mb.mv[l]; + int8_t *ref = h->mb.ref[l]; + + int i8 = x264_scan8[0] - 8; + if( neighbour_changed & MB_TOP ) + { + h->mb.cache.ref[l][i8+0] = + h->mb.cache.ref[l][i8+1] = ref[top_8x8 + 0]; + h->mb.cache.ref[l][i8+2] = + h->mb.cache.ref[l][i8+3] = ref[top_8x8 + 1]; + CP128( h->mb.cache.mv[l][i8], mv[top_4x4] ); + } + + i8 = x264_scan8[0] - 1; + if( neighbour_changed & MB_LEFT ) + { + h->mb.cache.ref[l][i8+0*8] = + h->mb.cache.ref[l][i8+1*8] = ref[h->mb.left_b8[0] + 1 + s8x8*left_index_table->ref[0]]; + h->mb.cache.ref[l][i8+2*8] = + h->mb.cache.ref[l][i8+3*8] = ref[h->mb.left_b8[1] + 1 + s8x8*left_index_table->ref[2]]; + + CP32( h->mb.cache.mv[l][i8+0*8], mv[h->mb.left_b4[0] + 3 + s4x4*left_index_table->mv[0]] ); + CP32( h->mb.cache.mv[l][i8+1*8], mv[h->mb.left_b4[0] + 3 + s4x4*left_index_table->mv[1]] ); + CP32( h->mb.cache.mv[l][i8+2*8], mv[h->mb.left_b4[1] + 3 + s4x4*left_index_table->mv[2]] ); + CP32( h->mb.cache.mv[l][i8+3*8], mv[h->mb.left_b4[1] + 3 + s4x4*left_index_table->mv[3]] ); + } + } + } + + if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_SMART && h->sh.i_type == SLICE_TYPE_P ) + { + /* Handle reference frame duplicates */ + int i8 = x264_scan8[0] - 8; + h->mb.cache.ref[0][i8+0] = + h->mb.cache.ref[0][i8+1] = deblock_ref_table(h->mb.cache.ref[0][i8+0]); + h->mb.cache.ref[0][i8+2] = + h->mb.cache.ref[0][i8+3] = deblock_ref_table(h->mb.cache.ref[0][i8+2]); + + i8 = x264_scan8[0] - 1; + h->mb.cache.ref[0][i8+0*8] = + h->mb.cache.ref[0][i8+1*8] = deblock_ref_table(h->mb.cache.ref[0][i8+0*8]); + h->mb.cache.ref[0][i8+2*8] = + h->mb.cache.ref[0][i8+3*8] = deblock_ref_table(h->mb.cache.ref[0][i8+2*8]); + + int ref0 = deblock_ref_table(h->mb.cache.ref[0][x264_scan8[ 0]]); + int ref1 = deblock_ref_table(h->mb.cache.ref[0][x264_scan8[ 4]]); + int ref2 = deblock_ref_table(h->mb.cache.ref[0][x264_scan8[ 8]]); + int ref3 = deblock_ref_table(h->mb.cache.ref[0][x264_scan8[12]]); + uint32_t reftop = pack16to32( (uint8_t)ref0, (uint8_t)ref1 ) * 0x0101; + uint32_t refbot = pack16to32( (uint8_t)ref2, (uint8_t)ref3 ) * 0x0101; + + M32( &h->mb.cache.ref[0][x264_scan8[0]+8*0] ) = reftop; + M32( &h->mb.cache.ref[0][x264_scan8[0]+8*1] ) = reftop; + M32( &h->mb.cache.ref[0][x264_scan8[0]+8*2] ) = refbot; + M32( &h->mb.cache.ref[0][x264_scan8[0]+8*3] ) = refbot; + } + + /* Munge NNZ for cavlc + 8x8dct */ + if( !h->param.b_cabac && h->pps->b_transform_8x8_mode ) + { + uint8_t (*nnz)[48] = h->mb.non_zero_count; + int top = h->mb.i_mb_top_xy; + int *left = h->mb.i_mb_left_xy; + + if( (h->mb.i_neighbour & MB_TOP) && h->mb.mb_transform_size[top] ) + { + int i8 = x264_scan8[0] - 8; + int nnz_top0 = M16( &nnz[top][8] ) | M16( &nnz[top][12] ); + int nnz_top1 = M16( &nnz[top][10] ) | M16( &nnz[top][14] ); + M16( &h->mb.cache.non_zero_count[i8+0] ) = nnz_top0 ? 0x0101 : 0; + M16( &h->mb.cache.non_zero_count[i8+2] ) = nnz_top1 ? 0x0101 : 0; + } + + if( h->mb.i_neighbour & MB_LEFT ) + { + int i8 = x264_scan8[0] - 1; + if( h->mb.mb_transform_size[left[0]] ) + { + int nnz_left0 = M16( &nnz[left[0]][2] ) | M16( &nnz[left[0]][6] ); + h->mb.cache.non_zero_count[i8+8*0] = !!nnz_left0; + h->mb.cache.non_zero_count[i8+8*1] = !!nnz_left0; + } + if( h->mb.mb_transform_size[left[1]] ) + { + int nnz_left1 = M16( &nnz[left[1]][10] ) | M16( &nnz[left[1]][14] ); + h->mb.cache.non_zero_count[i8+8*2] = !!nnz_left1; + h->mb.cache.non_zero_count[i8+8*3] = !!nnz_left1; + } + } + + if( h->mb.b_transform_8x8 ) + { + int nnz0 = M16( &h->mb.cache.non_zero_count[x264_scan8[ 0]] ) | M16( &h->mb.cache.non_zero_count[x264_scan8[ 2]] ); + int nnz1 = M16( &h->mb.cache.non_zero_count[x264_scan8[ 4]] ) | M16( &h->mb.cache.non_zero_count[x264_scan8[ 6]] ); + int nnz2 = M16( &h->mb.cache.non_zero_count[x264_scan8[ 8]] ) | M16( &h->mb.cache.non_zero_count[x264_scan8[10]] ); + int nnz3 = M16( &h->mb.cache.non_zero_count[x264_scan8[12]] ) | M16( &h->mb.cache.non_zero_count[x264_scan8[14]] ); + uint32_t nnztop = pack16to32( !!nnz0, !!nnz1 ) * 0x0101; + uint32_t nnzbot = pack16to32( !!nnz2, !!nnz3 ) * 0x0101; + + M32( &h->mb.cache.non_zero_count[x264_scan8[0]+8*0] ) = nnztop; + M32( &h->mb.cache.non_zero_count[x264_scan8[0]+8*1] ) = nnztop; + M32( &h->mb.cache.non_zero_count[x264_scan8[0]+8*2] ) = nnzbot; + M32( &h->mb.cache.non_zero_count[x264_scan8[0]+8*3] ) = nnzbot; + } + } + + h->loopf.deblock_strength( h->mb.cache.non_zero_count, h->mb.cache.ref, h->mb.cache.mv, + bs, 4 >> MB_INTERLACED, h->sh.i_type == SLICE_TYPE_B ); + + if( SLICE_MBAFF ) + x264_macroblock_deblock_strength_mbaff( h, bs ); +} + +static void ALWAYS_INLINE x264_macroblock_store_pic( x264_t *h, int mb_x, int mb_y, int i, int b_chroma, int b_mbaff ) +{ + int height = b_chroma ? 16>>CHROMA_V_SHIFT : 16; + int i_stride = h->fdec->i_stride[i]; + int i_stride2 = i_stride << (b_mbaff && MB_INTERLACED); + int i_pix_offset = (b_mbaff && MB_INTERLACED) + ? 16 * mb_x + height * (mb_y&~1) * i_stride + (mb_y&1) * i_stride + : 16 * mb_x + height * mb_y * i_stride; + if( b_chroma ) + h->mc.store_interleave_chroma( &h->fdec->plane[1][i_pix_offset], i_stride2, h->mb.pic.p_fdec[1], h->mb.pic.p_fdec[2], height ); + else + h->mc.copy[PIXEL_16x16]( &h->fdec->plane[i][i_pix_offset], i_stride2, h->mb.pic.p_fdec[i], FDEC_STRIDE, 16 ); +} + +static void ALWAYS_INLINE x264_macroblock_backup_intra( x264_t *h, int mb_x, int mb_y, int b_mbaff ) +{ + /* In MBAFF we store the last two rows in intra_border_backup[0] and [1]. + * For progressive mbs this is the bottom two rows, and for interlaced the + * bottom row of each field. We also store samples needed for the next + * mbpair in intra_border_backup[2]. */ + int backup_dst = !b_mbaff ? (mb_y&1) : (mb_y&1) ? 1 : MB_INTERLACED ? 0 : 2; + memcpy( &h->intra_border_backup[backup_dst][0][mb_x*16 ], h->mb.pic.p_fdec[0]+FDEC_STRIDE*15, 16*sizeof(pixel) ); + if( CHROMA444 ) + { + memcpy( &h->intra_border_backup[backup_dst][1][mb_x*16 ], h->mb.pic.p_fdec[1]+FDEC_STRIDE*15, 16*sizeof(pixel) ); + memcpy( &h->intra_border_backup[backup_dst][2][mb_x*16 ], h->mb.pic.p_fdec[2]+FDEC_STRIDE*15, 16*sizeof(pixel) ); + } + else + { + int backup_src = (15>>CHROMA_V_SHIFT) * FDEC_STRIDE; + memcpy( &h->intra_border_backup[backup_dst][1][mb_x*16 ], h->mb.pic.p_fdec[1]+backup_src, 8*sizeof(pixel) ); + memcpy( &h->intra_border_backup[backup_dst][1][mb_x*16+8], h->mb.pic.p_fdec[2]+backup_src, 8*sizeof(pixel) ); + } + if( b_mbaff ) + { + if( mb_y&1 ) + { + int backup_src = (MB_INTERLACED ? 7 : 14) * FDEC_STRIDE; + backup_dst = MB_INTERLACED ? 2 : 0; + memcpy( &h->intra_border_backup[backup_dst][0][mb_x*16 ], h->mb.pic.p_fdec[0]+backup_src, 16*sizeof(pixel) ); + if( CHROMA444 ) + { + memcpy( &h->intra_border_backup[backup_dst][1][mb_x*16 ], h->mb.pic.p_fdec[1]+backup_src, 16*sizeof(pixel) ); + memcpy( &h->intra_border_backup[backup_dst][2][mb_x*16 ], h->mb.pic.p_fdec[2]+backup_src, 16*sizeof(pixel) ); + } + else + { + if( CHROMA_FORMAT == CHROMA_420 ) + backup_src = (MB_INTERLACED ? 3 : 6) * FDEC_STRIDE; + memcpy( &h->intra_border_backup[backup_dst][1][mb_x*16 ], h->mb.pic.p_fdec[1]+backup_src, 8*sizeof(pixel) ); + memcpy( &h->intra_border_backup[backup_dst][1][mb_x*16+8], h->mb.pic.p_fdec[2]+backup_src, 8*sizeof(pixel) ); + } + } + } +} + +void x264_macroblock_cache_save( x264_t *h ) +{ + const int i_mb_xy = h->mb.i_mb_xy; + const int i_mb_type = x264_mb_type_fix[h->mb.i_type]; + const int s8x8 = h->mb.i_b8_stride; + const int s4x4 = h->mb.i_b4_stride; + const int i_mb_4x4 = h->mb.i_b4_xy; + const int i_mb_8x8 = h->mb.i_b8_xy; + + /* GCC pessimizes direct stores to heap-allocated arrays due to aliasing. */ + /* By only dereferencing them once, we avoid this issue. */ + int8_t *i4x4 = h->mb.intra4x4_pred_mode[i_mb_xy]; + uint8_t *nnz = h->mb.non_zero_count[i_mb_xy]; + + if( SLICE_MBAFF ) + { + x264_macroblock_backup_intra( h, h->mb.i_mb_x, h->mb.i_mb_y, 1 ); + x264_macroblock_store_pic( h, h->mb.i_mb_x, h->mb.i_mb_y, 0, 0, 1 ); + if( CHROMA444 ) + { + x264_macroblock_store_pic( h, h->mb.i_mb_x, h->mb.i_mb_y, 1, 0, 1 ); + x264_macroblock_store_pic( h, h->mb.i_mb_x, h->mb.i_mb_y, 2, 0, 1 ); + } + else + x264_macroblock_store_pic( h, h->mb.i_mb_x, h->mb.i_mb_y, 1, 1, 1 ); + } + else + { + x264_macroblock_backup_intra( h, h->mb.i_mb_x, h->mb.i_mb_y, 0 ); + x264_macroblock_store_pic( h, h->mb.i_mb_x, h->mb.i_mb_y, 0, 0, 0 ); + if( CHROMA444 ) + { + x264_macroblock_store_pic( h, h->mb.i_mb_x, h->mb.i_mb_y, 1, 0, 0 ); + x264_macroblock_store_pic( h, h->mb.i_mb_x, h->mb.i_mb_y, 2, 0, 0 ); + } + else + x264_macroblock_store_pic( h, h->mb.i_mb_x, h->mb.i_mb_y, 1, 1, 0 ); + } + + x264_prefetch_fenc( h, h->fdec, h->mb.i_mb_x, h->mb.i_mb_y ); + + h->mb.type[i_mb_xy] = i_mb_type; + h->mb.slice_table[i_mb_xy] = h->sh.i_first_mb; + h->mb.partition[i_mb_xy] = IS_INTRA( i_mb_type ) ? D_16x16 : h->mb.i_partition; + h->mb.i_mb_prev_xy = i_mb_xy; + + /* save intra4x4 */ + if( i_mb_type == I_4x4 ) + { + CP32( &i4x4[0], &h->mb.cache.intra4x4_pred_mode[x264_scan8[10]] ); + M32( &i4x4[4] ) = pack8to32( h->mb.cache.intra4x4_pred_mode[x264_scan8[5] ], + h->mb.cache.intra4x4_pred_mode[x264_scan8[7] ], + h->mb.cache.intra4x4_pred_mode[x264_scan8[13] ], 0); + } + else if( !h->param.b_constrained_intra || IS_INTRA(i_mb_type) ) + M64( i4x4 ) = I_PRED_4x4_DC * 0x0101010101010101ULL; + else + M64( i4x4 ) = (uint8_t)(-1) * 0x0101010101010101ULL; + + + if( i_mb_type == I_PCM ) + { + h->mb.qp[i_mb_xy] = 0; + h->mb.i_last_dqp = 0; + h->mb.i_cbp_chroma = CHROMA444 ? 0 : 2; + h->mb.i_cbp_luma = 0xf; + h->mb.cbp[i_mb_xy] = (h->mb.i_cbp_chroma << 4) | h->mb.i_cbp_luma | 0x1700; + h->mb.b_transform_8x8 = 0; + for( int i = 0; i < 48; i++ ) + h->mb.cache.non_zero_count[x264_scan8[i]] = h->param.b_cabac ? 1 : 16; + } + else + { + if( h->mb.i_type != I_16x16 && h->mb.i_cbp_luma == 0 && h->mb.i_cbp_chroma == 0 ) + h->mb.i_qp = h->mb.i_last_qp; + h->mb.qp[i_mb_xy] = h->mb.i_qp; + h->mb.i_last_dqp = h->mb.i_qp - h->mb.i_last_qp; + h->mb.i_last_qp = h->mb.i_qp; + } + + /* save non zero count */ + CP32( &nnz[ 0+0*4], &h->mb.cache.non_zero_count[x264_scan8[ 0]] ); + CP32( &nnz[ 0+1*4], &h->mb.cache.non_zero_count[x264_scan8[ 2]] ); + CP32( &nnz[ 0+2*4], &h->mb.cache.non_zero_count[x264_scan8[ 8]] ); + CP32( &nnz[ 0+3*4], &h->mb.cache.non_zero_count[x264_scan8[10]] ); + CP32( &nnz[16+0*4], &h->mb.cache.non_zero_count[x264_scan8[16+0]] ); + CP32( &nnz[16+1*4], &h->mb.cache.non_zero_count[x264_scan8[16+2]] ); + CP32( &nnz[32+0*4], &h->mb.cache.non_zero_count[x264_scan8[32+0]] ); + CP32( &nnz[32+1*4], &h->mb.cache.non_zero_count[x264_scan8[32+2]] ); + if( CHROMA_FORMAT >= CHROMA_422 ) + { + CP32( &nnz[16+2*4], &h->mb.cache.non_zero_count[x264_scan8[16+ 8]] ); + CP32( &nnz[16+3*4], &h->mb.cache.non_zero_count[x264_scan8[16+10]] ); + CP32( &nnz[32+2*4], &h->mb.cache.non_zero_count[x264_scan8[32+ 8]] ); + CP32( &nnz[32+3*4], &h->mb.cache.non_zero_count[x264_scan8[32+10]] ); + } + + if( h->mb.i_cbp_luma == 0 && h->mb.i_type != I_8x8 ) + h->mb.b_transform_8x8 = 0; + h->mb.mb_transform_size[i_mb_xy] = h->mb.b_transform_8x8; + + if( h->sh.i_type != SLICE_TYPE_I ) + { + int16_t (*mv0)[2] = &h->mb.mv[0][i_mb_4x4]; + int16_t (*mv1)[2] = &h->mb.mv[1][i_mb_4x4]; + int8_t *ref0 = &h->mb.ref[0][i_mb_8x8]; + int8_t *ref1 = &h->mb.ref[1][i_mb_8x8]; + if( !IS_INTRA( i_mb_type ) ) + { + ref0[0+0*s8x8] = h->mb.cache.ref[0][x264_scan8[0]]; + ref0[1+0*s8x8] = h->mb.cache.ref[0][x264_scan8[4]]; + ref0[0+1*s8x8] = h->mb.cache.ref[0][x264_scan8[8]]; + ref0[1+1*s8x8] = h->mb.cache.ref[0][x264_scan8[12]]; + CP128( &mv0[0*s4x4], h->mb.cache.mv[0][x264_scan8[0]+8*0] ); + CP128( &mv0[1*s4x4], h->mb.cache.mv[0][x264_scan8[0]+8*1] ); + CP128( &mv0[2*s4x4], h->mb.cache.mv[0][x264_scan8[0]+8*2] ); + CP128( &mv0[3*s4x4], h->mb.cache.mv[0][x264_scan8[0]+8*3] ); + if( h->sh.i_type == SLICE_TYPE_B ) + { + ref1[0+0*s8x8] = h->mb.cache.ref[1][x264_scan8[0]]; + ref1[1+0*s8x8] = h->mb.cache.ref[1][x264_scan8[4]]; + ref1[0+1*s8x8] = h->mb.cache.ref[1][x264_scan8[8]]; + ref1[1+1*s8x8] = h->mb.cache.ref[1][x264_scan8[12]]; + CP128( &mv1[0*s4x4], h->mb.cache.mv[1][x264_scan8[0]+8*0] ); + CP128( &mv1[1*s4x4], h->mb.cache.mv[1][x264_scan8[0]+8*1] ); + CP128( &mv1[2*s4x4], h->mb.cache.mv[1][x264_scan8[0]+8*2] ); + CP128( &mv1[3*s4x4], h->mb.cache.mv[1][x264_scan8[0]+8*3] ); + } + } + else + { + M16( &ref0[0*s8x8] ) = (uint8_t)(-1) * 0x0101; + M16( &ref0[1*s8x8] ) = (uint8_t)(-1) * 0x0101; + M128( &mv0[0*s4x4] ) = M128_ZERO; + M128( &mv0[1*s4x4] ) = M128_ZERO; + M128( &mv0[2*s4x4] ) = M128_ZERO; + M128( &mv0[3*s4x4] ) = M128_ZERO; + if( h->sh.i_type == SLICE_TYPE_B ) + { + M16( &ref1[0*s8x8] ) = (uint8_t)(-1) * 0x0101; + M16( &ref1[1*s8x8] ) = (uint8_t)(-1) * 0x0101; + M128( &mv1[0*s4x4] ) = M128_ZERO; + M128( &mv1[1*s4x4] ) = M128_ZERO; + M128( &mv1[2*s4x4] ) = M128_ZERO; + M128( &mv1[3*s4x4] ) = M128_ZERO; + } + } + } + + if( h->param.b_cabac ) + { + uint8_t (*mvd0)[2] = h->mb.mvd[0][i_mb_xy]; + uint8_t (*mvd1)[2] = h->mb.mvd[1][i_mb_xy]; + if( IS_INTRA(i_mb_type) && i_mb_type != I_PCM ) + h->mb.chroma_pred_mode[i_mb_xy] = x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode]; + else + h->mb.chroma_pred_mode[i_mb_xy] = I_PRED_CHROMA_DC; + + if( (0x3FF30 >> i_mb_type) & 1 ) /* !INTRA && !SKIP && !DIRECT */ + { + CP64( mvd0[0], h->mb.cache.mvd[0][x264_scan8[10]] ); + CP16( mvd0[4], h->mb.cache.mvd[0][x264_scan8[5 ]] ); + CP16( mvd0[5], h->mb.cache.mvd[0][x264_scan8[7 ]] ); + CP16( mvd0[6], h->mb.cache.mvd[0][x264_scan8[13]] ); + if( h->sh.i_type == SLICE_TYPE_B ) + { + CP64( mvd1[0], h->mb.cache.mvd[1][x264_scan8[10]] ); + CP16( mvd1[4], h->mb.cache.mvd[1][x264_scan8[5 ]] ); + CP16( mvd1[5], h->mb.cache.mvd[1][x264_scan8[7 ]] ); + CP16( mvd1[6], h->mb.cache.mvd[1][x264_scan8[13]] ); + } + } + else + { + M128( mvd0[0] ) = M128_ZERO; + if( h->sh.i_type == SLICE_TYPE_B ) + M128( mvd1[0] ) = M128_ZERO; + } + + if( h->sh.i_type == SLICE_TYPE_B ) + { + if( i_mb_type == B_SKIP || i_mb_type == B_DIRECT ) + h->mb.skipbp[i_mb_xy] = 0xf; + else if( i_mb_type == B_8x8 ) + { + int skipbp = ( h->mb.i_sub_partition[0] == D_DIRECT_8x8 ) << 0; + skipbp |= ( h->mb.i_sub_partition[1] == D_DIRECT_8x8 ) << 1; + skipbp |= ( h->mb.i_sub_partition[2] == D_DIRECT_8x8 ) << 2; + skipbp |= ( h->mb.i_sub_partition[3] == D_DIRECT_8x8 ) << 3; + h->mb.skipbp[i_mb_xy] = skipbp; + } + else + h->mb.skipbp[i_mb_xy] = 0; + } + } +} + + +void x264_macroblock_bipred_init( x264_t *h ) +{ + for( int mbfield = 0; mbfield <= SLICE_MBAFF; mbfield++ ) + for( int field = 0; field <= SLICE_MBAFF; field++ ) + for( int i_ref0 = 0; i_ref0 < (h->i_ref[0]<fref[0][i_ref0>>mbfield]; + int poc0 = l0->i_poc + mbfield*l0->i_delta_poc[field^(i_ref0&1)]; + for( int i_ref1 = 0; i_ref1 < (h->i_ref[1]<fref[1][i_ref1>>mbfield]; + int cur_poc = h->fdec->i_poc + mbfield*h->fdec->i_delta_poc[field]; + int poc1 = l1->i_poc + mbfield*l1->i_delta_poc[field^(i_ref1&1)]; + int td = x264_clip3( poc1 - poc0, -128, 127 ); + if( td == 0 /* || pic0 is a long-term ref */ ) + dist_scale_factor = 256; + else + { + int tb = x264_clip3( cur_poc - poc0, -128, 127 ); + int tx = (16384 + (abs(td) >> 1)) / td; + dist_scale_factor = x264_clip3( (tb * tx + 32) >> 6, -1024, 1023 ); + } + + h->mb.dist_scale_factor_buf[mbfield][field][i_ref0][i_ref1] = dist_scale_factor; + + dist_scale_factor >>= 2; + if( h->param.analyse.b_weighted_bipred + && dist_scale_factor >= -64 + && dist_scale_factor <= 128 ) + { + h->mb.bipred_weight_buf[mbfield][field][i_ref0][i_ref1] = 64 - dist_scale_factor; + // ssse3 implementation of biweight doesn't support the extrema. + // if we ever generate them, we'll have to drop that optimization. + assert( dist_scale_factor >= -63 && dist_scale_factor <= 127 ); + } + else + h->mb.bipred_weight_buf[mbfield][field][i_ref0][i_ref1] = 32; + } + } +} + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/macroblock.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/macroblock.h new file mode 100644 index 00000000..f1dfb275 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/macroblock.h @@ -0,0 +1,444 @@ +/***************************************************************************** + * macroblock.h: macroblock common functions + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_MACROBLOCK_H +#define X264_MACROBLOCK_H + +enum macroblock_position_e +{ + MB_LEFT = 0x01, + MB_TOP = 0x02, + MB_TOPRIGHT = 0x04, + MB_TOPLEFT = 0x08, + + MB_PRIVATE = 0x10, + + ALL_NEIGHBORS = 0xf, +}; + +static const uint8_t x264_pred_i4x4_neighbors[12] = +{ + MB_TOP, // I_PRED_4x4_V + MB_LEFT, // I_PRED_4x4_H + MB_LEFT | MB_TOP, // I_PRED_4x4_DC + MB_TOP | MB_TOPRIGHT, // I_PRED_4x4_DDL + MB_LEFT | MB_TOPLEFT | MB_TOP, // I_PRED_4x4_DDR + MB_LEFT | MB_TOPLEFT | MB_TOP, // I_PRED_4x4_VR + MB_LEFT | MB_TOPLEFT | MB_TOP, // I_PRED_4x4_HD + MB_TOP | MB_TOPRIGHT, // I_PRED_4x4_VL + MB_LEFT, // I_PRED_4x4_HU + MB_LEFT, // I_PRED_4x4_DC_LEFT + MB_TOP, // I_PRED_4x4_DC_TOP + 0 // I_PRED_4x4_DC_128 +}; + + +/* XXX mb_type isn't the one written in the bitstream -> only internal usage */ +#define IS_INTRA(type) ( (type) == I_4x4 || (type) == I_8x8 || (type) == I_16x16 || (type) == I_PCM ) +#define IS_SKIP(type) ( (type) == P_SKIP || (type) == B_SKIP ) +#define IS_DIRECT(type) ( (type) == B_DIRECT ) +enum mb_class_e +{ + I_4x4 = 0, + I_8x8 = 1, + I_16x16 = 2, + I_PCM = 3, + + P_L0 = 4, + P_8x8 = 5, + P_SKIP = 6, + + B_DIRECT = 7, + B_L0_L0 = 8, + B_L0_L1 = 9, + B_L0_BI = 10, + B_L1_L0 = 11, + B_L1_L1 = 12, + B_L1_BI = 13, + B_BI_L0 = 14, + B_BI_L1 = 15, + B_BI_BI = 16, + B_8x8 = 17, + B_SKIP = 18, + + X264_MBTYPE_MAX = 19 +}; +static const uint8_t x264_mb_type_fix[X264_MBTYPE_MAX] = +{ + I_4x4, I_4x4, I_16x16, I_PCM, + P_L0, P_8x8, P_SKIP, + B_DIRECT, B_L0_L0, B_L0_L1, B_L0_BI, B_L1_L0, B_L1_L1, + B_L1_BI, B_BI_L0, B_BI_L1, B_BI_BI, B_8x8, B_SKIP +}; +static const uint8_t x264_mb_type_list_table[X264_MBTYPE_MAX][2][2] = +{ + {{0,0},{0,0}}, {{0,0},{0,0}}, {{0,0},{0,0}}, {{0,0},{0,0}}, /* INTRA */ + {{1,1},{0,0}}, /* P_L0 */ + {{0,0},{0,0}}, /* P_8x8 */ + {{1,1},{0,0}}, /* P_SKIP */ + {{0,0},{0,0}}, /* B_DIRECT */ + {{1,1},{0,0}}, {{1,0},{0,1}}, {{1,1},{0,1}}, /* B_L0_* */ + {{0,1},{1,0}}, {{0,0},{1,1}}, {{0,1},{1,1}}, /* B_L1_* */ + {{1,1},{1,0}}, {{1,0},{1,1}}, {{1,1},{1,1}}, /* B_BI_* */ + {{0,0},{0,0}}, /* B_8x8 */ + {{0,0},{0,0}} /* B_SKIP */ +}; + +#define IS_SUB4x4(type) ( (type == D_L0_4x4)||(type == D_L1_4x4)||(type == D_BI_4x4) ) +#define IS_SUB4x8(type) ( (type == D_L0_4x8)||(type == D_L1_4x8)||(type == D_BI_4x8) ) +#define IS_SUB8x4(type) ( (type == D_L0_8x4)||(type == D_L1_8x4)||(type == D_BI_8x4) ) +#define IS_SUB8x8(type) ( (type == D_L0_8x8)||(type == D_L1_8x8)||(type == D_BI_8x8)||(type == D_DIRECT_8x8) ) +enum mb_partition_e +{ + /* sub partition type for P_8x8 and B_8x8 */ + D_L0_4x4 = 0, + D_L0_8x4 = 1, + D_L0_4x8 = 2, + D_L0_8x8 = 3, + + /* sub partition type for B_8x8 only */ + D_L1_4x4 = 4, + D_L1_8x4 = 5, + D_L1_4x8 = 6, + D_L1_8x8 = 7, + + D_BI_4x4 = 8, + D_BI_8x4 = 9, + D_BI_4x8 = 10, + D_BI_8x8 = 11, + D_DIRECT_8x8 = 12, + + /* partition */ + D_8x8 = 13, + D_16x8 = 14, + D_8x16 = 15, + D_16x16 = 16, + X264_PARTTYPE_MAX = 17, +}; + +static const uint8_t x264_mb_partition_listX_table[2][17] = +{{ + 1, 1, 1, 1, /* D_L0_* */ + 0, 0, 0, 0, /* D_L1_* */ + 1, 1, 1, 1, /* D_BI_* */ + 0, /* D_DIRECT_8x8 */ + 0, 0, 0, 0 /* 8x8 .. 16x16 */ +}, +{ + 0, 0, 0, 0, /* D_L0_* */ + 1, 1, 1, 1, /* D_L1_* */ + 1, 1, 1, 1, /* D_BI_* */ + 0, /* D_DIRECT_8x8 */ + 0, 0, 0, 0 /* 8x8 .. 16x16 */ +}}; +static const uint8_t x264_mb_partition_count_table[17] = +{ + /* sub L0 */ + 4, 2, 2, 1, + /* sub L1 */ + 4, 2, 2, 1, + /* sub BI */ + 4, 2, 2, 1, + /* Direct */ + 1, + /* Partition */ + 4, 2, 2, 1 +}; +static const uint8_t x264_mb_partition_pixel_table[17] = +{ + PIXEL_4x4, PIXEL_8x4, PIXEL_4x8, PIXEL_8x8, /* D_L0_* */ + PIXEL_4x4, PIXEL_8x4, PIXEL_4x8, PIXEL_8x8, /* D_L1_* */ + PIXEL_4x4, PIXEL_8x4, PIXEL_4x8, PIXEL_8x8, /* D_BI_* */ + PIXEL_8x8, /* D_DIRECT_8x8 */ + PIXEL_8x8, PIXEL_16x8, PIXEL_8x16, PIXEL_16x16, /* 8x8 .. 16x16 */ +}; + +/* zigzags are transposed with respect to the tables in the standard */ +static const uint8_t x264_zigzag_scan4[2][16] = +{{ // frame + 0, 4, 1, 2, 5, 8, 12, 9, 6, 3, 7, 10, 13, 14, 11, 15 +}, +{ // field + 0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}}; +static const uint8_t x264_zigzag_scan8[2][64] = +{{ + 0, 8, 1, 2, 9, 16, 24, 17, 10, 3, 4, 11, 18, 25, 32, 40, + 33, 26, 19, 12, 5, 6, 13, 20, 27, 34, 41, 48, 56, 49, 42, 35, + 28, 21, 14, 7, 15, 22, 29, 36, 43, 50, 57, 58, 51, 44, 37, 30, + 23, 31, 38, 45, 52, 59, 60, 53, 46, 39, 47, 54, 61, 62, 55, 63 +}, +{ + 0, 1, 2, 8, 9, 3, 4, 10, 16, 11, 5, 6, 7, 12, 17, 24, + 18, 13, 14, 15, 19, 25, 32, 26, 20, 21, 22, 23, 27, 33, 40, 34, + 28, 29, 30, 31, 35, 41, 48, 42, 36, 37, 38, 39, 43, 49, 50, 44, + 45, 46, 47, 51, 56, 57, 52, 53, 54, 55, 58, 59, 60, 61, 62, 63 +}}; + +static const uint8_t block_idx_x[16] = +{ + 0, 1, 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, 3 +}; +static const uint8_t block_idx_y[16] = +{ + 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 3, 3, 2, 2, 3, 3 +}; +static const uint8_t block_idx_xy[4][4] = +{ + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 } +}; +static const uint8_t block_idx_xy_1d[16] = +{ + 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15 +}; +static const uint8_t block_idx_yx_1d[16] = +{ + 0, 4, 1, 5, 8, 12, 9, 13, 2, 6, 3, 7, 10, 14, 11, 15 +}; +static const uint8_t block_idx_xy_fenc[16] = +{ + 0*4 + 0*4*FENC_STRIDE, 1*4 + 0*4*FENC_STRIDE, + 0*4 + 1*4*FENC_STRIDE, 1*4 + 1*4*FENC_STRIDE, + 2*4 + 0*4*FENC_STRIDE, 3*4 + 0*4*FENC_STRIDE, + 2*4 + 1*4*FENC_STRIDE, 3*4 + 1*4*FENC_STRIDE, + 0*4 + 2*4*FENC_STRIDE, 1*4 + 2*4*FENC_STRIDE, + 0*4 + 3*4*FENC_STRIDE, 1*4 + 3*4*FENC_STRIDE, + 2*4 + 2*4*FENC_STRIDE, 3*4 + 2*4*FENC_STRIDE, + 2*4 + 3*4*FENC_STRIDE, 3*4 + 3*4*FENC_STRIDE +}; +static const uint16_t block_idx_xy_fdec[16] = +{ + 0*4 + 0*4*FDEC_STRIDE, 1*4 + 0*4*FDEC_STRIDE, + 0*4 + 1*4*FDEC_STRIDE, 1*4 + 1*4*FDEC_STRIDE, + 2*4 + 0*4*FDEC_STRIDE, 3*4 + 0*4*FDEC_STRIDE, + 2*4 + 1*4*FDEC_STRIDE, 3*4 + 1*4*FDEC_STRIDE, + 0*4 + 2*4*FDEC_STRIDE, 1*4 + 2*4*FDEC_STRIDE, + 0*4 + 3*4*FDEC_STRIDE, 1*4 + 3*4*FDEC_STRIDE, + 2*4 + 2*4*FDEC_STRIDE, 3*4 + 2*4*FDEC_STRIDE, + 2*4 + 3*4*FDEC_STRIDE, 3*4 + 3*4*FDEC_STRIDE +}; + +#define QP(qP) ( (qP)+QP_BD_OFFSET ) +static const uint8_t i_chroma_qp_table[QP_MAX+1+12*2] = +{ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +#if BIT_DEPTH > 9 + QP(-12),QP(-11),QP(-10), QP(-9), QP(-8), QP(-7), +#endif +#if BIT_DEPTH > 8 + QP(-6), QP(-5), QP(-4), QP(-3), QP(-2), QP(-1), +#endif + QP(0), QP(1), QP(2), QP(3), QP(4), QP(5), + QP(6), QP(7), QP(8), QP(9), QP(10), QP(11), + QP(12), QP(13), QP(14), QP(15), QP(16), QP(17), + QP(18), QP(19), QP(20), QP(21), QP(22), QP(23), + QP(24), QP(25), QP(26), QP(27), QP(28), QP(29), + QP(29), QP(30), QP(31), QP(32), QP(32), QP(33), + QP(34), QP(34), QP(35), QP(35), QP(36), QP(36), + QP(37), QP(37), QP(37), QP(38), QP(38), QP(38), + QP(39), QP(39), QP(39), QP(39), + QP(39), QP(39), QP(39), QP(39), QP(39), QP(39), + QP(39), QP(39), QP(39), QP(39), QP(39), QP(39), +}; +#undef QP + +enum cabac_ctx_block_cat_e +{ + DCT_LUMA_DC = 0, + DCT_LUMA_AC = 1, + DCT_LUMA_4x4 = 2, + DCT_CHROMA_DC = 3, + DCT_CHROMA_AC = 4, + DCT_LUMA_8x8 = 5, + DCT_CHROMAU_DC = 6, + DCT_CHROMAU_AC = 7, + DCT_CHROMAU_4x4 = 8, + DCT_CHROMAU_8x8 = 9, + DCT_CHROMAV_DC = 10, + DCT_CHROMAV_AC = 11, + DCT_CHROMAV_4x4 = 12, + DCT_CHROMAV_8x8 = 13, +}; + +static const uint8_t ctx_cat_plane[6][3] = +{ + { DCT_LUMA_DC, DCT_CHROMAU_DC, DCT_CHROMAV_DC}, + { DCT_LUMA_AC, DCT_CHROMAU_AC, DCT_CHROMAV_AC}, + {DCT_LUMA_4x4, DCT_CHROMAU_4x4, DCT_CHROMAV_4x4}, + {0}, + {0}, + {DCT_LUMA_8x8, DCT_CHROMAU_8x8, DCT_CHROMAV_8x8} +}; + +/* Per-frame allocation: is allocated per-thread only in frame-threads mode. */ +int x264_macroblock_cache_allocate( x264_t *h ); +void x264_macroblock_cache_free( x264_t *h ); + +/* Per-thread allocation: is allocated per-thread even in sliced-threads mode. */ +int x264_macroblock_thread_allocate( x264_t *h, int b_lookahead ); +void x264_macroblock_thread_free( x264_t *h, int b_lookahead ); + +void x264_macroblock_slice_init( x264_t *h ); +void x264_macroblock_thread_init( x264_t *h ); +void x264_macroblock_cache_load_progressive( x264_t *h, int mb_x, int mb_y ); +void x264_macroblock_cache_load_interlaced( x264_t *h, int mb_x, int mb_y ); +void x264_macroblock_deblock_strength( x264_t *h ); +void x264_macroblock_cache_save( x264_t *h ); + +void x264_macroblock_bipred_init( x264_t *h ); + +void x264_prefetch_fenc( x264_t *h, x264_frame_t *fenc, int i_mb_x, int i_mb_y ); + +void x264_copy_column8( pixel *dst, pixel *src ); + +/* x264_mb_predict_mv_16x16: + * set mvp with predicted mv for D_16x16 block + * h->mb. need only valid values from other blocks */ +void x264_mb_predict_mv_16x16( x264_t *h, int i_list, int i_ref, int16_t mvp[2] ); +/* x264_mb_predict_mv_pskip: + * set mvp with predicted mv for P_SKIP + * h->mb. need only valid values from other blocks */ +void x264_mb_predict_mv_pskip( x264_t *h, int16_t mv[2] ); +/* x264_mb_predict_mv: + * set mvp with predicted mv for all blocks except SKIP and DIRECT + * h->mb. need valid ref/partition/sub of current block to be valid + * and valid mv/ref from other blocks. */ +void x264_mb_predict_mv( x264_t *h, int i_list, int idx, int i_width, int16_t mvp[2] ); +/* x264_mb_predict_mv_direct16x16: + * set h->mb.cache.mv and h->mb.cache.ref for B_SKIP or B_DIRECT + * h->mb. need only valid values from other blocks. + * return 1 on success, 0 on failure. + * if b_changed != NULL, set it to whether refs or mvs differ from + * before this functioncall. */ +int x264_mb_predict_mv_direct16x16( x264_t *h, int *b_changed ); +/* x264_mb_predict_mv_ref16x16: + * set mvc with D_16x16 prediction. + * uses all neighbors, even those that didn't end up using this ref. + * h->mb. need only valid values from other blocks */ +void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[8][2], int *i_mvc ); + +void x264_mb_mc( x264_t *h ); +void x264_mb_mc_8x8( x264_t *h, int i8 ); + +static ALWAYS_INLINE uint32_t pack16to32( uint32_t a, uint32_t b ) +{ +#if WORDS_BIGENDIAN + return b + (a<<16); +#else + return a + (b<<16); +#endif +} +static ALWAYS_INLINE uint32_t pack8to16( uint32_t a, uint32_t b ) +{ +#if WORDS_BIGENDIAN + return b + (a<<8); +#else + return a + (b<<8); +#endif +} +static ALWAYS_INLINE uint32_t pack8to32( uint32_t a, uint32_t b, uint32_t c, uint32_t d ) +{ +#if WORDS_BIGENDIAN + return d + (c<<8) + (b<<16) + (a<<24); +#else + return a + (b<<8) + (c<<16) + (d<<24); +#endif +} +static ALWAYS_INLINE uint32_t pack16to32_mask( int a, int b ) +{ +#if WORDS_BIGENDIAN + return (b&0xFFFF) + (a<<16); +#else + return (a&0xFFFF) + (b<<16); +#endif +} +static ALWAYS_INLINE uint64_t pack32to64( uint32_t a, uint32_t b ) +{ +#if WORDS_BIGENDIAN + return b + ((uint64_t)a<<32); +#else + return a + ((uint64_t)b<<32); +#endif +} + +#if HIGH_BIT_DEPTH +# define pack_pixel_1to2 pack16to32 +# define pack_pixel_2to4 pack32to64 +#else +# define pack_pixel_1to2 pack8to16 +# define pack_pixel_2to4 pack16to32 +#endif + +static ALWAYS_INLINE int x264_mb_predict_intra4x4_mode( x264_t *h, int idx ) +{ + const int ma = h->mb.cache.intra4x4_pred_mode[x264_scan8[idx] - 1]; + const int mb = h->mb.cache.intra4x4_pred_mode[x264_scan8[idx] - 8]; + const int m = X264_MIN( x264_mb_pred_mode4x4_fix(ma), + x264_mb_pred_mode4x4_fix(mb) ); + + if( m < 0 ) + return I_PRED_4x4_DC; + + return m; +} +static ALWAYS_INLINE int x264_mb_predict_non_zero_code( x264_t *h, int idx ) +{ + const int za = h->mb.cache.non_zero_count[x264_scan8[idx] - 1]; + const int zb = h->mb.cache.non_zero_count[x264_scan8[idx] - 8]; + + int i_ret = za + zb; + + if( i_ret < 0x80 ) + i_ret = ( i_ret + 1 ) >> 1; + return i_ret & 0x7f; +} + +/* intra and skip are disallowed, p8x8 is conditional. */ +static const uint8_t x264_transform_allowed[X264_MBTYPE_MAX] = +{ + 0,0,0,0,1,2,0,1,1,1,1,1,1,1,1,1,1,1,0 +}; + +/* x264_mb_transform_8x8_allowed: + * check whether any partition is smaller than 8x8 (or at least + * might be, according to just partition type.) + * doesn't check for cbp */ +static ALWAYS_INLINE int x264_mb_transform_8x8_allowed( x264_t *h ) +{ + if( !h->pps->b_transform_8x8_mode ) + return 0; + if( h->mb.i_type != P_8x8 ) + return x264_transform_allowed[h->mb.i_type]; + return M32( h->mb.i_sub_partition ) == D_L0_8x8*0x01010101; +} + +#endif + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mc.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mc.c new file mode 100644 index 00000000..65af5b9e --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mc.c @@ -0,0 +1,779 @@ +/***************************************************************************** + * mc.c: motion compensation + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#if HAVE_MMX +#include "x86/mc.h" +#endif +#if ARCH_PPC +#include "ppc/mc.h" +#endif +#if ARCH_ARM +#include "arm/mc.h" +#endif +#if ARCH_AARCH64 +#include "aarch64/mc.h" +#endif +#if ARCH_MIPS +#include "mips/mc.h" +#endif + + +static inline void pixel_avg( pixel *dst, intptr_t i_dst_stride, + pixel *src1, intptr_t i_src1_stride, + pixel *src2, intptr_t i_src2_stride, int i_width, int i_height ) +{ + for( int y = 0; y < i_height; y++ ) + { + for( int x = 0; x < i_width; x++ ) + dst[x] = ( src1[x] + src2[x] + 1 ) >> 1; + dst += i_dst_stride; + src1 += i_src1_stride; + src2 += i_src2_stride; + } +} + +static inline void pixel_avg_wxh( pixel *dst, intptr_t i_dst, + pixel *src1, intptr_t i_src1, + pixel *src2, intptr_t i_src2, int width, int height ) +{ + for( int y = 0; y < height; y++ ) + { + for( int x = 0; x < width; x++ ) + dst[x] = ( src1[x] + src2[x] + 1 ) >> 1; + src1 += i_src1; + src2 += i_src2; + dst += i_dst; + } +} + +/* Implicit weighted bipred only: + * assumes log2_denom = 5, offset = 0, weight1 + weight2 = 64 */ +static inline void pixel_avg_weight_wxh( pixel *dst, intptr_t i_dst, + pixel *src1, intptr_t i_src1, + pixel *src2, intptr_t i_src2, int width, int height, int i_weight1 ) +{ + int i_weight2 = 64 - i_weight1; + for( int y = 0; y> 6 ); +} +#undef op_scale2 + +#define PIXEL_AVG_C( name, width, height ) \ +static void name( pixel *pix1, intptr_t i_stride_pix1, \ + pixel *pix2, intptr_t i_stride_pix2, \ + pixel *pix3, intptr_t i_stride_pix3, int weight ) \ +{ \ + if( weight == 32 ) \ + pixel_avg_wxh( pix1, i_stride_pix1, pix2, i_stride_pix2, pix3, i_stride_pix3, width, height ); \ + else \ + pixel_avg_weight_wxh( pix1, i_stride_pix1, pix2, i_stride_pix2, pix3, i_stride_pix3, width, height, weight ); \ +} +PIXEL_AVG_C( pixel_avg_16x16, 16, 16 ) +PIXEL_AVG_C( pixel_avg_16x8, 16, 8 ) +PIXEL_AVG_C( pixel_avg_8x16, 8, 16 ) +PIXEL_AVG_C( pixel_avg_8x8, 8, 8 ) +PIXEL_AVG_C( pixel_avg_8x4, 8, 4 ) +PIXEL_AVG_C( pixel_avg_4x16, 4, 16 ) +PIXEL_AVG_C( pixel_avg_4x8, 4, 8 ) +PIXEL_AVG_C( pixel_avg_4x4, 4, 4 ) +PIXEL_AVG_C( pixel_avg_4x2, 4, 2 ) +PIXEL_AVG_C( pixel_avg_2x8, 2, 8 ) +PIXEL_AVG_C( pixel_avg_2x4, 2, 4 ) +PIXEL_AVG_C( pixel_avg_2x2, 2, 2 ) + +static void x264_weight_cache( x264_t *h, x264_weight_t *w ) +{ + w->weightfn = h->mc.weight; +} +#define opscale(x) dst[x] = x264_clip_pixel( ((src[x] * scale + (1<<(denom - 1))) >> denom) + offset ) +#define opscale_noden(x) dst[x] = x264_clip_pixel( src[x] * scale + offset ) +static void mc_weight( pixel *dst, intptr_t i_dst_stride, pixel *src, intptr_t i_src_stride, + const x264_weight_t *weight, int i_width, int i_height ) +{ + int offset = weight->i_offset << (BIT_DEPTH-8); + int scale = weight->i_scale; + int denom = weight->i_denom; + if( denom >= 1 ) + { + for( int y = 0; y < i_height; y++, dst += i_dst_stride, src += i_src_stride ) + for( int x = 0; x < i_width; x++ ) + opscale( x ); + } + else + { + for( int y = 0; y < i_height; y++, dst += i_dst_stride, src += i_src_stride ) + for( int x = 0; x < i_width; x++ ) + opscale_noden( x ); + } +} + +#define MC_WEIGHT_C( name, width ) \ + static void name( pixel *dst, intptr_t i_dst_stride, pixel *src, intptr_t i_src_stride, const x264_weight_t *weight, int height ) \ +{ \ + mc_weight( dst, i_dst_stride, src, i_src_stride, weight, width, height );\ +} + +MC_WEIGHT_C( mc_weight_w20, 20 ) +MC_WEIGHT_C( mc_weight_w16, 16 ) +MC_WEIGHT_C( mc_weight_w12, 12 ) +MC_WEIGHT_C( mc_weight_w8, 8 ) +MC_WEIGHT_C( mc_weight_w4, 4 ) +MC_WEIGHT_C( mc_weight_w2, 2 ) + +static weight_fn_t x264_mc_weight_wtab[6] = +{ + mc_weight_w2, + mc_weight_w4, + mc_weight_w8, + mc_weight_w12, + mc_weight_w16, + mc_weight_w20, +}; +const x264_weight_t x264_weight_none[3] = { {{0}} }; +static void mc_copy( pixel *src, intptr_t i_src_stride, pixel *dst, intptr_t i_dst_stride, int i_width, int i_height ) +{ + for( int y = 0; y < i_height; y++ ) + { + memcpy( dst, src, i_width * sizeof(pixel) ); + + src += i_src_stride; + dst += i_dst_stride; + } +} + +#define TAPFILTER(pix, d) ((pix)[x-2*d] + (pix)[x+3*d] - 5*((pix)[x-d] + (pix)[x+2*d]) + 20*((pix)[x] + (pix)[x+d])) +static void hpel_filter( pixel *dsth, pixel *dstv, pixel *dstc, pixel *src, + intptr_t stride, int width, int height, int16_t *buf ) +{ + const int pad = (BIT_DEPTH > 9) ? (-10 * PIXEL_MAX) : 0; + for( int y = 0; y < height; y++ ) + { + for( int x = -2; x < width+3; x++ ) + { + int v = TAPFILTER(src,stride); + dstv[x] = x264_clip_pixel( (v + 16) >> 5 ); + /* transform v for storage in a 16-bit integer */ + buf[x+2] = v + pad; + } + for( int x = 0; x < width; x++ ) + dstc[x] = x264_clip_pixel( (TAPFILTER(buf+2,1) - 32*pad + 512) >> 10 ); + for( int x = 0; x < width; x++ ) + dsth[x] = x264_clip_pixel( (TAPFILTER(src,1) + 16) >> 5 ); + dsth += stride; + dstv += stride; + dstc += stride; + src += stride; + } +} + +const uint8_t x264_hpel_ref0[16] = {0,1,1,1,0,1,1,1,2,3,3,3,0,1,1,1}; +const uint8_t x264_hpel_ref1[16] = {0,0,1,0,2,2,3,2,2,2,3,2,2,2,3,2}; + +static void mc_luma( pixel *dst, intptr_t i_dst_stride, + pixel *src[4], intptr_t i_src_stride, + int mvx, int mvy, + int i_width, int i_height, const x264_weight_t *weight ) +{ + int qpel_idx = ((mvy&3)<<2) + (mvx&3); + int offset = (mvy>>2)*i_src_stride + (mvx>>2); + pixel *src1 = src[x264_hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride; + + if( qpel_idx & 5 ) /* qpel interpolation needed */ + { + pixel *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3); + pixel_avg( dst, i_dst_stride, src1, i_src_stride, + src2, i_src_stride, i_width, i_height ); + if( weight->weightfn ) + mc_weight( dst, i_dst_stride, dst, i_dst_stride, weight, i_width, i_height ); + } + else if( weight->weightfn ) + mc_weight( dst, i_dst_stride, src1, i_src_stride, weight, i_width, i_height ); + else + mc_copy( src1, i_src_stride, dst, i_dst_stride, i_width, i_height ); +} + +static pixel *get_ref( pixel *dst, intptr_t *i_dst_stride, + pixel *src[4], intptr_t i_src_stride, + int mvx, int mvy, + int i_width, int i_height, const x264_weight_t *weight ) +{ + int qpel_idx = ((mvy&3)<<2) + (mvx&3); + int offset = (mvy>>2)*i_src_stride + (mvx>>2); + pixel *src1 = src[x264_hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride; + + if( qpel_idx & 5 ) /* qpel interpolation needed */ + { + pixel *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3); + pixel_avg( dst, *i_dst_stride, src1, i_src_stride, + src2, i_src_stride, i_width, i_height ); + if( weight->weightfn ) + mc_weight( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_width, i_height ); + return dst; + } + else if( weight->weightfn ) + { + mc_weight( dst, *i_dst_stride, src1, i_src_stride, weight, i_width, i_height ); + return dst; + } + else + { + *i_dst_stride = i_src_stride; + return src1; + } +} + +/* full chroma mc (ie until 1/8 pixel)*/ +static void mc_chroma( pixel *dstu, pixel *dstv, intptr_t i_dst_stride, + pixel *src, intptr_t i_src_stride, + int mvx, int mvy, + int i_width, int i_height ) +{ + pixel *srcp; + + int d8x = mvx&0x07; + int d8y = mvy&0x07; + int cA = (8-d8x)*(8-d8y); + int cB = d8x *(8-d8y); + int cC = (8-d8x)*d8y; + int cD = d8x *d8y; + + src += (mvy >> 3) * i_src_stride + (mvx >> 3)*2; + srcp = &src[i_src_stride]; + + for( int y = 0; y < i_height; y++ ) + { + for( int x = 0; x < i_width; x++ ) + { + dstu[x] = ( cA*src[2*x] + cB*src[2*x+2] + + cC*srcp[2*x] + cD*srcp[2*x+2] + 32 ) >> 6; + dstv[x] = ( cA*src[2*x+1] + cB*src[2*x+3] + + cC*srcp[2*x+1] + cD*srcp[2*x+3] + 32 ) >> 6; + } + dstu += i_dst_stride; + dstv += i_dst_stride; + src = srcp; + srcp += i_src_stride; + } +} + +#define MC_COPY(W) \ +static void mc_copy_w##W( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int i_height ) \ +{ \ + mc_copy( src, i_src, dst, i_dst, W, i_height ); \ +} +MC_COPY( 16 ) +MC_COPY( 8 ) +MC_COPY( 4 ) + +void x264_plane_copy_c( pixel *dst, intptr_t i_dst, + pixel *src, intptr_t i_src, int w, int h ) +{ + while( h-- ) + { + memcpy( dst, src, w * sizeof(pixel) ); + dst += i_dst; + src += i_src; + } +} + +void x264_plane_copy_swap_c( pixel *dst, intptr_t i_dst, + pixel *src, intptr_t i_src, int w, int h ) +{ + for( int y=0; y>8)&0xff00) + (x>>24); +} +#else +#define v210_endian_fix32(x) (x) +#endif + +static void x264_plane_copy_deinterleave_v210_c( pixel *dsty, intptr_t i_dsty, + pixel *dstc, intptr_t i_dstc, + uint32_t *src, intptr_t i_src, int w, int h ) +{ + for( int l = 0; l < h; l++ ) + { + pixel *dsty0 = dsty; + pixel *dstc0 = dstc; + uint32_t *src0 = src; + + for( int n = 0; n < w; n += 3 ) + { + uint32_t s = v210_endian_fix32( *src0++ ); + *dstc0++ = s & 0x03FF; + *dsty0++ = (s >> 10) & 0x03FF; + *dstc0++ = (s >> 20) & 0x03FF; + s = v210_endian_fix32( *src0++ ); + *dsty0++ = s & 0x03FF; + *dstc0++ = (s >> 10) & 0x03FF; + *dsty0++ = (s >> 20) & 0x03FF; + } + + dsty += i_dsty; + dstc += i_dstc; + src += i_src; + } +} + +static void store_interleave_chroma( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ) +{ + for( int y=0; yplane[0]; + int i_stride = frame->i_stride[0]; + int i_height = frame->i_lines[0]; + int i_width = frame->i_width[0]; + + // duplicate last row and column so that their interpolation doesn't have to be special-cased + for( int y = 0; y < i_height; y++ ) + src[i_width+y*i_stride] = src[i_width-1+y*i_stride]; + memcpy( src+i_stride*i_height, src+i_stride*(i_height-1), (i_width+1) * sizeof(pixel) ); + h->mc.frame_init_lowres_core( src, frame->lowres[0], frame->lowres[1], frame->lowres[2], frame->lowres[3], + i_stride, frame->i_stride_lowres, frame->i_width_lowres, frame->i_lines_lowres ); + x264_frame_expand_border_lowres( frame ); + + memset( frame->i_cost_est, -1, sizeof(frame->i_cost_est) ); + + for( int y = 0; y < h->param.i_bframe + 2; y++ ) + for( int x = 0; x < h->param.i_bframe + 2; x++ ) + frame->i_row_satds[y][x][0] = -1; + + for( int y = 0; y <= !!h->param.i_bframe; y++ ) + for( int x = 0; x <= h->param.i_bframe; x++ ) + frame->lowres_mvs[y][x][0][0] = 0x7FFF; +} + +static void frame_init_lowres_core( pixel *src0, pixel *dst0, pixel *dsth, pixel *dstv, pixel *dstc, + intptr_t src_stride, intptr_t dst_stride, int width, int height ) +{ + for( int y = 0; y < height; y++ ) + { + pixel *src1 = src0+src_stride; + pixel *src2 = src1+src_stride; + for( int x = 0; x>1)+((c+d+1)>>1)+1)>>1) + dst0[x] = FILTER(src0[2*x ], src1[2*x ], src0[2*x+1], src1[2*x+1]); + dsth[x] = FILTER(src0[2*x+1], src1[2*x+1], src0[2*x+2], src1[2*x+2]); + dstv[x] = FILTER(src1[2*x ], src2[2*x ], src1[2*x+1], src2[2*x+1]); + dstc[x] = FILTER(src1[2*x+1], src2[2*x+1], src1[2*x+2], src2[2*x+2]); +#undef FILTER + } + src0 += src_stride*2; + dst0 += dst_stride; + dsth += dst_stride; + dstv += dst_stride; + dstc += dst_stride; + } +} + +/* Estimate the total amount of influence on future quality that could be had if we + * were to improve the reference samples used to inter predict any given macroblock. */ +static void mbtree_propagate_cost( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ) +{ + float fps = *fps_factor; + for( int i = 0; i < len; i++ ) + { + int intra_cost = intra_costs[i]; + int inter_cost = X264_MIN(intra_costs[i], inter_costs[i] & LOWRES_COST_MASK); + float propagate_intra = intra_cost * inv_qscales[i]; + float propagate_amount = propagate_in[i] + propagate_intra*fps; + float propagate_num = intra_cost - inter_cost; + float propagate_denom = intra_cost; + dst[i] = X264_MIN((int)(propagate_amount * propagate_num / propagate_denom + 0.5f), 32767); + } +} + +static void mbtree_propagate_list( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2], + int16_t *propagate_amount, uint16_t *lowres_costs, + int bipred_weight, int mb_y, int len, int list ) +{ + unsigned stride = h->mb.i_mb_stride; + unsigned width = h->mb.i_mb_width; + unsigned height = h->mb.i_mb_height; + + for( unsigned i = 0; i < len; i++ ) + { + int lists_used = lowres_costs[i]>>LOWRES_COST_SHIFT; + + if( !(lists_used & (1 << list)) ) + continue; + + int listamount = propagate_amount[i]; + /* Apply bipred weighting. */ + if( lists_used == 3 ) + listamount = (listamount * bipred_weight + 32) >> 6; + + /* Early termination for simple case of mv0. */ + if( !M32( mvs[i] ) ) + { + MC_CLIP_ADD( ref_costs[mb_y*stride + i], listamount ); + continue; + } + + int x = mvs[i][0]; + int y = mvs[i][1]; + unsigned mbx = (x>>5)+i; + unsigned mby = (y>>5)+mb_y; + unsigned idx0 = mbx + mby * stride; + unsigned idx2 = idx0 + stride; + x &= 31; + y &= 31; + int idx0weight = (32-y)*(32-x); + int idx1weight = (32-y)*x; + int idx2weight = y*(32-x); + int idx3weight = y*x; + idx0weight = (idx0weight * listamount + 512) >> 10; + idx1weight = (idx1weight * listamount + 512) >> 10; + idx2weight = (idx2weight * listamount + 512) >> 10; + idx3weight = (idx3weight * listamount + 512) >> 10; + + if( mbx < width-1 && mby < height-1 ) + { + MC_CLIP_ADD( ref_costs[idx0+0], idx0weight ); + MC_CLIP_ADD( ref_costs[idx0+1], idx1weight ); + MC_CLIP_ADD( ref_costs[idx2+0], idx2weight ); + MC_CLIP_ADD( ref_costs[idx2+1], idx3weight ); + } + else + { + /* Note: this takes advantage of unsigned representation to + * catch negative mbx/mby. */ + if( mby < height ) + { + if( mbx < width ) + MC_CLIP_ADD( ref_costs[idx0+0], idx0weight ); + if( mbx+1 < width ) + MC_CLIP_ADD( ref_costs[idx0+1], idx1weight ); + } + if( mby+1 < height ) + { + if( mbx < width ) + MC_CLIP_ADD( ref_costs[idx2+0], idx2weight ); + if( mbx+1 < width ) + MC_CLIP_ADD( ref_costs[idx2+1], idx3weight ); + } + } + } +} + +/* Conversion between float and Q8.8 fixed point (big-endian) for storage */ +static void mbtree_fix8_pack( uint16_t *dst, float *src, int count ) +{ + for( int i = 0; i < count; i++ ) + dst[i] = endian_fix16( (int16_t)(src[i] * 256.0f) ); +} + +static void mbtree_fix8_unpack( float *dst, uint16_t *src, int count ) +{ + for( int i = 0; i < count; i++ ) + dst[i] = (int16_t)endian_fix16( src[i] ) * (1.0f/256.0f); +} + +void x264_mc_init( int cpu, x264_mc_functions_t *pf, int cpu_independent ) +{ + pf->mc_luma = mc_luma; + pf->get_ref = get_ref; + + pf->mc_chroma = mc_chroma; + + pf->avg[PIXEL_16x16]= pixel_avg_16x16; + pf->avg[PIXEL_16x8] = pixel_avg_16x8; + pf->avg[PIXEL_8x16] = pixel_avg_8x16; + pf->avg[PIXEL_8x8] = pixel_avg_8x8; + pf->avg[PIXEL_8x4] = pixel_avg_8x4; + pf->avg[PIXEL_4x16] = pixel_avg_4x16; + pf->avg[PIXEL_4x8] = pixel_avg_4x8; + pf->avg[PIXEL_4x4] = pixel_avg_4x4; + pf->avg[PIXEL_4x2] = pixel_avg_4x2; + pf->avg[PIXEL_2x8] = pixel_avg_2x8; + pf->avg[PIXEL_2x4] = pixel_avg_2x4; + pf->avg[PIXEL_2x2] = pixel_avg_2x2; + + pf->weight = x264_mc_weight_wtab; + pf->offsetadd = x264_mc_weight_wtab; + pf->offsetsub = x264_mc_weight_wtab; + pf->weight_cache = x264_weight_cache; + + pf->copy_16x16_unaligned = mc_copy_w16; + pf->copy[PIXEL_16x16] = mc_copy_w16; + pf->copy[PIXEL_8x8] = mc_copy_w8; + pf->copy[PIXEL_4x4] = mc_copy_w4; + + pf->store_interleave_chroma = store_interleave_chroma; + pf->load_deinterleave_chroma_fenc = load_deinterleave_chroma_fenc; + pf->load_deinterleave_chroma_fdec = load_deinterleave_chroma_fdec; + + pf->plane_copy = x264_plane_copy_c; + pf->plane_copy_swap = x264_plane_copy_swap_c; + pf->plane_copy_interleave = x264_plane_copy_interleave_c; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_c; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_c; + pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_c; + pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_c; + + pf->hpel_filter = hpel_filter; + + pf->prefetch_fenc_420 = prefetch_fenc_null; + pf->prefetch_fenc_422 = prefetch_fenc_null; + pf->prefetch_ref = prefetch_ref_null; + pf->memcpy_aligned = memcpy; + pf->memzero_aligned = memzero_aligned; + pf->frame_init_lowres_core = frame_init_lowres_core; + + pf->integral_init4h = integral_init4h; + pf->integral_init8h = integral_init8h; + pf->integral_init4v = integral_init4v; + pf->integral_init8v = integral_init8v; + + pf->mbtree_propagate_cost = mbtree_propagate_cost; + pf->mbtree_propagate_list = mbtree_propagate_list; + pf->mbtree_fix8_pack = mbtree_fix8_pack; + pf->mbtree_fix8_unpack = mbtree_fix8_unpack; + +#if HAVE_MMX + x264_mc_init_mmx( cpu, pf ); +#endif +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + x264_mc_init_altivec( pf ); +#endif +#if HAVE_ARMV6 + x264_mc_init_arm( cpu, pf ); +#endif +#if ARCH_AARCH64 + x264_mc_init_aarch64( cpu, pf ); +#endif +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + x264_mc_init_mips( cpu, pf ); +#endif + + if( cpu_independent ) + { + pf->mbtree_propagate_cost = mbtree_propagate_cost; + pf->mbtree_propagate_list = mbtree_propagate_list; + } +} + +void x264_frame_filter( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ) +{ + const int b_interlaced = PARAM_INTERLACED; + int start = mb_y*16 - 8; // buffer = 4 for deblock + 3 for 6tap, rounded to 8 + int height = (b_end ? frame->i_lines[0] + 16*PARAM_INTERLACED : (mb_y+b_interlaced)*16) + 8; + + if( mb_y & b_interlaced ) + return; + + for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ ) + { + int stride = frame->i_stride[p]; + const int width = frame->i_width[p]; + int offs = start*stride - 8; // buffer = 3 for 6tap, aligned to 8 for simd + + if( !b_interlaced || h->mb.b_adaptive_mbaff ) + h->mc.hpel_filter( + frame->filtered[p][1] + offs, + frame->filtered[p][2] + offs, + frame->filtered[p][3] + offs, + frame->plane[p] + offs, + stride, width + 16, height - start, + h->scratch_buffer ); + + if( b_interlaced ) + { + /* MC must happen between pixels in the same field. */ + stride = frame->i_stride[p] << 1; + start = (mb_y*16 >> 1) - 8; + int height_fld = ((b_end ? frame->i_lines[p] : mb_y*16) >> 1) + 8; + offs = start*stride - 8; + for( int i = 0; i < 2; i++, offs += frame->i_stride[p] ) + { + h->mc.hpel_filter( + frame->filtered_fld[p][1] + offs, + frame->filtered_fld[p][2] + offs, + frame->filtered_fld[p][3] + offs, + frame->plane_fld[p] + offs, + stride, width + 16, height_fld - start, + h->scratch_buffer ); + } + } + } + + /* generate integral image: + * frame->integral contains 2 planes. in the upper plane, each element is + * the sum of an 8x8 pixel region with top-left corner on that point. + * in the lower plane, 4x4 sums (needed only with --partitions p4x4). */ + + if( frame->integral ) + { + int stride = frame->i_stride[0]; + if( start < 0 ) + { + memset( frame->integral - PADV * stride - PADH, 0, stride * sizeof(uint16_t) ); + start = -PADV; + } + if( b_end ) + height += PADV-9; + for( int y = start; y < height; y++ ) + { + pixel *pix = frame->plane[0] + y * stride - PADH; + uint16_t *sum8 = frame->integral + (y+1) * stride - PADH; + uint16_t *sum4; + if( h->frames.b_have_sub8x8_esa ) + { + h->mc.integral_init4h( sum8, pix, stride ); + sum8 -= 8*stride; + sum4 = sum8 + stride * (frame->i_lines[0] + PADV*2); + if( y >= 8-PADV ) + h->mc.integral_init4v( sum8, sum4, stride ); + } + else + { + h->mc.integral_init8h( sum8, pix, stride ); + if( y >= 8-PADV ) + h->mc.integral_init8v( sum8-8*stride, stride ); + } + } + } +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mc.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mc.h new file mode 100644 index 00000000..f3e7079d --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mc.h @@ -0,0 +1,340 @@ +/***************************************************************************** + * mc.h: motion compensation + ***************************************************************************** + * Copyright (C) 2004-2017 x264 project + * + * Authors: Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_MC_H +#define X264_MC_H + +#define MC_CLIP_ADD(s,x) (s) = X264_MIN((s)+(x),(1<<15)-1) +#define MC_CLIP_ADD2(s,x)\ +do\ +{\ + MC_CLIP_ADD((s)[0], (x)[0]);\ + MC_CLIP_ADD((s)[1], (x)[1]);\ +} while( 0 ) + +#define PROPAGATE_LIST(cpu)\ +void x264_mbtree_propagate_list_internal_##cpu( int16_t (*mvs)[2], int16_t *propagate_amount,\ + uint16_t *lowres_costs, int16_t *output,\ + int bipred_weight, int mb_y, int len );\ +\ +static void x264_mbtree_propagate_list_##cpu( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2],\ + int16_t *propagate_amount, uint16_t *lowres_costs,\ + int bipred_weight, int mb_y, int len, int list )\ +{\ + int16_t *current = h->scratch_buffer2;\ +\ + x264_mbtree_propagate_list_internal_##cpu( mvs, propagate_amount, lowres_costs,\ + current, bipred_weight, mb_y, len );\ +\ + unsigned stride = h->mb.i_mb_stride;\ + unsigned width = h->mb.i_mb_width;\ + unsigned height = h->mb.i_mb_height;\ +\ + for( unsigned i = 0; i < len; current += 32 )\ + {\ + int end = X264_MIN( i+8, len );\ + for( ; i < end; i++, current += 2 )\ + {\ + if( !(lowres_costs[i] & (1 << (list+LOWRES_COST_SHIFT))) )\ + continue;\ +\ + unsigned mbx = current[0];\ + unsigned mby = current[1];\ + unsigned idx0 = mbx + mby * stride;\ + unsigned idx2 = idx0 + stride;\ +\ + /* Shortcut for the simple/common case of zero MV */\ + if( !M32( mvs[i] ) )\ + {\ + MC_CLIP_ADD( ref_costs[idx0], current[16] );\ + continue;\ + }\ +\ + if( mbx < width-1 && mby < height-1 )\ + {\ + MC_CLIP_ADD2( ref_costs+idx0, current+16 );\ + MC_CLIP_ADD2( ref_costs+idx2, current+32 );\ + }\ + else\ + {\ + /* Note: this takes advantage of unsigned representation to\ + * catch negative mbx/mby. */\ + if( mby < height )\ + {\ + if( mbx < width )\ + MC_CLIP_ADD( ref_costs[idx0+0], current[16] );\ + if( mbx+1 < width )\ + MC_CLIP_ADD( ref_costs[idx0+1], current[17] );\ + }\ + if( mby+1 < height )\ + {\ + if( mbx < width )\ + MC_CLIP_ADD( ref_costs[idx2+0], current[32] );\ + if( mbx+1 < width )\ + MC_CLIP_ADD( ref_costs[idx2+1], current[33] );\ + }\ + }\ + }\ + }\ +} + +void x264_plane_copy_c( pixel *, intptr_t, pixel *, intptr_t, int w, int h ); + +#define PLANE_COPY(align, cpu)\ +static void x264_plane_copy_##cpu( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int w, int h )\ +{\ + int c_w = (align) / sizeof(pixel) - 1;\ + if( w < 256 ) /* tiny resolutions don't want non-temporal hints. dunno the exact threshold. */\ + x264_plane_copy_c( dst, i_dst, src, i_src, w, h );\ + else if( !(w&c_w) )\ + x264_plane_copy_core_##cpu( dst, i_dst, src, i_src, w, h );\ + else\ + {\ + if( --h > 0 )\ + {\ + if( i_src > 0 )\ + {\ + x264_plane_copy_core_##cpu( dst, i_dst, src, i_src, (w+c_w)&~c_w, h );\ + dst += i_dst * h;\ + src += i_src * h;\ + }\ + else\ + x264_plane_copy_core_##cpu( dst+i_dst, i_dst, src+i_src, i_src, (w+c_w)&~c_w, h );\ + }\ + /* use plain memcpy on the last line (in memory order) to avoid overreading src. */\ + memcpy( dst, src, w*sizeof(pixel) );\ + }\ +} + +void x264_plane_copy_swap_c( pixel *, intptr_t, pixel *, intptr_t, int w, int h ); + +#define PLANE_COPY_SWAP(align, cpu)\ +static void x264_plane_copy_swap_##cpu( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int w, int h )\ +{\ + int c_w = (align>>1) / sizeof(pixel) - 1;\ + if( !(w&c_w) )\ + x264_plane_copy_swap_core_##cpu( dst, i_dst, src, i_src, w, h );\ + else if( w > c_w )\ + {\ + if( --h > 0 )\ + {\ + if( i_src > 0 )\ + {\ + x264_plane_copy_swap_core_##cpu( dst, i_dst, src, i_src, (w+c_w)&~c_w, h );\ + dst += i_dst * h;\ + src += i_src * h;\ + }\ + else\ + x264_plane_copy_swap_core_##cpu( dst+i_dst, i_dst, src+i_src, i_src, (w+c_w)&~c_w, h );\ + }\ + x264_plane_copy_swap_core_##cpu( dst, 0, src, 0, w&~c_w, 1 );\ + for( int x = 2*(w&~c_w); x < 2*w; x += 2 )\ + {\ + dst[x] = src[x+1];\ + dst[x+1] = src[x];\ + }\ + }\ + else\ + x264_plane_copy_swap_c( dst, i_dst, src, i_src, w, h );\ +} + +void x264_plane_copy_deinterleave_c( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, + pixel *src, intptr_t i_src, int w, int h ); + +/* We can utilize existing plane_copy_deinterleave() functions for YUYV/UYUV + * input with the additional constraint that we cannot overread src. */ +#define PLANE_COPY_YUYV(align, cpu)\ +static void x264_plane_copy_deinterleave_yuyv_##cpu( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb,\ + pixel *src, intptr_t i_src, int w, int h )\ +{\ + int c_w = (align>>1) / sizeof(pixel) - 1;\ + if( !(w&c_w) )\ + x264_plane_copy_deinterleave_##cpu( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\ + else if( w > c_w )\ + {\ + if( --h > 0 )\ + {\ + if( i_src > 0 )\ + {\ + x264_plane_copy_deinterleave_##cpu( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\ + dsta += i_dsta * h;\ + dstb += i_dstb * h;\ + src += i_src * h;\ + }\ + else\ + x264_plane_copy_deinterleave_##cpu( dsta+i_dsta, i_dsta, dstb+i_dstb, i_dstb,\ + src+i_src, i_src, w, h );\ + }\ + x264_plane_copy_deinterleave_c( dsta, 0, dstb, 0, src, 0, w, 1 );\ + }\ + else\ + x264_plane_copy_deinterleave_c( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\ +} + +void x264_plane_copy_interleave_c( pixel *dst, intptr_t i_dst, + pixel *srcu, intptr_t i_srcu, + pixel *srcv, intptr_t i_srcv, int w, int h ); + +#define PLANE_INTERLEAVE(cpu) \ +static void x264_plane_copy_interleave_##cpu( pixel *dst, intptr_t i_dst,\ + pixel *srcu, intptr_t i_srcu,\ + pixel *srcv, intptr_t i_srcv, int w, int h )\ +{\ + int c_w = 16 / sizeof(pixel) - 1;\ + if( !(w&c_w) )\ + x264_plane_copy_interleave_core_##cpu( dst, i_dst, srcu, i_srcu, srcv, i_srcv, w, h );\ + else if( w > c_w && (i_srcu ^ i_srcv) >= 0 ) /* only works correctly for strides with identical signs */\ + {\ + if( --h > 0 )\ + {\ + if( i_srcu > 0 )\ + {\ + x264_plane_copy_interleave_core_##cpu( dst, i_dst, srcu, i_srcu, srcv, i_srcv, (w+c_w)&~c_w, h );\ + dst += i_dst * h;\ + srcu += i_srcu * h;\ + srcv += i_srcv * h;\ + }\ + else\ + x264_plane_copy_interleave_core_##cpu( dst+i_dst, i_dst, srcu+i_srcu, i_srcu, srcv+i_srcv, i_srcv, (w+c_w)&~c_w, h );\ + }\ + x264_plane_copy_interleave_c( dst, 0, srcu, 0, srcv, 0, w, 1 );\ + }\ + else\ + x264_plane_copy_interleave_c( dst, i_dst, srcu, i_srcu, srcv, i_srcv, w, h );\ +} + +struct x264_weight_t; +typedef void (* weight_fn_t)( pixel *, intptr_t, pixel *,intptr_t, const struct x264_weight_t *, int ); +typedef struct x264_weight_t +{ + /* aligning the first member is a gcc hack to force the struct to be + * 16 byte aligned, as well as force sizeof(struct) to be a multiple of 16 */ + ALIGNED_16( int16_t cachea[8] ); + int16_t cacheb[8]; + int32_t i_denom; + int32_t i_scale; + int32_t i_offset; + weight_fn_t *weightfn; +} ALIGNED_16( x264_weight_t ); + +extern const x264_weight_t x264_weight_none[3]; +extern const uint8_t x264_hpel_ref0[16]; +extern const uint8_t x264_hpel_ref1[16]; + +#define SET_WEIGHT( w, b, s, d, o )\ +{\ + (w).i_scale = (s);\ + (w).i_denom = (d);\ + (w).i_offset = (o);\ + if( b )\ + h->mc.weight_cache( h, &w );\ + else\ + w.weightfn = NULL;\ +} + +/* Do the MC + * XXX: Only width = 4, 8 or 16 are valid + * width == 4 -> height == 4 or 8 + * width == 8 -> height == 4 or 8 or 16 + * width == 16-> height == 8 or 16 + * */ + +typedef struct +{ + void (*mc_luma)( pixel *dst, intptr_t i_dst, pixel **src, intptr_t i_src, + int mvx, int mvy, int i_width, int i_height, const x264_weight_t *weight ); + + /* may round up the dimensions if they're not a power of 2 */ + pixel* (*get_ref)( pixel *dst, intptr_t *i_dst, pixel **src, intptr_t i_src, + int mvx, int mvy, int i_width, int i_height, const x264_weight_t *weight ); + + /* mc_chroma may write up to 2 bytes of garbage to the right of dst, + * so it must be run from left to right. */ + void (*mc_chroma)( pixel *dstu, pixel *dstv, intptr_t i_dst, pixel *src, intptr_t i_src, + int mvx, int mvy, int i_width, int i_height ); + + void (*avg[12])( pixel *dst, intptr_t dst_stride, pixel *src1, intptr_t src1_stride, + pixel *src2, intptr_t src2_stride, int i_weight ); + + /* only 16x16, 8x8, and 4x4 defined */ + void (*copy[7])( pixel *dst, intptr_t dst_stride, pixel *src, intptr_t src_stride, int i_height ); + void (*copy_16x16_unaligned)( pixel *dst, intptr_t dst_stride, pixel *src, intptr_t src_stride, int i_height ); + + void (*store_interleave_chroma)( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); + void (*load_deinterleave_chroma_fenc)( pixel *dst, pixel *src, intptr_t i_src, int height ); + void (*load_deinterleave_chroma_fdec)( pixel *dst, pixel *src, intptr_t i_src, int height ); + + void (*plane_copy)( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int w, int h ); + void (*plane_copy_swap)( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int w, int h ); + void (*plane_copy_interleave)( pixel *dst, intptr_t i_dst, pixel *srcu, intptr_t i_srcu, + pixel *srcv, intptr_t i_srcv, int w, int h ); + /* may write up to 15 pixels off the end of each plane */ + void (*plane_copy_deinterleave)( pixel *dstu, intptr_t i_dstu, pixel *dstv, intptr_t i_dstv, + pixel *src, intptr_t i_src, int w, int h ); + void (*plane_copy_deinterleave_yuyv)( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, + pixel *src, intptr_t i_src, int w, int h ); + void (*plane_copy_deinterleave_rgb)( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb, + pixel *dstc, intptr_t i_dstc, pixel *src, intptr_t i_src, int pw, int w, int h ); + void (*plane_copy_deinterleave_v210)( pixel *dsty, intptr_t i_dsty, + pixel *dstc, intptr_t i_dstc, + uint32_t *src, intptr_t i_src, int w, int h ); + void (*hpel_filter)( pixel *dsth, pixel *dstv, pixel *dstc, pixel *src, + intptr_t i_stride, int i_width, int i_height, int16_t *buf ); + + /* prefetch the next few macroblocks of fenc or fdec */ + void (*prefetch_fenc) ( pixel *pix_y, intptr_t stride_y, pixel *pix_uv, intptr_t stride_uv, int mb_x ); + void (*prefetch_fenc_420)( pixel *pix_y, intptr_t stride_y, pixel *pix_uv, intptr_t stride_uv, int mb_x ); + void (*prefetch_fenc_422)( pixel *pix_y, intptr_t stride_y, pixel *pix_uv, intptr_t stride_uv, int mb_x ); + /* prefetch the next few macroblocks of a hpel reference frame */ + void (*prefetch_ref)( pixel *pix, intptr_t stride, int parity ); + + void *(*memcpy_aligned)( void *dst, const void *src, size_t n ); + void (*memzero_aligned)( void *dst, size_t n ); + + /* successive elimination prefilter */ + void (*integral_init4h)( uint16_t *sum, pixel *pix, intptr_t stride ); + void (*integral_init8h)( uint16_t *sum, pixel *pix, intptr_t stride ); + void (*integral_init4v)( uint16_t *sum8, uint16_t *sum4, intptr_t stride ); + void (*integral_init8v)( uint16_t *sum8, intptr_t stride ); + + void (*frame_init_lowres_core)( pixel *src0, pixel *dst0, pixel *dsth, pixel *dstv, pixel *dstc, + intptr_t src_stride, intptr_t dst_stride, int width, int height ); + weight_fn_t *weight; + weight_fn_t *offsetadd; + weight_fn_t *offsetsub; + void (*weight_cache)( x264_t *, x264_weight_t * ); + + void (*mbtree_propagate_cost)( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); + void (*mbtree_propagate_list)( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2], + int16_t *propagate_amount, uint16_t *lowres_costs, + int bipred_weight, int mb_y, int len, int list ); + void (*mbtree_fix8_pack)( uint16_t *dst, float *src, int count ); + void (*mbtree_fix8_unpack)( float *dst, uint16_t *src, int count ); +} x264_mc_functions_t; + +void x264_mc_init( int cpu, x264_mc_functions_t *pf, int cpu_independent ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mvpred.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mvpred.c new file mode 100644 index 00000000..a7e34487 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/mvpred.c @@ -0,0 +1,607 @@ +/***************************************************************************** + * mvpred.c: motion vector prediction + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Fiona Glaser + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +void x264_mb_predict_mv( x264_t *h, int i_list, int idx, int i_width, int16_t mvp[2] ) +{ + const int i8 = x264_scan8[idx]; + const int i_ref= h->mb.cache.ref[i_list][i8]; + int i_refa = h->mb.cache.ref[i_list][i8 - 1]; + int16_t *mv_a = h->mb.cache.mv[i_list][i8 - 1]; + int i_refb = h->mb.cache.ref[i_list][i8 - 8]; + int16_t *mv_b = h->mb.cache.mv[i_list][i8 - 8]; + int i_refc = h->mb.cache.ref[i_list][i8 - 8 + i_width]; + int16_t *mv_c = h->mb.cache.mv[i_list][i8 - 8 + i_width]; + + // Partitions not yet reached in scan order are unavailable. + if( (idx&3) >= 2 + (i_width&1) || i_refc == -2 ) + { + i_refc = h->mb.cache.ref[i_list][i8 - 8 - 1]; + mv_c = h->mb.cache.mv[i_list][i8 - 8 - 1]; + + if( SLICE_MBAFF + && h->mb.cache.ref[i_list][x264_scan8[0]-1] != -2 + && MB_INTERLACED != h->mb.field[h->mb.i_mb_left_xy[0]] ) + { + if( idx == 2 ) + { + mv_c = h->mb.cache.topright_mv[i_list][0]; + i_refc = h->mb.cache.topright_ref[i_list][0]; + } + else if( idx == 8 ) + { + mv_c = h->mb.cache.topright_mv[i_list][1]; + i_refc = h->mb.cache.topright_ref[i_list][1]; + } + else if( idx == 10 ) + { + mv_c = h->mb.cache.topright_mv[i_list][2]; + i_refc = h->mb.cache.topright_ref[i_list][2]; + } + } + } + if( h->mb.i_partition == D_16x8 ) + { + if( idx == 0 ) + { + if( i_refb == i_ref ) + { + CP32( mvp, mv_b ); + return; + } + } + else + { + if( i_refa == i_ref ) + { + CP32( mvp, mv_a ); + return; + } + } + } + else if( h->mb.i_partition == D_8x16 ) + { + if( idx == 0 ) + { + if( i_refa == i_ref ) + { + CP32( mvp, mv_a ); + return; + } + } + else + { + if( i_refc == i_ref ) + { + CP32( mvp, mv_c ); + return; + } + } + } + + int i_count = (i_refa == i_ref) + (i_refb == i_ref) + (i_refc == i_ref); + + if( i_count > 1 ) + { +median: + x264_median_mv( mvp, mv_a, mv_b, mv_c ); + } + else if( i_count == 1 ) + { + if( i_refa == i_ref ) + CP32( mvp, mv_a ); + else if( i_refb == i_ref ) + CP32( mvp, mv_b ); + else + CP32( mvp, mv_c ); + } + else if( i_refb == -2 && i_refc == -2 && i_refa != -2 ) + CP32( mvp, mv_a ); + else + goto median; +} + +void x264_mb_predict_mv_16x16( x264_t *h, int i_list, int i_ref, int16_t mvp[2] ) +{ + int i_refa = h->mb.cache.ref[i_list][X264_SCAN8_0 - 1]; + int16_t *mv_a = h->mb.cache.mv[i_list][X264_SCAN8_0 - 1]; + int i_refb = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8]; + int16_t *mv_b = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8]; + int i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 + 4]; + int16_t *mv_c = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 + 4]; + if( i_refc == -2 ) + { + i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 - 1]; + mv_c = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 - 1]; + } + + int i_count = (i_refa == i_ref) + (i_refb == i_ref) + (i_refc == i_ref); + + if( i_count > 1 ) + { +median: + x264_median_mv( mvp, mv_a, mv_b, mv_c ); + } + else if( i_count == 1 ) + { + if( i_refa == i_ref ) + CP32( mvp, mv_a ); + else if( i_refb == i_ref ) + CP32( mvp, mv_b ); + else + CP32( mvp, mv_c ); + } + else if( i_refb == -2 && i_refc == -2 && i_refa != -2 ) + CP32( mvp, mv_a ); + else + goto median; +} + + +void x264_mb_predict_mv_pskip( x264_t *h, int16_t mv[2] ) +{ + int i_refa = h->mb.cache.ref[0][X264_SCAN8_0 - 1]; + int i_refb = h->mb.cache.ref[0][X264_SCAN8_0 - 8]; + int16_t *mv_a = h->mb.cache.mv[0][X264_SCAN8_0 - 1]; + int16_t *mv_b = h->mb.cache.mv[0][X264_SCAN8_0 - 8]; + + if( i_refa == -2 || i_refb == -2 || + !( i_refa | M32( mv_a ) ) || + !( i_refb | M32( mv_b ) ) ) + { + M32( mv ) = 0; + } + else + x264_mb_predict_mv_16x16( h, 0, 0, mv ); +} + +static int x264_mb_predict_mv_direct16x16_temporal( x264_t *h ) +{ + int mb_x = h->mb.i_mb_x; + int mb_y = h->mb.i_mb_y; + int mb_xy = h->mb.i_mb_xy; + int type_col[2] = { h->fref[1][0]->mb_type[mb_xy], h->fref[1][0]->mb_type[mb_xy] }; + int partition_col[2] = { h->fref[1][0]->mb_partition[mb_xy], h->fref[1][0]->mb_partition[mb_xy] }; + int preshift = MB_INTERLACED; + int postshift = MB_INTERLACED; + int offset = 1; + int yshift = 1; + h->mb.i_partition = partition_col[0]; + if( PARAM_INTERLACED && h->fref[1][0]->field[mb_xy] != MB_INTERLACED ) + { + if( MB_INTERLACED ) + { + mb_y = h->mb.i_mb_y&~1; + mb_xy = mb_x + h->mb.i_mb_stride * mb_y; + type_col[0] = h->fref[1][0]->mb_type[mb_xy]; + type_col[1] = h->fref[1][0]->mb_type[mb_xy + h->mb.i_mb_stride]; + partition_col[0] = h->fref[1][0]->mb_partition[mb_xy]; + partition_col[1] = h->fref[1][0]->mb_partition[mb_xy + h->mb.i_mb_stride]; + preshift = 0; + yshift = 0; + + if( (IS_INTRA(type_col[0]) || partition_col[0] == D_16x16) && + (IS_INTRA(type_col[1]) || partition_col[1] == D_16x16) && + partition_col[0] != D_8x8 ) + h->mb.i_partition = D_16x8; + else + h->mb.i_partition = D_8x8; + } + else + { + int cur_poc = h->fdec->i_poc + h->fdec->i_delta_poc[MB_INTERLACED&h->mb.i_mb_y&1]; + int col_parity = abs(h->fref[1][0]->i_poc + h->fref[1][0]->i_delta_poc[0] - cur_poc) + >= abs(h->fref[1][0]->i_poc + h->fref[1][0]->i_delta_poc[1] - cur_poc); + mb_y = (h->mb.i_mb_y&~1) + col_parity; + mb_xy = mb_x + h->mb.i_mb_stride * mb_y; + type_col[0] = type_col[1] = h->fref[1][0]->mb_type[mb_xy]; + partition_col[0] = partition_col[1] = h->fref[1][0]->mb_partition[mb_xy]; + preshift = 1; + yshift = 2; + h->mb.i_partition = partition_col[0]; + } + offset = 0; + } + int i_mb_4x4 = 16 * h->mb.i_mb_stride * mb_y + 4 * mb_x; + int i_mb_8x8 = 4 * h->mb.i_mb_stride * mb_y + 2 * mb_x; + + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, 0 ); + + /* Don't do any checks other than the ones we have to, based + * on the size of the colocated partitions. + * Depends on the enum order: D_8x8, D_16x8, D_8x16, D_16x16 */ + int max_i8 = (D_16x16 - h->mb.i_partition) + 1; + int step = (h->mb.i_partition == D_16x8) + 1; + int width = 4 >> ((D_16x16 - h->mb.i_partition)&1); + int height = 4 >> ((D_16x16 - h->mb.i_partition)>>1); + for( int i8 = 0; i8 < max_i8; i8 += step ) + { + int x8 = i8&1; + int y8 = i8>>1; + int ypart = (SLICE_MBAFF && h->fref[1][0]->field[mb_xy] != MB_INTERLACED) ? + MB_INTERLACED ? y8*6 : 2*(h->mb.i_mb_y&1) + y8 : + 3*y8; + + if( IS_INTRA( type_col[y8] ) ) + { + x264_macroblock_cache_ref( h, 2*x8, 2*y8, width, height, 0, 0 ); + x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 0, 0 ); + x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 1, 0 ); + continue; + } + + int i_part_8x8 = i_mb_8x8 + x8 + (ypart>>1) * h->mb.i_b8_stride; + int i_ref1_ref = h->fref[1][0]->ref[0][i_part_8x8]; + int i_ref = (map_col_to_list0(i_ref1_ref>>preshift) << postshift) + (offset&i_ref1_ref&MB_INTERLACED); + + if( i_ref >= 0 ) + { + int dist_scale_factor = h->mb.dist_scale_factor[i_ref][0]; + int16_t *mv_col = h->fref[1][0]->mv[0][i_mb_4x4 + 3*x8 + ypart * h->mb.i_b4_stride]; + int16_t mv_y = (mv_col[1]<> 8; + int l0y = ( dist_scale_factor * mv_y + 128 ) >> 8; + if( h->param.i_threads > 1 && (l0y > h->mb.mv_max_spel[1] || l0y-mv_y > h->mb.mv_max_spel[1]) ) + return 0; + x264_macroblock_cache_ref( h, 2*x8, 2*y8, width, height, 0, i_ref ); + x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 0, pack16to32_mask(l0x, l0y) ); + x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 1, pack16to32_mask(l0x-mv_col[0], l0y-mv_y) ); + } + else + { + /* the collocated ref isn't in the current list0 */ + /* FIXME: we might still be able to use direct_8x8 on some partitions */ + /* FIXME: with B-pyramid + extensive ref list reordering + * (not currently used), we would also have to check + * l1mv1 like in spatial mode */ + return 0; + } + } + + return 1; +} + +static ALWAYS_INLINE int x264_mb_predict_mv_direct16x16_spatial( x264_t *h, int b_interlaced ) +{ + int8_t ref[2]; + ALIGNED_ARRAY_8( int16_t, mv,[2],[2] ); + for( int i_list = 0; i_list < 2; i_list++ ) + { + int i_refa = h->mb.cache.ref[i_list][X264_SCAN8_0 - 1]; + int16_t *mv_a = h->mb.cache.mv[i_list][X264_SCAN8_0 - 1]; + int i_refb = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8]; + int16_t *mv_b = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8]; + int i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 + 4]; + int16_t *mv_c = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 + 4]; + if( i_refc == -2 ) + { + i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 - 1]; + mv_c = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 - 1]; + } + + int i_ref = X264_MIN3( (unsigned)i_refa, (unsigned)i_refb, (unsigned)i_refc ); + if( i_ref < 0 ) + { + i_ref = -1; + M32( mv[i_list] ) = 0; + } + else + { + /* Same as x264_mb_predict_mv_16x16, but simplified to eliminate cases + * not relevant to spatial direct. */ + int i_count = (i_refa == i_ref) + (i_refb == i_ref) + (i_refc == i_ref); + + if( i_count > 1 ) + x264_median_mv( mv[i_list], mv_a, mv_b, mv_c ); + else + { + if( i_refa == i_ref ) + CP32( mv[i_list], mv_a ); + else if( i_refb == i_ref ) + CP32( mv[i_list], mv_b ); + else + CP32( mv[i_list], mv_c ); + } + } + + x264_macroblock_cache_ref( h, 0, 0, 4, 4, i_list, i_ref ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, i_list, mv[i_list] ); + ref[i_list] = i_ref; + } + + int mb_x = h->mb.i_mb_x; + int mb_y = h->mb.i_mb_y; + int mb_xy = h->mb.i_mb_xy; + int type_col[2] = { h->fref[1][0]->mb_type[mb_xy], h->fref[1][0]->mb_type[mb_xy] }; + int partition_col[2] = { h->fref[1][0]->mb_partition[mb_xy], h->fref[1][0]->mb_partition[mb_xy] }; + h->mb.i_partition = partition_col[0]; + if( b_interlaced && h->fref[1][0]->field[mb_xy] != MB_INTERLACED ) + { + if( MB_INTERLACED ) + { + mb_y = h->mb.i_mb_y&~1; + mb_xy = mb_x + h->mb.i_mb_stride * mb_y; + type_col[0] = h->fref[1][0]->mb_type[mb_xy]; + type_col[1] = h->fref[1][0]->mb_type[mb_xy + h->mb.i_mb_stride]; + partition_col[0] = h->fref[1][0]->mb_partition[mb_xy]; + partition_col[1] = h->fref[1][0]->mb_partition[mb_xy + h->mb.i_mb_stride]; + + if( (IS_INTRA(type_col[0]) || partition_col[0] == D_16x16) && + (IS_INTRA(type_col[1]) || partition_col[1] == D_16x16) && + partition_col[0] != D_8x8 ) + h->mb.i_partition = D_16x8; + else + h->mb.i_partition = D_8x8; + } + else + { + int cur_poc = h->fdec->i_poc + h->fdec->i_delta_poc[MB_INTERLACED&h->mb.i_mb_y&1]; + int col_parity = abs(h->fref[1][0]->i_poc + h->fref[1][0]->i_delta_poc[0] - cur_poc) + >= abs(h->fref[1][0]->i_poc + h->fref[1][0]->i_delta_poc[1] - cur_poc); + mb_y = (h->mb.i_mb_y&~1) + col_parity; + mb_xy = mb_x + h->mb.i_mb_stride * mb_y; + type_col[0] = type_col[1] = h->fref[1][0]->mb_type[mb_xy]; + partition_col[0] = partition_col[1] = h->fref[1][0]->mb_partition[mb_xy]; + h->mb.i_partition = partition_col[0]; + } + } + int i_mb_4x4 = b_interlaced ? 4 * (h->mb.i_b4_stride*mb_y + mb_x) : h->mb.i_b4_xy; + int i_mb_8x8 = b_interlaced ? 2 * (h->mb.i_b8_stride*mb_y + mb_x) : h->mb.i_b8_xy; + + int8_t *l1ref0 = &h->fref[1][0]->ref[0][i_mb_8x8]; + int8_t *l1ref1 = &h->fref[1][0]->ref[1][i_mb_8x8]; + int16_t (*l1mv[2])[2] = { (int16_t (*)[2]) &h->fref[1][0]->mv[0][i_mb_4x4], + (int16_t (*)[2]) &h->fref[1][0]->mv[1][i_mb_4x4] }; + + if( (M16( ref ) & 0x8080) == 0x8080 ) /* if( ref[0] < 0 && ref[1] < 0 ) */ + { + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, 0 ); + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, 0 ); + return 1; + } + + if( h->param.i_threads > 1 + && ( mv[0][1] > h->mb.mv_max_spel[1] + || mv[1][1] > h->mb.mv_max_spel[1] ) ) + { +#if 0 + fprintf(stderr, "direct_spatial: (%d,%d) (%d,%d) > %d \n", + mv[0][0], mv[0][1], mv[1][0], mv[1][1], + h->mb.mv_max_spel[1]); +#endif + return 0; + } + + if( !M64( mv ) || (!b_interlaced && IS_INTRA( type_col[0] )) || (ref[0]&&ref[1]) ) + return 1; + + /* Don't do any checks other than the ones we have to, based + * on the size of the colocated partitions. + * Depends on the enum order: D_8x8, D_16x8, D_8x16, D_16x16 */ + int max_i8 = (D_16x16 - h->mb.i_partition) + 1; + int step = (h->mb.i_partition == D_16x8) + 1; + int width = 4 >> ((D_16x16 - h->mb.i_partition)&1); + int height = 4 >> ((D_16x16 - h->mb.i_partition)>>1); + + /* col_zero_flag */ + for( int i8 = 0; i8 < max_i8; i8 += step ) + { + const int x8 = i8&1; + const int y8 = i8>>1; + int ypart = (b_interlaced && h->fref[1][0]->field[mb_xy] != MB_INTERLACED) ? + MB_INTERLACED ? y8*6 : 2*(h->mb.i_mb_y&1) + y8 : + 3*y8; + int o8 = x8 + (ypart>>1) * h->mb.i_b8_stride; + int o4 = 3*x8 + ypart * h->mb.i_b4_stride; + + if( b_interlaced && IS_INTRA( type_col[y8] ) ) + continue; + + int idx; + if( l1ref0[o8] == 0 ) + idx = 0; + else if( l1ref0[o8] < 0 && l1ref1[o8] == 0 ) + idx = 1; + else + continue; + + if( abs( l1mv[idx][o4][0] ) <= 1 && abs( l1mv[idx][o4][1] ) <= 1 ) + { + if( ref[0] == 0 ) x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 0, 0 ); + if( ref[1] == 0 ) x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 1, 0 ); + } + } + + return 1; +} + + +static int x264_mb_predict_mv_direct16x16_spatial_interlaced( x264_t *h ) +{ + return x264_mb_predict_mv_direct16x16_spatial( h, 1 ); +} + +static int x264_mb_predict_mv_direct16x16_spatial_progressive( x264_t *h ) +{ + return x264_mb_predict_mv_direct16x16_spatial( h, 0 ); +} + +int x264_mb_predict_mv_direct16x16( x264_t *h, int *b_changed ) +{ + int b_available; + if( h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_NONE ) + return 0; + else if( h->sh.b_direct_spatial_mv_pred ) + { + if( SLICE_MBAFF ) + b_available = x264_mb_predict_mv_direct16x16_spatial_interlaced( h ); + else + b_available = x264_mb_predict_mv_direct16x16_spatial_progressive( h ); + } + else + b_available = x264_mb_predict_mv_direct16x16_temporal( h ); + + if( b_changed != NULL && b_available ) + { + int changed; + + changed = M32( h->mb.cache.direct_mv[0][0] ) ^ M32( h->mb.cache.mv[0][x264_scan8[0]] ); + changed |= M32( h->mb.cache.direct_mv[1][0] ) ^ M32( h->mb.cache.mv[1][x264_scan8[0]] ); + changed |= h->mb.cache.direct_ref[0][0] ^ h->mb.cache.ref[0][x264_scan8[0]]; + changed |= h->mb.cache.direct_ref[1][0] ^ h->mb.cache.ref[1][x264_scan8[0]]; + if( !changed && h->mb.i_partition != D_16x16 ) + { + changed |= M32( h->mb.cache.direct_mv[0][3] ) ^ M32( h->mb.cache.mv[0][x264_scan8[12]] ); + changed |= M32( h->mb.cache.direct_mv[1][3] ) ^ M32( h->mb.cache.mv[1][x264_scan8[12]] ); + changed |= h->mb.cache.direct_ref[0][3] ^ h->mb.cache.ref[0][x264_scan8[12]]; + changed |= h->mb.cache.direct_ref[1][3] ^ h->mb.cache.ref[1][x264_scan8[12]]; + } + if( !changed && h->mb.i_partition == D_8x8 ) + { + changed |= M32( h->mb.cache.direct_mv[0][1] ) ^ M32( h->mb.cache.mv[0][x264_scan8[4]] ); + changed |= M32( h->mb.cache.direct_mv[1][1] ) ^ M32( h->mb.cache.mv[1][x264_scan8[4]] ); + changed |= M32( h->mb.cache.direct_mv[0][2] ) ^ M32( h->mb.cache.mv[0][x264_scan8[8]] ); + changed |= M32( h->mb.cache.direct_mv[1][2] ) ^ M32( h->mb.cache.mv[1][x264_scan8[8]] ); + changed |= h->mb.cache.direct_ref[0][1] ^ h->mb.cache.ref[0][x264_scan8[4]]; + changed |= h->mb.cache.direct_ref[1][1] ^ h->mb.cache.ref[1][x264_scan8[4]]; + changed |= h->mb.cache.direct_ref[0][2] ^ h->mb.cache.ref[0][x264_scan8[8]]; + changed |= h->mb.cache.direct_ref[1][2] ^ h->mb.cache.ref[1][x264_scan8[8]]; + } + *b_changed = changed; + if( !changed ) + return b_available; + } + + /* cache ref & mv */ + if( b_available ) + for( int l = 0; l < 2; l++ ) + { + CP32( h->mb.cache.direct_mv[l][0], h->mb.cache.mv[l][x264_scan8[ 0]] ); + CP32( h->mb.cache.direct_mv[l][1], h->mb.cache.mv[l][x264_scan8[ 4]] ); + CP32( h->mb.cache.direct_mv[l][2], h->mb.cache.mv[l][x264_scan8[ 8]] ); + CP32( h->mb.cache.direct_mv[l][3], h->mb.cache.mv[l][x264_scan8[12]] ); + h->mb.cache.direct_ref[l][0] = h->mb.cache.ref[l][x264_scan8[ 0]]; + h->mb.cache.direct_ref[l][1] = h->mb.cache.ref[l][x264_scan8[ 4]]; + h->mb.cache.direct_ref[l][2] = h->mb.cache.ref[l][x264_scan8[ 8]]; + h->mb.cache.direct_ref[l][3] = h->mb.cache.ref[l][x264_scan8[12]]; + h->mb.cache.direct_partition = h->mb.i_partition; + } + + return b_available; +} + +/* This just improves encoder performance, it's not part of the spec */ +void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[9][2], int *i_mvc ) +{ + int16_t (*mvr)[2] = h->mb.mvr[i_list][i_ref]; + int i = 0; + +#define SET_MVP(mvp) \ + { \ + CP32( mvc[i], mvp ); \ + i++; \ + } + +#define SET_IMVP(xy) \ + if( xy >= 0 ) \ + { \ + int shift = 1 + MB_INTERLACED - h->mb.field[xy]; \ + int16_t *mvp = h->mb.mvr[i_list][i_ref<<1>>shift][xy]; \ + mvc[i][0] = mvp[0]; \ + mvc[i][1] = mvp[1]<<1>>shift; \ + i++; \ + } + + /* b_direct */ + if( h->sh.i_type == SLICE_TYPE_B + && h->mb.cache.ref[i_list][x264_scan8[12]] == i_ref ) + { + SET_MVP( h->mb.cache.mv[i_list][x264_scan8[12]] ); + } + + if( i_ref == 0 && h->frames.b_have_lowres ) + { + int idx = i_list ? h->fref[1][0]->i_frame-h->fenc->i_frame-1 + : h->fenc->i_frame-h->fref[0][0]->i_frame-1; + if( idx <= h->param.i_bframe ) + { + int16_t (*lowres_mv)[2] = h->fenc->lowres_mvs[i_list][idx]; + if( lowres_mv[0][0] != 0x7fff ) + { + M32( mvc[i] ) = (M32( lowres_mv[h->mb.i_mb_xy] )*2)&0xfffeffff; + i++; + } + } + } + + /* spatial predictors */ + if( SLICE_MBAFF ) + { + SET_IMVP( h->mb.i_mb_left_xy[0] ); + SET_IMVP( h->mb.i_mb_top_xy ); + SET_IMVP( h->mb.i_mb_topleft_xy ); + SET_IMVP( h->mb.i_mb_topright_xy ); + } + else + { + SET_MVP( mvr[h->mb.i_mb_left_xy[0]] ); + SET_MVP( mvr[h->mb.i_mb_top_xy] ); + SET_MVP( mvr[h->mb.i_mb_topleft_xy] ); + SET_MVP( mvr[h->mb.i_mb_topright_xy] ); + } +#undef SET_IMVP +#undef SET_MVP + + /* temporal predictors */ + if( h->fref[0][0]->i_ref[0] > 0 ) + { + x264_frame_t *l0 = h->fref[0][0]; + int field = h->mb.i_mb_y&1; + int curpoc = h->fdec->i_poc + h->fdec->i_delta_poc[field]; + int refpoc = h->fref[i_list][i_ref>>SLICE_MBAFF]->i_poc; + refpoc += l0->i_delta_poc[field^(i_ref&1)]; + +#define SET_TMVP( dx, dy ) \ + { \ + int mb_index = h->mb.i_mb_xy + dx + dy*h->mb.i_mb_stride; \ + int scale = (curpoc - refpoc) * l0->inv_ref_poc[MB_INTERLACED&field]; \ + mvc[i][0] = (l0->mv16x16[mb_index][0]*scale + 128) >> 8; \ + mvc[i][1] = (l0->mv16x16[mb_index][1]*scale + 128) >> 8; \ + i++; \ + } + + SET_TMVP(0,0); + if( h->mb.i_mb_x < h->mb.i_mb_width-1 ) + SET_TMVP(1,0); + if( h->mb.i_mb_y < h->mb.i_mb_height-1 ) + SET_TMVP(0,1); +#undef SET_TMVP + } + + *i_mvc = i; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/opencl.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/opencl.c new file mode 100644 index 00000000..7f26ed98 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/opencl.c @@ -0,0 +1,719 @@ +/***************************************************************************** + * opencl.c: OpenCL initialization and kernel compilation + ***************************************************************************** + * Copyright (C) 2012-2017 x264 project + * + * Authors: Steve Borho + * Anton Mitrofanov + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#ifdef _WIN32 +#include +#define ocl_open LoadLibraryW( L"OpenCL" ) +#define ocl_close FreeLibrary +#define ocl_address GetProcAddress +#else +#include //dlopen, dlsym, dlclose +#if SYS_MACOSX +#define ocl_open dlopen( "/System/Library/Frameworks/OpenCL.framework/OpenCL", RTLD_NOW ) +#else +#define ocl_open dlopen( "libOpenCL.so", RTLD_NOW ) +#endif +#define ocl_close dlclose +#define ocl_address dlsym +#endif + +#define LOAD_OCL_FUNC(name, continue_on_fail)\ +{\ + ocl->name = (void*)ocl_address( ocl->library, #name );\ + if( !continue_on_fail && !ocl->name )\ + goto fail;\ +} + +/* load the library and functions we require from it */ +x264_opencl_function_t *x264_opencl_load_library( void ) +{ + x264_opencl_function_t *ocl; +#undef fail +#define fail fail0 + CHECKED_MALLOCZERO( ocl, sizeof(x264_opencl_function_t) ); +#undef fail +#define fail fail1 + ocl->library = ocl_open; + if( !ocl->library ) + goto fail; +#undef fail +#define fail fail2 + LOAD_OCL_FUNC( clBuildProgram, 0 ); + LOAD_OCL_FUNC( clCreateBuffer, 0 ); + LOAD_OCL_FUNC( clCreateCommandQueue, 0 ); + LOAD_OCL_FUNC( clCreateContext, 0 ); + LOAD_OCL_FUNC( clCreateImage2D, 0 ); + LOAD_OCL_FUNC( clCreateKernel, 0 ); + LOAD_OCL_FUNC( clCreateProgramWithBinary, 0 ); + LOAD_OCL_FUNC( clCreateProgramWithSource, 0 ); + LOAD_OCL_FUNC( clEnqueueCopyBuffer, 0 ); + LOAD_OCL_FUNC( clEnqueueMapBuffer, 0 ); + LOAD_OCL_FUNC( clEnqueueNDRangeKernel, 0 ); + LOAD_OCL_FUNC( clEnqueueReadBuffer, 0 ); + LOAD_OCL_FUNC( clEnqueueWriteBuffer, 0 ); + LOAD_OCL_FUNC( clFinish, 0 ); + LOAD_OCL_FUNC( clGetCommandQueueInfo, 0 ); + LOAD_OCL_FUNC( clGetDeviceIDs, 0 ); + LOAD_OCL_FUNC( clGetDeviceInfo, 0 ); + LOAD_OCL_FUNC( clGetKernelWorkGroupInfo, 0 ); + LOAD_OCL_FUNC( clGetPlatformIDs, 0 ); + LOAD_OCL_FUNC( clGetProgramBuildInfo, 0 ); + LOAD_OCL_FUNC( clGetProgramInfo, 0 ); + LOAD_OCL_FUNC( clGetSupportedImageFormats, 0 ); + LOAD_OCL_FUNC( clReleaseCommandQueue, 0 ); + LOAD_OCL_FUNC( clReleaseContext, 0 ); + LOAD_OCL_FUNC( clReleaseKernel, 0 ); + LOAD_OCL_FUNC( clReleaseMemObject, 0 ); + LOAD_OCL_FUNC( clReleaseProgram, 0 ); + LOAD_OCL_FUNC( clSetKernelArg, 0 ); + return ocl; +#undef fail +fail2: + ocl_close( ocl->library ); +fail1: + x264_free( ocl ); +fail0: + return NULL; +} + +void x264_opencl_close_library( x264_opencl_function_t *ocl ) +{ + if( !ocl ) + return; + ocl_close( ocl->library ); + x264_free( ocl ); +} + +/* define from recent cl_ext.h, copied here in case headers are old */ +#define CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD 0x4042 + +/* Requires full include path in case of out-of-tree builds */ +#include "common/oclobj.h" + +static int x264_detect_switchable_graphics( void ); + +/* Try to load the cached compiled program binary, verify the device context is + * still valid before reuse */ +static cl_program x264_opencl_cache_load( x264_t *h, const char *dev_name, const char *dev_vendor, const char *driver_version ) +{ + /* try to load cached program binary */ + FILE *fp = x264_fopen( h->param.psz_clbin_file, "rb" ); + if( !fp ) + return NULL; + + x264_opencl_function_t *ocl = h->opencl.ocl; + cl_program program = NULL; + uint8_t *binary = NULL; + + fseek( fp, 0, SEEK_END ); + size_t size = ftell( fp ); + rewind( fp ); + CHECKED_MALLOC( binary, size ); + + if( fread( binary, 1, size, fp ) != size ) + goto fail; + const uint8_t *ptr = (const uint8_t*)binary; + +#define CHECK_STRING( STR )\ + do {\ + size_t len = strlen( STR );\ + if( size <= len || strncmp( (char*)ptr, STR, len ) )\ + goto fail;\ + else {\ + size -= (len+1); ptr += (len+1);\ + }\ + } while( 0 ) + + CHECK_STRING( dev_name ); + CHECK_STRING( dev_vendor ); + CHECK_STRING( driver_version ); + CHECK_STRING( x264_opencl_source_hash ); +#undef CHECK_STRING + + cl_int status; + program = ocl->clCreateProgramWithBinary( h->opencl.context, 1, &h->opencl.device, &size, &ptr, NULL, &status ); + if( status != CL_SUCCESS ) + program = NULL; + +fail: + fclose( fp ); + x264_free( binary ); + return program; +} + +/* Save the compiled program binary to a file for later reuse. Device context + * is also saved in the cache file so we do not reuse stale binaries */ +static void x264_opencl_cache_save( x264_t *h, cl_program program, const char *dev_name, const char *dev_vendor, const char *driver_version ) +{ + FILE *fp = x264_fopen( h->param.psz_clbin_file, "wb" ); + if( !fp ) + { + x264_log( h, X264_LOG_INFO, "OpenCL: unable to open clbin file for write\n" ); + return; + } + + x264_opencl_function_t *ocl = h->opencl.ocl; + uint8_t *binary = NULL; + + size_t size = 0; + cl_int status = ocl->clGetProgramInfo( program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL ); + if( status != CL_SUCCESS || !size ) + { + x264_log( h, X264_LOG_INFO, "OpenCL: Unable to query program binary size, no cache file generated\n" ); + goto fail; + } + + CHECKED_MALLOC( binary, size ); + status = ocl->clGetProgramInfo( program, CL_PROGRAM_BINARIES, sizeof(uint8_t *), &binary, NULL ); + if( status != CL_SUCCESS ) + { + x264_log( h, X264_LOG_INFO, "OpenCL: Unable to query program binary, no cache file generated\n" ); + goto fail; + } + + fputs( dev_name, fp ); + fputc( '\n', fp ); + fputs( dev_vendor, fp ); + fputc( '\n', fp ); + fputs( driver_version, fp ); + fputc( '\n', fp ); + fputs( x264_opencl_source_hash, fp ); + fputc( '\n', fp ); + fwrite( binary, 1, size, fp ); + +fail: + fclose( fp ); + x264_free( binary ); + return; +} + +/* The OpenCL source under common/opencl will be merged into common/oclobj.h by + * the Makefile. It defines a x264_opencl_source byte array which we will pass + * to clCreateProgramWithSource(). We also attempt to use a cache file for the + * compiled binary, stored in the current working folder. */ +static cl_program x264_opencl_compile( x264_t *h ) +{ + x264_opencl_function_t *ocl = h->opencl.ocl; + cl_program program = NULL; + char *build_log = NULL; + + char dev_name[64]; + char dev_vendor[64]; + char driver_version[64]; + cl_int status; + status = ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_NAME, sizeof(dev_name), dev_name, NULL ); + status |= ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_VENDOR, sizeof(dev_vendor), dev_vendor, NULL ); + status |= ocl->clGetDeviceInfo( h->opencl.device, CL_DRIVER_VERSION, sizeof(driver_version), driver_version, NULL ); + if( status != CL_SUCCESS ) + return NULL; + + // Most AMD GPUs have vector registers + int vectorize = !strcmp( dev_vendor, "Advanced Micro Devices, Inc." ); + h->opencl.b_device_AMD_SI = 0; + + if( vectorize ) + { + /* Disable OpenCL on Intel/AMD switchable graphics devices */ + if( x264_detect_switchable_graphics() ) + { + x264_log( h, X264_LOG_INFO, "OpenCL acceleration disabled, switchable graphics detected\n" ); + return NULL; + } + + /* Detect AMD SouthernIsland or newer device (single-width registers) */ + cl_uint simdwidth = 4; + status = ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, sizeof(cl_uint), &simdwidth, NULL ); + if( status == CL_SUCCESS && simdwidth == 1 ) + { + vectorize = 0; + h->opencl.b_device_AMD_SI = 1; + } + } + + x264_log( h, X264_LOG_INFO, "OpenCL acceleration enabled with %s %s %s\n", dev_vendor, dev_name, h->opencl.b_device_AMD_SI ? "(SI)" : "" ); + + program = x264_opencl_cache_load( h, dev_name, dev_vendor, driver_version ); + if( !program ) + { + /* clCreateProgramWithSource() requires a pointer variable, you cannot just use &x264_opencl_source */ + x264_log( h, X264_LOG_INFO, "Compiling OpenCL kernels...\n" ); + const char *strptr = (const char*)x264_opencl_source; + size_t size = sizeof(x264_opencl_source); + program = ocl->clCreateProgramWithSource( h->opencl.context, 1, &strptr, &size, &status ); + if( status != CL_SUCCESS || !program ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: unable to create program\n" ); + return NULL; + } + } + + /* Build the program binary for the OpenCL device */ + const char *buildopts = vectorize ? "-DVECTORIZE=1" : ""; + status = ocl->clBuildProgram( program, 1, &h->opencl.device, buildopts, NULL, NULL ); + if( status == CL_SUCCESS ) + { + x264_opencl_cache_save( h, program, dev_name, dev_vendor, driver_version ); + return program; + } + + /* Compile failure, should not happen with production code. */ + + size_t build_log_len = 0; + status = ocl->clGetProgramBuildInfo( program, h->opencl.device, CL_PROGRAM_BUILD_LOG, 0, NULL, &build_log_len ); + if( status != CL_SUCCESS || !build_log_len ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to query build log\n" ); + goto fail; + } + + build_log = x264_malloc( build_log_len ); + if( !build_log ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to alloc build log\n" ); + goto fail; + } + + status = ocl->clGetProgramBuildInfo( program, h->opencl.device, CL_PROGRAM_BUILD_LOG, build_log_len, build_log, NULL ); + if( status != CL_SUCCESS ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to get build log\n" ); + goto fail; + } + + FILE *log_file = x264_fopen( "x264_kernel_build_log.txt", "w" ); + if( !log_file ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to create file x264_kernel_build_log.txt\n" ); + goto fail; + } + fwrite( build_log, 1, build_log_len, log_file ); + fclose( log_file ); + x264_log( h, X264_LOG_WARNING, "OpenCL: kernel build errors written to x264_kernel_build_log.txt\n" ); + +fail: + x264_free( build_log ); + if( program ) + ocl->clReleaseProgram( program ); + return NULL; +} + +static int x264_opencl_lookahead_alloc( x264_t *h ) +{ + if( !h->param.rc.i_lookahead ) + return -1; + + static const char *kernelnames[] = { + "mb_intra_cost_satd_8x8", + "sum_intra_cost", + "downscale_hpel", + "downscale1", + "downscale2", + "memset_int16", + "weightp_scaled_images", + "weightp_hpel", + "hierarchical_motion", + "subpel_refine", + "mode_selection", + "sum_inter_cost" + }; + + cl_kernel *kernels[] = { + &h->opencl.intra_kernel, + &h->opencl.rowsum_intra_kernel, + &h->opencl.downscale_hpel_kernel, + &h->opencl.downscale_kernel1, + &h->opencl.downscale_kernel2, + &h->opencl.memset_kernel, + &h->opencl.weightp_scaled_images_kernel, + &h->opencl.weightp_hpel_kernel, + &h->opencl.hme_kernel, + &h->opencl.subpel_refine_kernel, + &h->opencl.mode_select_kernel, + &h->opencl.rowsum_inter_kernel + }; + + x264_opencl_function_t *ocl = h->opencl.ocl; + cl_int status; + + h->opencl.lookahead_program = x264_opencl_compile( h ); + if( !h->opencl.lookahead_program ) + goto fail; + + for( int i = 0; i < ARRAY_SIZE(kernelnames); i++ ) + { + *kernels[i] = ocl->clCreateKernel( h->opencl.lookahead_program, kernelnames[i], &status ); + if( status != CL_SUCCESS ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to compile kernel '%s' (%d)\n", kernelnames[i], status ); + goto fail; + } + } + + h->opencl.page_locked_buffer = ocl->clCreateBuffer( h->opencl.context, CL_MEM_WRITE_ONLY|CL_MEM_ALLOC_HOST_PTR, PAGE_LOCKED_BUF_SIZE, NULL, &status ); + if( status != CL_SUCCESS ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to allocate page-locked buffer, error '%d'\n", status ); + goto fail; + } + h->opencl.page_locked_ptr = ocl->clEnqueueMapBuffer( h->opencl.queue, h->opencl.page_locked_buffer, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, + 0, PAGE_LOCKED_BUF_SIZE, 0, NULL, NULL, &status ); + if( status != CL_SUCCESS ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to map page-locked buffer, error '%d'\n", status ); + goto fail; + } + + return 0; +fail: + x264_opencl_lookahead_delete( h ); + return -1; +} + +static void CL_CALLBACK x264_opencl_error_notify( const char *errinfo, const void *private_info, size_t cb, void *user_data ) +{ + /* Any error notification can be assumed to be fatal to the OpenCL context. + * We need to stop using it immediately to prevent further damage. */ + x264_t *h = (x264_t*)user_data; + h->param.b_opencl = 0; + h->opencl.b_fatal_error = 1; + x264_log( h, X264_LOG_ERROR, "OpenCL: %s\n", errinfo ); + x264_log( h, X264_LOG_ERROR, "OpenCL: fatal error, aborting encode\n" ); +} + +int x264_opencl_lookahead_init( x264_t *h ) +{ + x264_opencl_function_t *ocl = h->opencl.ocl; + cl_platform_id *platforms = NULL; + cl_device_id *devices = NULL; + cl_image_format *imageType = NULL; + cl_context context = NULL; + int ret = -1; + + cl_uint numPlatforms = 0; + cl_int status = ocl->clGetPlatformIDs( 0, NULL, &numPlatforms ); + if( status != CL_SUCCESS || !numPlatforms ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to query installed platforms\n" ); + goto fail; + } + platforms = (cl_platform_id*)x264_malloc( sizeof(cl_platform_id) * numPlatforms ); + if( !platforms ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: malloc of installed platforms buffer failed\n" ); + goto fail; + } + status = ocl->clGetPlatformIDs( numPlatforms, platforms, NULL ); + if( status != CL_SUCCESS ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to query installed platforms\n" ); + goto fail; + } + + /* Select the first OpenCL platform with a GPU device that supports our + * required image (texture) formats */ + for( cl_uint i = 0; i < numPlatforms; i++ ) + { + cl_uint gpu_count = 0; + status = ocl->clGetDeviceIDs( platforms[i], CL_DEVICE_TYPE_GPU, 0, NULL, &gpu_count ); + if( status != CL_SUCCESS || !gpu_count ) + continue; + + x264_free( devices ); + devices = x264_malloc( sizeof(cl_device_id) * gpu_count ); + if( !devices ) + continue; + + status = ocl->clGetDeviceIDs( platforms[i], CL_DEVICE_TYPE_GPU, gpu_count, devices, NULL ); + if( status != CL_SUCCESS ) + continue; + + /* Find a GPU device that supports our image formats */ + for( cl_uint gpu = 0; gpu < gpu_count; gpu++ ) + { + h->opencl.device = devices[gpu]; + + /* if the user has specified an exact device ID, skip all other + * GPUs. If this device matches, allow it to continue through the + * checks for supported images, etc. */ + if( h->param.opencl_device_id && devices[gpu] != (cl_device_id)h->param.opencl_device_id ) + continue; + + cl_bool image_support = 0; + status = ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool), &image_support, NULL ); + if( status != CL_SUCCESS || !image_support ) + continue; + + if( context ) + ocl->clReleaseContext( context ); + context = ocl->clCreateContext( NULL, 1, &h->opencl.device, (void*)x264_opencl_error_notify, (void*)h, &status ); + if( status != CL_SUCCESS || !context ) + continue; + + cl_uint imagecount = 0; + status = ocl->clGetSupportedImageFormats( context, CL_MEM_READ_WRITE, CL_MEM_OBJECT_IMAGE2D, 0, NULL, &imagecount ); + if( status != CL_SUCCESS || !imagecount ) + continue; + + x264_free( imageType ); + imageType = x264_malloc( sizeof(cl_image_format) * imagecount ); + if( !imageType ) + continue; + + status = ocl->clGetSupportedImageFormats( context, CL_MEM_READ_WRITE, CL_MEM_OBJECT_IMAGE2D, imagecount, imageType, NULL ); + if( status != CL_SUCCESS ) + continue; + + int b_has_r = 0; + int b_has_rgba = 0; + for( cl_uint j = 0; j < imagecount; j++ ) + { + if( imageType[j].image_channel_order == CL_R && + imageType[j].image_channel_data_type == CL_UNSIGNED_INT32 ) + b_has_r = 1; + else if( imageType[j].image_channel_order == CL_RGBA && + imageType[j].image_channel_data_type == CL_UNSIGNED_INT8 ) + b_has_rgba = 1; + } + if( !b_has_r || !b_has_rgba ) + { + char dev_name[64]; + status = ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_NAME, sizeof(dev_name), dev_name, NULL ); + if( status == CL_SUCCESS ) + { + /* emit warning if we are discarding the user's explicit choice */ + int level = h->param.opencl_device_id ? X264_LOG_WARNING : X264_LOG_DEBUG; + x264_log( h, level, "OpenCL: %s does not support required image formats\n", dev_name ); + } + continue; + } + + /* user selection of GPU device, skip N first matches */ + if( h->param.i_opencl_device ) + { + h->param.i_opencl_device--; + continue; + } + + h->opencl.queue = ocl->clCreateCommandQueue( context, h->opencl.device, 0, &status ); + if( status != CL_SUCCESS || !h->opencl.queue ) + continue; + + h->opencl.context = context; + context = NULL; + + ret = 0; + break; + } + + if( !ret ) + break; + } + + if( !h->param.psz_clbin_file ) + h->param.psz_clbin_file = "x264_lookahead.clbin"; + + if( ret ) + x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to find a compatible device\n" ); + else + ret = x264_opencl_lookahead_alloc( h ); + +fail: + if( context ) + ocl->clReleaseContext( context ); + x264_free( imageType ); + x264_free( devices ); + x264_free( platforms ); + return ret; +} + +static void x264_opencl_lookahead_free( x264_t *h ) +{ + x264_opencl_function_t *ocl = h->opencl.ocl; + +#define RELEASE( a, f ) do { if( a ) { ocl->f( a ); a = NULL; } } while( 0 ) + RELEASE( h->opencl.downscale_hpel_kernel, clReleaseKernel ); + RELEASE( h->opencl.downscale_kernel1, clReleaseKernel ); + RELEASE( h->opencl.downscale_kernel2, clReleaseKernel ); + RELEASE( h->opencl.weightp_hpel_kernel, clReleaseKernel ); + RELEASE( h->opencl.weightp_scaled_images_kernel, clReleaseKernel ); + RELEASE( h->opencl.memset_kernel, clReleaseKernel ); + RELEASE( h->opencl.intra_kernel, clReleaseKernel ); + RELEASE( h->opencl.rowsum_intra_kernel, clReleaseKernel ); + RELEASE( h->opencl.hme_kernel, clReleaseKernel ); + RELEASE( h->opencl.subpel_refine_kernel, clReleaseKernel ); + RELEASE( h->opencl.mode_select_kernel, clReleaseKernel ); + RELEASE( h->opencl.rowsum_inter_kernel, clReleaseKernel ); + + RELEASE( h->opencl.lookahead_program, clReleaseProgram ); + + RELEASE( h->opencl.page_locked_buffer, clReleaseMemObject ); + RELEASE( h->opencl.luma_16x16_image[0], clReleaseMemObject ); + RELEASE( h->opencl.luma_16x16_image[1], clReleaseMemObject ); + for( int i = 0; i < NUM_IMAGE_SCALES; i++ ) + RELEASE( h->opencl.weighted_scaled_images[i], clReleaseMemObject ); + RELEASE( h->opencl.weighted_luma_hpel, clReleaseMemObject ); + RELEASE( h->opencl.row_satds[0], clReleaseMemObject ); + RELEASE( h->opencl.row_satds[1], clReleaseMemObject ); + RELEASE( h->opencl.mv_buffers[0], clReleaseMemObject ); + RELEASE( h->opencl.mv_buffers[1], clReleaseMemObject ); + RELEASE( h->opencl.lowres_mv_costs, clReleaseMemObject ); + RELEASE( h->opencl.mvp_buffer, clReleaseMemObject ); + RELEASE( h->opencl.lowres_costs[0], clReleaseMemObject ); + RELEASE( h->opencl.lowres_costs[1], clReleaseMemObject ); + RELEASE( h->opencl.frame_stats[0], clReleaseMemObject ); + RELEASE( h->opencl.frame_stats[1], clReleaseMemObject ); +#undef RELEASE +} + +void x264_opencl_lookahead_delete( x264_t *h ) +{ + x264_opencl_function_t *ocl = h->opencl.ocl; + + if( !ocl ) + return; + + if( h->opencl.queue ) + ocl->clFinish( h->opencl.queue ); + + x264_opencl_lookahead_free( h ); + + if( h->opencl.queue ) + { + ocl->clReleaseCommandQueue( h->opencl.queue ); + h->opencl.queue = NULL; + } + if( h->opencl.context ) + { + ocl->clReleaseContext( h->opencl.context ); + h->opencl.context = NULL; + } +} + +void x264_opencl_frame_delete( x264_frame_t *frame ) +{ + x264_opencl_function_t *ocl = frame->opencl.ocl; + + if( !ocl ) + return; + +#define RELEASEBUF(mem) do { if( mem ) { ocl->clReleaseMemObject( mem ); mem = NULL; } } while( 0 ) + for( int j = 0; j < NUM_IMAGE_SCALES; j++ ) + RELEASEBUF( frame->opencl.scaled_image2Ds[j] ); + RELEASEBUF( frame->opencl.luma_hpel ); + RELEASEBUF( frame->opencl.inv_qscale_factor ); + RELEASEBUF( frame->opencl.intra_cost ); + RELEASEBUF( frame->opencl.lowres_mvs0 ); + RELEASEBUF( frame->opencl.lowres_mvs1 ); + RELEASEBUF( frame->opencl.lowres_mv_costs0 ); + RELEASEBUF( frame->opencl.lowres_mv_costs1 ); +#undef RELEASEBUF +} + +/* OpenCL misbehaves on hybrid laptops with Intel iGPU and AMD dGPU, so + * we consult AMD's ADL interface to detect this situation and disable + * OpenCL on these machines (Linux and Windows) */ +#ifdef _WIN32 +#define ADL_API_CALL +#define ADL_CALLBACK __stdcall +#define adl_close FreeLibrary +#define adl_address GetProcAddress +#else +#define ADL_API_CALL +#define ADL_CALLBACK +#define adl_close dlclose +#define adl_address dlsym +#endif + +typedef void* ( ADL_CALLBACK *ADL_MAIN_MALLOC_CALLBACK )( int ); +typedef int ( ADL_API_CALL *ADL_MAIN_CONTROL_CREATE )( ADL_MAIN_MALLOC_CALLBACK, int ); +typedef int ( ADL_API_CALL *ADL_ADAPTER_NUMBEROFADAPTERS_GET )( int * ); +typedef int ( ADL_API_CALL *ADL_POWERXPRESS_SCHEME_GET )( int, int *, int *, int * ); +typedef int ( ADL_API_CALL *ADL_MAIN_CONTROL_DESTROY )( void ); + +#define ADL_OK 0 +#define ADL_PX_SCHEME_DYNAMIC 2 + +static void* ADL_CALLBACK adl_malloc_wrapper( int iSize ) +{ + return x264_malloc( iSize ); +} + +static int x264_detect_switchable_graphics( void ) +{ + void *hDLL; + ADL_MAIN_CONTROL_CREATE ADL_Main_Control_Create; + ADL_ADAPTER_NUMBEROFADAPTERS_GET ADL_Adapter_NumberOfAdapters_Get; + ADL_POWERXPRESS_SCHEME_GET ADL_PowerXpress_Scheme_Get; + ADL_MAIN_CONTROL_DESTROY ADL_Main_Control_Destroy; + int ret = 0; + +#ifdef _WIN32 + hDLL = LoadLibraryW( L"atiadlxx.dll" ); + if( !hDLL ) + hDLL = LoadLibraryW( L"atiadlxy.dll" ); +#else + hDLL = dlopen( "libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL ); +#endif + if( !hDLL ) + goto fail0; + + ADL_Main_Control_Create = (ADL_MAIN_CONTROL_CREATE)adl_address(hDLL, "ADL_Main_Control_Create"); + ADL_Main_Control_Destroy = (ADL_MAIN_CONTROL_DESTROY)adl_address(hDLL, "ADL_Main_Control_Destroy"); + ADL_Adapter_NumberOfAdapters_Get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)adl_address(hDLL, "ADL_Adapter_NumberOfAdapters_Get"); + ADL_PowerXpress_Scheme_Get = (ADL_POWERXPRESS_SCHEME_GET)adl_address(hDLL, "ADL_PowerXpress_Scheme_Get"); + if( !ADL_Main_Control_Create || !ADL_Main_Control_Destroy || !ADL_Adapter_NumberOfAdapters_Get || + !ADL_PowerXpress_Scheme_Get ) + goto fail1; + + if( ADL_OK != ADL_Main_Control_Create( adl_malloc_wrapper, 1 ) ) + goto fail1; + + int numAdapters = 0; + if( ADL_OK != ADL_Adapter_NumberOfAdapters_Get( &numAdapters ) ) + goto fail2; + + for( int i = 0; i < numAdapters; i++ ) + { + int PXSchemeRange, PXSchemeCurrentState, PXSchemeDefaultState; + if( ADL_OK != ADL_PowerXpress_Scheme_Get( i, &PXSchemeRange, &PXSchemeCurrentState, &PXSchemeDefaultState) ) + break; + + if( PXSchemeRange >= ADL_PX_SCHEME_DYNAMIC ) + { + ret = 1; + break; + } + } + +fail2: + ADL_Main_Control_Destroy(); +fail1: + adl_close( hDLL ); +fail0: + return ret; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/opencl.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/opencl.h new file mode 100644 index 00000000..9b0da8b7 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/opencl.h @@ -0,0 +1,804 @@ +/***************************************************************************** + * opencl.h: OpenCL structures and defines + ***************************************************************************** + * Copyright (C) 2012-2017 x264 project + * + * Authors: Steve Borho + * Anton Mitrofanov + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_OPENCL_H +#define X264_OPENCL_H + +#define CL_USE_DEPRECATED_OPENCL_1_1_APIS +#include "extras/cl.h" + +#define OCL_API(ret, attr, name) typedef ret (attr *name##_func) + +/* Platform API */ +OCL_API(cl_int, CL_API_CALL, clGetPlatformIDs) +( cl_uint /* num_entries */, + cl_platform_id * /* platforms */, + cl_uint * /* num_platforms */); + +OCL_API(cl_int, CL_API_CALL, clGetPlatformInfo) +( cl_platform_id /* platform */, + cl_platform_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +/* Device APIs */ +OCL_API(cl_int, CL_API_CALL, clGetDeviceIDs) +( cl_platform_id /* platform */, + cl_device_type /* device_type */, + cl_uint /* num_entries */, + cl_device_id * /* devices */, + cl_uint * /* num_devices */); + +OCL_API(cl_int, CL_API_CALL, clGetDeviceInfo) +( cl_device_id /* device */, + cl_device_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +OCL_API(cl_int, CL_API_CALL, clCreateSubDevices) +( cl_device_id /* in_device */, + const cl_device_partition_property * /* properties */, + cl_uint /* num_devices */, + cl_device_id * /* out_devices */, + cl_uint * /* num_devices_ret */); + +OCL_API(cl_int, CL_API_CALL, clRetainDevice) +( cl_device_id /* device */); + +OCL_API(cl_int, CL_API_CALL, clReleaseDevice) +( cl_device_id /* device */); + +/* Context APIs */ +OCL_API(cl_context, CL_API_CALL, clCreateContext) +( const cl_context_properties * /* properties */, + cl_uint /* num_devices */, + const cl_device_id * /* devices */, + void (CL_CALLBACK * /* pfn_notify */)(const char *, const void *, size_t, void *), + void * /* user_data */, + cl_int * /* errcode_ret */); + +OCL_API(cl_context, CL_API_CALL, clCreateContextFromType) +( const cl_context_properties * /* properties */, + cl_device_type /* device_type */, + void (CL_CALLBACK * /* pfn_notify*/ )(const char *, const void *, size_t, void *), + void * /* user_data */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clRetainContext) +( cl_context /* context */); + +OCL_API(cl_int, CL_API_CALL, clReleaseContext) +( cl_context /* context */); + +OCL_API(cl_int, CL_API_CALL, clGetContextInfo) +( cl_context /* context */, + cl_context_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +/* Command Queue APIs */ +OCL_API(cl_command_queue, CL_API_CALL, clCreateCommandQueue) +( cl_context /* context */, + cl_device_id /* device */, + cl_command_queue_properties /* properties */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clRetainCommandQueue) +( cl_command_queue /* command_queue */); + +OCL_API(cl_int, CL_API_CALL, clReleaseCommandQueue) +( cl_command_queue /* command_queue */); + +OCL_API(cl_int, CL_API_CALL, clGetCommandQueueInfo) +( cl_command_queue /* command_queue */, + cl_command_queue_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +/* Memory Object APIs */ +OCL_API(cl_mem, CL_API_CALL, clCreateBuffer) +( cl_context /* context */, + cl_mem_flags /* flags */, + size_t /* size */, + void * /* host_ptr */, + cl_int * /* errcode_ret */); + +OCL_API(cl_mem, CL_API_CALL, clCreateSubBuffer) +( cl_mem /* buffer */, + cl_mem_flags /* flags */, + cl_buffer_create_type /* buffer_create_type */, + const void * /* buffer_create_info */, + cl_int * /* errcode_ret */); + +OCL_API(cl_mem, CL_API_CALL, clCreateImage) +( cl_context /* context */, + cl_mem_flags /* flags */, + const cl_image_format * /* image_format */, + const cl_image_desc * /* image_desc */, + void * /* host_ptr */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clRetainMemObject) +( cl_mem /* memobj */); + +OCL_API(cl_int, CL_API_CALL, clReleaseMemObject) +( cl_mem /* memobj */); + +OCL_API(cl_int, CL_API_CALL, clGetSupportedImageFormats) +( cl_context /* context */, + cl_mem_flags /* flags */, + cl_mem_object_type /* image_type */, + cl_uint /* num_entries */, + cl_image_format * /* image_formats */, + cl_uint * /* num_image_formats */); + +OCL_API(cl_int, CL_API_CALL, clGetMemObjectInfo) +( cl_mem /* memobj */, + cl_mem_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +OCL_API(cl_int, CL_API_CALL, clGetImageInfo) +( cl_mem /* image */, + cl_image_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +OCL_API(cl_int, CL_API_CALL, clSetMemObjectDestructorCallback) +( cl_mem /* memobj */, + void (CL_CALLBACK * /*pfn_notify*/)( cl_mem /* memobj */, void* /*user_data*/), + void * /*user_data */ ); + +/* Sampler APIs */ +OCL_API(cl_sampler, CL_API_CALL, clCreateSampler) +( cl_context /* context */, + cl_bool /* normalized_coords */, + cl_addressing_mode /* addressing_mode */, + cl_filter_mode /* filter_mode */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clRetainSampler) +( cl_sampler /* sampler */); + +OCL_API(cl_int, CL_API_CALL, clReleaseSampler) +( cl_sampler /* sampler */); + +OCL_API(cl_int, CL_API_CALL, clGetSamplerInfo) +( cl_sampler /* sampler */, + cl_sampler_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +/* Program Object APIs */ +OCL_API(cl_program, CL_API_CALL, clCreateProgramWithSource) +( cl_context /* context */, + cl_uint /* count */, + const char ** /* strings */, + const size_t * /* lengths */, + cl_int * /* errcode_ret */); + +OCL_API(cl_program, CL_API_CALL, clCreateProgramWithBinary) +( cl_context /* context */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const size_t * /* lengths */, + const unsigned char ** /* binaries */, + cl_int * /* binary_status */, + cl_int * /* errcode_ret */); + +OCL_API(cl_program, CL_API_CALL, clCreateProgramWithBuiltInKernels) +( cl_context /* context */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* kernel_names */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clRetainProgram) +( cl_program /* program */); + +OCL_API(cl_int, CL_API_CALL, clReleaseProgram) +( cl_program /* program */); + +OCL_API(cl_int, CL_API_CALL, clBuildProgram) +( cl_program /* program */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* options */, + void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), + void * /* user_data */); + +OCL_API(cl_int, CL_API_CALL, clCompileProgram) +( cl_program /* program */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* options */, + cl_uint /* num_input_headers */, + const cl_program * /* input_headers */, + const char ** /* header_include_names */, + void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), + void * /* user_data */); + +OCL_API(cl_program, CL_API_CALL, clLinkProgram) +( cl_context /* context */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* options */, + cl_uint /* num_input_programs */, + const cl_program * /* input_programs */, + void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), + void * /* user_data */, + cl_int * /* errcode_ret */ ); + + +OCL_API(cl_int, CL_API_CALL, clUnloadPlatformCompiler) +( cl_platform_id /* platform */); + +OCL_API(cl_int, CL_API_CALL, clGetProgramInfo) +( cl_program /* program */, + cl_program_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +OCL_API(cl_int, CL_API_CALL, clGetProgramBuildInfo) +( cl_program /* program */, + cl_device_id /* device */, + cl_program_build_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +/* Kernel Object APIs */ +OCL_API(cl_kernel, CL_API_CALL, clCreateKernel) +( cl_program /* program */, + const char * /* kernel_name */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clCreateKernelsInProgram) +( cl_program /* program */, + cl_uint /* num_kernels */, + cl_kernel * /* kernels */, + cl_uint * /* num_kernels_ret */); + +OCL_API(cl_int, CL_API_CALL, clRetainKernel) +( cl_kernel /* kernel */); + +OCL_API(cl_int, CL_API_CALL, clReleaseKernel) +( cl_kernel /* kernel */); + +OCL_API(cl_int, CL_API_CALL, clSetKernelArg) +( cl_kernel /* kernel */, + cl_uint /* arg_index */, + size_t /* arg_size */, + const void * /* arg_value */); + +OCL_API(cl_int, CL_API_CALL, clGetKernelInfo) +( cl_kernel /* kernel */, + cl_kernel_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +OCL_API(cl_int, CL_API_CALL, clGetKernelArgInfo) +( cl_kernel /* kernel */, + cl_uint /* arg_indx */, + cl_kernel_arg_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +OCL_API(cl_int, CL_API_CALL, clGetKernelWorkGroupInfo) +( cl_kernel /* kernel */, + cl_device_id /* device */, + cl_kernel_work_group_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +/* Event Object APIs */ +OCL_API(cl_int, CL_API_CALL, clWaitForEvents) +( cl_uint /* num_events */, + const cl_event * /* event_list */); + +OCL_API(cl_int, CL_API_CALL, clGetEventInfo) +( cl_event /* event */, + cl_event_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +OCL_API(cl_event, CL_API_CALL, clCreateUserEvent) +( cl_context /* context */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clRetainEvent) +( cl_event /* event */); + +OCL_API(cl_int, CL_API_CALL, clReleaseEvent) +( cl_event /* event */); + +OCL_API(cl_int, CL_API_CALL, clSetUserEventStatus) +( cl_event /* event */, + cl_int /* execution_status */); + +OCL_API(cl_int, CL_API_CALL, clSetEventCallback) +( cl_event /* event */, + cl_int /* command_exec_callback_type */, + void (CL_CALLBACK * /* pfn_notify */)(cl_event, cl_int, void *), + void * /* user_data */); + +/* Profiling APIs */ +OCL_API(cl_int, CL_API_CALL, clGetEventProfilingInfo) +( cl_event /* event */, + cl_profiling_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */); + +/* Flush and Finish APIs */ +OCL_API(cl_int, CL_API_CALL, clFlush) +( cl_command_queue /* command_queue */); + +OCL_API(cl_int, CL_API_CALL, clFinish) +( cl_command_queue /* command_queue */); + +/* Enqueued Commands APIs */ +OCL_API(cl_int, CL_API_CALL, clEnqueueReadBuffer) +( cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_read */, + size_t /* offset */, + size_t /* size */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueReadBufferRect) +( cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_read */, + const size_t * /* buffer_offset */, + const size_t * /* host_offset */, + const size_t * /* region */, + size_t /* buffer_row_pitch */, + size_t /* buffer_slice_pitch */, + size_t /* host_row_pitch */, + size_t /* host_slice_pitch */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueWriteBuffer) +( cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_write */, + size_t /* offset */, + size_t /* size */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueWriteBufferRect) +( cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_write */, + const size_t * /* buffer_offset */, + const size_t * /* host_offset */, + const size_t * /* region */, + size_t /* buffer_row_pitch */, + size_t /* buffer_slice_pitch */, + size_t /* host_row_pitch */, + size_t /* host_slice_pitch */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueFillBuffer) +( cl_command_queue /* command_queue */, + cl_mem /* buffer */, + const void * /* pattern */, + size_t /* pattern_size */, + size_t /* offset */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueCopyBuffer) +( cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_buffer */, + size_t /* src_offset */, + size_t /* dst_offset */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueCopyBufferRect) +( cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_buffer */, + const size_t * /* src_origin */, + const size_t * /* dst_origin */, + const size_t * /* region */, + size_t /* src_row_pitch */, + size_t /* src_slice_pitch */, + size_t /* dst_row_pitch */, + size_t /* dst_slice_pitch */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueReadImage) +( cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_read */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t /* row_pitch */, + size_t /* slice_pitch */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueWriteImage) +( cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_write */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t /* input_row_pitch */, + size_t /* input_slice_pitch */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueFillImage) +( cl_command_queue /* command_queue */, + cl_mem /* image */, + const void * /* fill_color */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueCopyImage) +( cl_command_queue /* command_queue */, + cl_mem /* src_image */, + cl_mem /* dst_image */, + const size_t * /* src_origin[3] */, + const size_t * /* dst_origin[3] */, + const size_t * /* region[3] */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueCopyImageToBuffer) +( cl_command_queue /* command_queue */, + cl_mem /* src_image */, + cl_mem /* dst_buffer */, + const size_t * /* src_origin[3] */, + const size_t * /* region[3] */, + size_t /* dst_offset */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueCopyBufferToImage) +( cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_image */, + size_t /* src_offset */, + const size_t * /* dst_origin[3] */, + const size_t * /* region[3] */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(void *, CL_API_CALL, clEnqueueMapBuffer) +( cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_map */, + cl_map_flags /* map_flags */, + size_t /* offset */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */, + cl_int * /* errcode_ret */); + +OCL_API(void *, CL_API_CALL, clEnqueueMapImage) +( cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_map */, + cl_map_flags /* map_flags */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t * /* image_row_pitch */, + size_t * /* image_slice_pitch */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueUnmapMemObject) +( cl_command_queue /* command_queue */, + cl_mem /* memobj */, + void * /* mapped_ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueMigrateMemObjects) +( cl_command_queue /* command_queue */, + cl_uint /* num_mem_objects */, + const cl_mem * /* mem_objects */, + cl_mem_migration_flags /* flags */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueNDRangeKernel) +( cl_command_queue /* command_queue */, + cl_kernel /* kernel */, + cl_uint /* work_dim */, + const size_t * /* global_work_offset */, + const size_t * /* global_work_size */, + const size_t * /* local_work_size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueTask) +( cl_command_queue /* command_queue */, + cl_kernel /* kernel */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueNativeKernel) +( cl_command_queue /* command_queue */, + void (CL_CALLBACK * /*user_func*/)(void *), + void * /* args */, + size_t /* cb_args */, + cl_uint /* num_mem_objects */, + const cl_mem * /* mem_list */, + const void ** /* args_mem_loc */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueMarkerWithWaitList) +( cl_command_queue /* command_queue */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueBarrierWithWaitList) +( cl_command_queue /* command_queue */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */); + + +/* Extension function access +* +* Returns the extension function address for the given function name, +* or NULL if a valid function can not be found. The client must +* check to make sure the address is not NULL, before using or +* calling the returned function address. +*/ +OCL_API(void *, CL_API_CALL, clGetExtensionFunctionAddressForPlatform) +( cl_platform_id /* platform */, + const char * /* func_name */); + + +// Deprecated OpenCL 1.1 APIs +OCL_API(cl_mem, CL_API_CALL, clCreateImage2D) +( cl_context /* context */, + cl_mem_flags /* flags */, + const cl_image_format * /* image_format */, + size_t /* image_width */, + size_t /* image_height */, + size_t /* image_row_pitch */, + void * /* host_ptr */, + cl_int * /* errcode_ret */); + +OCL_API(cl_mem, CL_API_CALL, clCreateImage3D) +( cl_context /* context */, + cl_mem_flags /* flags */, + const cl_image_format * /* image_format */, + size_t /* image_width */, + size_t /* image_height */, + size_t /* image_depth */, + size_t /* image_row_pitch */, + size_t /* image_slice_pitch */, + void * /* host_ptr */, + cl_int * /* errcode_ret */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueMarker) +( cl_command_queue /* command_queue */, + cl_event * /* event */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueWaitForEvents) +( cl_command_queue /* command_queue */, + cl_uint /* num_events */, + const cl_event * /* event_list */); + +OCL_API(cl_int, CL_API_CALL, clEnqueueBarrier) +( cl_command_queue /* command_queue */); + +OCL_API(cl_int, CL_API_CALL, clUnloadCompiler) +( void); + +OCL_API(void *, CL_API_CALL, clGetExtensionFunctionAddress) +( const char * /* func_name */); + +#define OCL_DECLARE_FUNC(name) name##_func name + +typedef struct +{ + void *library; + + OCL_DECLARE_FUNC( clBuildProgram ); + OCL_DECLARE_FUNC( clCreateBuffer ); + OCL_DECLARE_FUNC( clCreateCommandQueue ); + OCL_DECLARE_FUNC( clCreateContext ); + OCL_DECLARE_FUNC( clCreateImage2D ); + OCL_DECLARE_FUNC( clCreateKernel ); + OCL_DECLARE_FUNC( clCreateProgramWithBinary ); + OCL_DECLARE_FUNC( clCreateProgramWithSource ); + OCL_DECLARE_FUNC( clEnqueueCopyBuffer ); + OCL_DECLARE_FUNC( clEnqueueMapBuffer ); + OCL_DECLARE_FUNC( clEnqueueNDRangeKernel ); + OCL_DECLARE_FUNC( clEnqueueReadBuffer ); + OCL_DECLARE_FUNC( clEnqueueWriteBuffer ); + OCL_DECLARE_FUNC( clFinish ); + OCL_DECLARE_FUNC( clGetCommandQueueInfo ); + OCL_DECLARE_FUNC( clGetDeviceIDs ); + OCL_DECLARE_FUNC( clGetDeviceInfo ); + OCL_DECLARE_FUNC( clGetKernelWorkGroupInfo ); + OCL_DECLARE_FUNC( clGetPlatformIDs ); + OCL_DECLARE_FUNC( clGetProgramBuildInfo ); + OCL_DECLARE_FUNC( clGetProgramInfo ); + OCL_DECLARE_FUNC( clGetSupportedImageFormats ); + OCL_DECLARE_FUNC( clReleaseCommandQueue ); + OCL_DECLARE_FUNC( clReleaseContext ); + OCL_DECLARE_FUNC( clReleaseKernel ); + OCL_DECLARE_FUNC( clReleaseMemObject ); + OCL_DECLARE_FUNC( clReleaseProgram ); + OCL_DECLARE_FUNC( clSetKernelArg ); +} x264_opencl_function_t; + +/* Number of downscale resolutions to use for motion search */ +#define NUM_IMAGE_SCALES 4 + +/* Number of PCIe copies that can be queued before requiring a flush */ +#define MAX_FINISH_COPIES 1024 + +/* Size (in bytes) of the page-locked buffer used for PCIe xfers */ +#define PAGE_LOCKED_BUF_SIZE 32 * 1024 * 1024 + +typedef struct +{ + x264_opencl_function_t *ocl; + + cl_context context; + cl_device_id device; + cl_command_queue queue; + + cl_program lookahead_program; + cl_int last_buf; + + cl_mem page_locked_buffer; + char *page_locked_ptr; + int pl_occupancy; + + struct + { + void *src; + void *dest; + int bytes; + } copies[MAX_FINISH_COPIES]; + int num_copies; + + int b_device_AMD_SI; + int b_fatal_error; + int lookahead_thread_pri; + int opencl_thread_pri; + + /* downscale lowres luma */ + cl_kernel downscale_hpel_kernel; + cl_kernel downscale_kernel1; + cl_kernel downscale_kernel2; + cl_mem luma_16x16_image[2]; + + /* weightp filtering */ + cl_kernel weightp_hpel_kernel; + cl_kernel weightp_scaled_images_kernel; + cl_mem weighted_scaled_images[NUM_IMAGE_SCALES]; + cl_mem weighted_luma_hpel; + + /* intra */ + cl_kernel memset_kernel; + cl_kernel intra_kernel; + cl_kernel rowsum_intra_kernel; + cl_mem row_satds[2]; + + /* hierarchical motion estimation */ + cl_kernel hme_kernel; + cl_kernel subpel_refine_kernel; + cl_mem mv_buffers[2]; + cl_mem lowres_mv_costs; + cl_mem mvp_buffer; + + /* bidir */ + cl_kernel mode_select_kernel; + cl_kernel rowsum_inter_kernel; + cl_mem lowres_costs[2]; + cl_mem frame_stats[2]; /* cost_est, cost_est_aq, intra_mbs */ +} x264_opencl_t; + +typedef struct +{ + x264_opencl_function_t *ocl; + + cl_mem scaled_image2Ds[NUM_IMAGE_SCALES]; + cl_mem luma_hpel; + cl_mem inv_qscale_factor; + cl_mem intra_cost; + cl_mem lowres_mvs0; + cl_mem lowres_mvs1; + cl_mem lowres_mv_costs0; + cl_mem lowres_mv_costs1; +} x264_frame_opencl_t; + +typedef struct x264_frame x264_frame; + +x264_opencl_function_t *x264_opencl_load_library( void ); +void x264_opencl_close_library( x264_opencl_function_t *ocl ); + +int x264_opencl_lookahead_init( x264_t *h ); +void x264_opencl_lookahead_delete( x264_t *h ); + +void x264_opencl_frame_delete( x264_frame *frame ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/osdep.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/osdep.c new file mode 100644 index 00000000..9bc926a1 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/osdep.c @@ -0,0 +1,206 @@ +/***************************************************************************** + * osdep.c: platform-specific code + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Steven Walters + * Laurent Aimar + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#ifdef _WIN32 +#include +#include +#endif + +#if SYS_WINDOWS +#include +#include +#else +#include +#endif +#include + +#if PTW32_STATIC_LIB +/* this is a global in pthread-win32 to indicate if it has been initialized or not */ +extern int ptw32_processInitialized; +#endif + +int64_t x264_mdate( void ) +{ +#if SYS_WINDOWS + struct timeb tb; + ftime( &tb ); + return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000; +#else + struct timeval tv_date; + gettimeofday( &tv_date, NULL ); + return (int64_t)tv_date.tv_sec * 1000000 + (int64_t)tv_date.tv_usec; +#endif +} + +#if HAVE_WIN32THREAD || PTW32_STATIC_LIB +/* state of the threading library being initialized */ +static volatile LONG x264_threading_is_init = 0; + +static void x264_threading_destroy( void ) +{ +#if PTW32_STATIC_LIB + pthread_win32_thread_detach_np(); + pthread_win32_process_detach_np(); +#else + x264_win32_threading_destroy(); +#endif +} + +int x264_threading_init( void ) +{ + /* if already init, then do nothing */ + if( InterlockedCompareExchange( &x264_threading_is_init, 1, 0 ) ) + return 0; +#if PTW32_STATIC_LIB + /* if static pthread-win32 is already initialized, then do nothing */ + if( ptw32_processInitialized ) + return 0; + if( !pthread_win32_process_attach_np() ) + return -1; +#else + if( x264_win32_threading_init() ) + return -1; +#endif + /* register cleanup to run at process termination */ + atexit( x264_threading_destroy ); + + return 0; +} +#endif + +#ifdef _WIN32 +/* Functions for dealing with Unicode on Windows. */ +FILE *x264_fopen( const char *filename, const char *mode ) +{ + wchar_t filename_utf16[MAX_PATH]; + wchar_t mode_utf16[16]; + if( utf8_to_utf16( filename, filename_utf16 ) && utf8_to_utf16( mode, mode_utf16 ) ) + return _wfopen( filename_utf16, mode_utf16 ); + return NULL; +} + +int x264_rename( const char *oldname, const char *newname ) +{ + wchar_t oldname_utf16[MAX_PATH]; + wchar_t newname_utf16[MAX_PATH]; + if( utf8_to_utf16( oldname, oldname_utf16 ) && utf8_to_utf16( newname, newname_utf16 ) ) + { + /* POSIX says that rename() removes the destination, but Win32 doesn't. */ + _wunlink( newname_utf16 ); + return _wrename( oldname_utf16, newname_utf16 ); + } + return -1; +} + +int x264_stat( const char *path, x264_struct_stat *buf ) +{ + wchar_t path_utf16[MAX_PATH]; + if( utf8_to_utf16( path, path_utf16 ) ) + return _wstati64( path_utf16, buf ); + return -1; +} + +#if !HAVE_WINRT +int x264_vfprintf( FILE *stream, const char *format, va_list arg ) +{ + HANDLE console = NULL; + DWORD mode; + + if( stream == stdout ) + console = GetStdHandle( STD_OUTPUT_HANDLE ); + else if( stream == stderr ) + console = GetStdHandle( STD_ERROR_HANDLE ); + + /* Only attempt to convert to UTF-16 when writing to a non-redirected console screen buffer. */ + if( GetConsoleMode( console, &mode ) ) + { + char buf[4096]; + wchar_t buf_utf16[4096]; + va_list arg2; + + va_copy( arg2, arg ); + int length = vsnprintf( buf, sizeof(buf), format, arg2 ); + va_end( arg2 ); + + if( length > 0 && length < sizeof(buf) ) + { + /* WriteConsoleW is the most reliable way to output Unicode to a console. */ + int length_utf16 = MultiByteToWideChar( CP_UTF8, 0, buf, length, buf_utf16, sizeof(buf_utf16)/sizeof(wchar_t) ); + DWORD written; + WriteConsoleW( console, buf_utf16, length_utf16, &written, NULL ); + return length; + } + } + return vfprintf( stream, format, arg ); +} + +int x264_is_pipe( const char *path ) +{ + wchar_t path_utf16[MAX_PATH]; + if( utf8_to_utf16( path, path_utf16 ) ) + return WaitNamedPipeW( path_utf16, 0 ); + return 0; +} +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +/* MSVC pre-VS2015 has broken snprintf/vsnprintf implementations which are incompatible with C99. */ +int x264_snprintf( char *s, size_t n, const char *fmt, ... ) +{ + va_list arg; + va_start( arg, fmt ); + int length = x264_vsnprintf( s, n, fmt, arg ); + va_end( arg ); + return length; +} + +int x264_vsnprintf( char *s, size_t n, const char *fmt, va_list arg ) +{ + int length = -1; + + if( n ) + { + va_list arg2; + va_copy( arg2, arg ); + length = _vsnprintf( s, n, fmt, arg2 ); + va_end( arg2 ); + + /* _(v)snprintf adds a null-terminator only if the length is less than the buffer size. */ + if( length < 0 || length >= n ) + s[n-1] = '\0'; + } + + /* _(v)snprintf returns a negative number if the length is greater than the buffer size. */ + if( length < 0 ) + return _vscprintf( fmt, arg ); + + return length; +} +#endif +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/osdep.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/osdep.h new file mode 100644 index 00000000..7b5de6e4 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/osdep.h @@ -0,0 +1,414 @@ +/***************************************************************************** + * osdep.h: platform-specific code + ***************************************************************************** + * Copyright (C) 2007-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_OSDEP_H +#define X264_OSDEP_H + +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#include +#include +#include +#include + +//#include "config.h" + +#ifdef __INTEL_COMPILER +#include +#else +#include +#endif + +#if !HAVE_LOG2F +#define log2f(x) (logf(x)/0.693147180559945f) +#define log2(x) (log(x)/0.693147180559945) +#endif + +#ifdef _MSC_VER +#define inline __inline +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strtok_r strtok_s +#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) +#if _MSC_VER < 1900 +int x264_snprintf( char *s, size_t n, const char *fmt, ... ); +int x264_vsnprintf( char *s, size_t n, const char *fmt, va_list arg ); +#define snprintf x264_snprintf +#define vsnprintf x264_vsnprintf +#endif +#else +#include +#endif + +#if !defined(va_copy) && defined(__INTEL_COMPILER) +#define va_copy(dst, src) ((dst) = (src)) +#endif + +#if !defined(isfinite) && (SYS_OPENBSD || SYS_SunOS) +#define isfinite finite +#endif + +#ifdef _WIN32 +#ifndef strtok_r +#define strtok_r(str,delim,save) strtok(str,delim) +#endif + +#define utf8_to_utf16( utf8, utf16 )\ + MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, utf8, -1, utf16, sizeof(utf16)/sizeof(wchar_t) ) +FILE *x264_fopen( const char *filename, const char *mode ); +int x264_rename( const char *oldname, const char *newname ); +#define x264_struct_stat struct _stati64 +#define x264_fstat _fstati64 +int x264_stat( const char *path, x264_struct_stat *buf ); +#else +#define x264_fopen fopen +#define x264_rename rename +#define x264_struct_stat struct stat +#define x264_fstat fstat +#define x264_stat stat +#endif + +/* mdate: return the current date in microsecond */ +int64_t x264_mdate( void ); + +#if defined(_WIN32) && !HAVE_WINRT +int x264_vfprintf( FILE *stream, const char *format, va_list arg ); +int x264_is_pipe( const char *path ); +#else +#define x264_vfprintf vfprintf +#define x264_is_pipe(x) 0 +#endif + +#ifdef _MSC_VER +#define DECLARE_ALIGNED( var, n ) __declspec(align(n)) var +#else +#define DECLARE_ALIGNED( var, n ) var __attribute__((aligned(n))) +#endif + +#define ALIGNED_4( var ) DECLARE_ALIGNED( var, 4 ) +#define ALIGNED_8( var ) DECLARE_ALIGNED( var, 8 ) +#define ALIGNED_16( var ) DECLARE_ALIGNED( var, 16 ) + +// ARM compiliers don't reliably align stack variables +// - EABI requires only 8 byte stack alignment to be maintained +// - gcc can't align stack variables to more even if the stack were to be correctly aligned outside the function +// - armcc can't either, but is nice enough to actually tell you so +// - Apple gcc only maintains 4 byte alignment +// - llvm can align the stack, but only in svn and (unrelated) it exposes bugs in all released GNU binutils... + +#define ALIGNED_ARRAY_EMU( mask, type, name, sub1, ... )\ + uint8_t name##_u [sizeof(type sub1 __VA_ARGS__) + mask]; \ + type (*name) __VA_ARGS__ = (void*)((intptr_t)(name##_u+mask) & ~mask) + +#if ARCH_ARM && SYS_MACOSX +#define ALIGNED_ARRAY_8( ... ) EXPAND( ALIGNED_ARRAY_EMU( 7, __VA_ARGS__ ) ) +#else +#define ALIGNED_ARRAY_8( type, name, sub1, ... ) ALIGNED_8( type name sub1 __VA_ARGS__ ) +#endif + +#if ARCH_ARM +#define ALIGNED_ARRAY_16( ... ) EXPAND( ALIGNED_ARRAY_EMU( 15, __VA_ARGS__ ) ) +#else +#define ALIGNED_ARRAY_16( type, name, sub1, ... ) ALIGNED_16( type name sub1 __VA_ARGS__ ) +#endif + +#define EXPAND(x) x + +#if ARCH_X86 || ARCH_X86_64 +#define NATIVE_ALIGN 64 +#define ALIGNED_32( var ) DECLARE_ALIGNED( var, 32 ) +#define ALIGNED_64( var ) DECLARE_ALIGNED( var, 64 ) +#if STACK_ALIGNMENT >= 32 +#define ALIGNED_ARRAY_32( type, name, sub1, ... ) ALIGNED_32( type name sub1 __VA_ARGS__ ) +#else +#define ALIGNED_ARRAY_32( ... ) EXPAND( ALIGNED_ARRAY_EMU( 31, __VA_ARGS__ ) ) +#endif +#if STACK_ALIGNMENT >= 64 +#define ALIGNED_ARRAY_64( type, name, sub1, ... ) ALIGNED_64( type name sub1 __VA_ARGS__ ) +#else +#define ALIGNED_ARRAY_64( ... ) EXPAND( ALIGNED_ARRAY_EMU( 63, __VA_ARGS__ ) ) +#endif +#else +#define NATIVE_ALIGN 16 +#define ALIGNED_32 ALIGNED_16 +#define ALIGNED_64 ALIGNED_16 +#define ALIGNED_ARRAY_32 ALIGNED_ARRAY_16 +#define ALIGNED_ARRAY_64 ALIGNED_ARRAY_16 +#endif + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +#define UNUSED __attribute__((unused)) +#define ALWAYS_INLINE __attribute__((always_inline)) inline +#define NOINLINE __attribute__((noinline)) +#define MAY_ALIAS __attribute__((may_alias)) +#define x264_constant_p(x) __builtin_constant_p(x) +#define x264_nonconstant_p(x) (!__builtin_constant_p(x)) +#else +#ifdef _MSC_VER +#define ALWAYS_INLINE __forceinline +#define NOINLINE __declspec(noinline) +#else +#define ALWAYS_INLINE inline +#define NOINLINE +#endif +#define UNUSED +#define MAY_ALIAS +#define x264_constant_p(x) 0 +#define x264_nonconstant_p(x) 0 +#endif + +/* threads */ +#if HAVE_BEOSTHREAD +#include +#define x264_pthread_t thread_id +static inline int x264_pthread_create( x264_pthread_t *t, void *a, void *(*f)(void *), void *d ) +{ + *t = spawn_thread( f, "", 10, d ); + if( *t < B_NO_ERROR ) + return -1; + resume_thread( *t ); + return 0; +} +#define x264_pthread_join(t,s) { long tmp; \ + wait_for_thread(t,(s)?(long*)(s):&tmp); } + +#elif HAVE_POSIXTHREAD +#include +#define x264_pthread_t pthread_t +#define x264_pthread_create pthread_create +#define x264_pthread_join pthread_join +#define x264_pthread_mutex_t pthread_mutex_t +#define x264_pthread_mutex_init pthread_mutex_init +#define x264_pthread_mutex_destroy pthread_mutex_destroy +#define x264_pthread_mutex_lock pthread_mutex_lock +#define x264_pthread_mutex_unlock pthread_mutex_unlock +#define x264_pthread_cond_t pthread_cond_t +#define x264_pthread_cond_init pthread_cond_init +#define x264_pthread_cond_destroy pthread_cond_destroy +#define x264_pthread_cond_broadcast pthread_cond_broadcast +#define x264_pthread_cond_wait pthread_cond_wait +#define x264_pthread_attr_t pthread_attr_t +#define x264_pthread_attr_init pthread_attr_init +#define x264_pthread_attr_destroy pthread_attr_destroy +#define x264_pthread_num_processors_np pthread_num_processors_np +#define X264_PTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +#elif HAVE_WIN32THREAD +#include "win32thread.h" + +#else +#define x264_pthread_t int +#define x264_pthread_create(t,u,f,d) 0 +#define x264_pthread_join(t,s) +#endif //HAVE_*THREAD + +#if !HAVE_POSIXTHREAD && !HAVE_WIN32THREAD +#define x264_pthread_mutex_t int +#define x264_pthread_mutex_init(m,f) 0 +#define x264_pthread_mutex_destroy(m) +#define x264_pthread_mutex_lock(m) +#define x264_pthread_mutex_unlock(m) +#define x264_pthread_cond_t int +#define x264_pthread_cond_init(c,f) 0 +#define x264_pthread_cond_destroy(c) +#define x264_pthread_cond_broadcast(c) +#define x264_pthread_cond_wait(c,m) +#define x264_pthread_attr_t int +#define x264_pthread_attr_init(a) 0 +#define x264_pthread_attr_destroy(a) +#define X264_PTHREAD_MUTEX_INITIALIZER 0 +#endif + +#if HAVE_WIN32THREAD || PTW32_STATIC_LIB +int x264_threading_init( void ); +#else +#define x264_threading_init() 0 +#endif + +static ALWAYS_INLINE int x264_pthread_fetch_and_add( int *val, int add, x264_pthread_mutex_t *mutex ) +{ +#if HAVE_THREAD +#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 0) && (ARCH_X86 || ARCH_X86_64) + return __sync_fetch_and_add( val, add ); +#else + x264_pthread_mutex_lock( mutex ); + int res = *val; + *val += add; + x264_pthread_mutex_unlock( mutex ); + return res; +#endif +#else + int res = *val; + *val += add; + return res; +#endif +} + +#define WORD_SIZE sizeof(void*) + +#define asm __asm__ + +#if WORDS_BIGENDIAN +#define endian_fix(x) (x) +#define endian_fix64(x) (x) +#define endian_fix32(x) (x) +#define endian_fix16(x) (x) +#else +#if HAVE_X86_INLINE_ASM && HAVE_MMX +static ALWAYS_INLINE uint32_t endian_fix32( uint32_t x ) +{ + asm("bswap %0":"+r"(x)); + return x; +} +#elif defined(__GNUC__) && HAVE_ARMV6 +static ALWAYS_INLINE uint32_t endian_fix32( uint32_t x ) +{ + asm("rev %0, %0":"+r"(x)); + return x; +} +#else +static ALWAYS_INLINE uint32_t endian_fix32( uint32_t x ) +{ + return (x<<24) + ((x<<8)&0xff0000) + ((x>>8)&0xff00) + (x>>24); +} +#endif +#if HAVE_X86_INLINE_ASM && ARCH_X86_64 +static ALWAYS_INLINE uint64_t endian_fix64( uint64_t x ) +{ + asm("bswap %0":"+r"(x)); + return x; +} +#else +static ALWAYS_INLINE uint64_t endian_fix64( uint64_t x ) +{ + return endian_fix32(x>>32) + ((uint64_t)endian_fix32(x)<<32); +} +#endif +static ALWAYS_INLINE intptr_t endian_fix( intptr_t x ) +{ + return WORD_SIZE == 8 ? endian_fix64(x) : endian_fix32(x); +} +static ALWAYS_INLINE uint16_t endian_fix16( uint16_t x ) +{ + return (x<<8)|(x>>8); +} +#endif + +/* For values with 4 bits or less. */ +static int ALWAYS_INLINE x264_ctz_4bit( uint32_t x ) +{ + static uint8_t lut[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0}; + return lut[x]; +} + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 3) +#define x264_clz(x) __builtin_clz(x) +#define x264_ctz(x) __builtin_ctz(x) +#else +static int ALWAYS_INLINE x264_clz( uint32_t x ) +{ + static uint8_t lut[16] = {4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0}; + int y, z = (((x >> 16) - 1) >> 27) & 16; + x >>= z^16; + z += y = ((x - 0x100) >> 28) & 8; + x >>= y^8; + z += y = ((x - 0x10) >> 29) & 4; + x >>= y^4; + return z + lut[x]; +} + +static int ALWAYS_INLINE x264_ctz( uint32_t x ) +{ + static uint8_t lut[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0}; + int y, z = (((x & 0xffff) - 1) >> 27) & 16; + x >>= z; + z += y = (((x & 0xff) - 1) >> 28) & 8; + x >>= y; + z += y = (((x & 0xf) - 1) >> 29) & 4; + x >>= y; + return z + lut[x&0xf]; +} +#endif + +#if HAVE_X86_INLINE_ASM && HAVE_MMX +/* Don't use __builtin_prefetch; even as recent as 4.3.4, GCC seems incapable of + * using complex address modes properly unless we use inline asm. */ +static ALWAYS_INLINE void x264_prefetch( void *p ) +{ + asm volatile( "prefetcht0 %0"::"m"(*(uint8_t*)p) ); +} +/* We require that prefetch not fault on invalid reads, so we only enable it on + * known architectures. */ +#elif defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 1) &&\ + (ARCH_X86 || ARCH_X86_64 || ARCH_ARM || ARCH_PPC) +#define x264_prefetch(x) __builtin_prefetch(x) +#else +#define x264_prefetch(x) +#endif + +#if HAVE_POSIXTHREAD +#if SYS_WINDOWS +#define x264_lower_thread_priority(p)\ +{\ + x264_pthread_t handle = pthread_self();\ + struct sched_param sp;\ + int policy = SCHED_OTHER;\ + pthread_getschedparam( handle, &policy, &sp );\ + sp.sched_priority -= p;\ + pthread_setschedparam( handle, policy, &sp );\ +} +#elif SYS_HAIKU +#include +#define x264_lower_thread_priority(p)\ + { UNUSED status_t nice_ret = set_thread_priority( find_thread( NULL ), B_LOW_PRIORITY ); } +#else +#include +#define x264_lower_thread_priority(p) { UNUSED int nice_ret = nice(p); } +#endif /* SYS_WINDOWS */ +#elif HAVE_WIN32THREAD +#define x264_lower_thread_priority(p) SetThreadPriority( GetCurrentThread(), X264_MAX( -2, -p ) ) +#else +#define x264_lower_thread_priority(p) +#endif + +static inline int x264_is_regular_file( FILE *filehandle ) +{ + x264_struct_stat file_stat; + if( x264_fstat( fileno( filehandle ), &file_stat ) ) + return 1; + return S_ISREG( file_stat.st_mode ); +} + +static inline int x264_is_regular_file_path( const char *filename ) +{ + x264_struct_stat file_stat; + if( x264_stat( filename, &file_stat ) ) + return !x264_is_pipe( filename ); + return S_ISREG( file_stat.st_mode ); +} + +#endif /* X264_OSDEP_H */ diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/pixel.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/pixel.c new file mode 100644 index 00000000..d668491b --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/pixel.c @@ -0,0 +1,1522 @@ +/***************************************************************************** + * pixel.c: pixel metrics + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#if HAVE_MMX +# include "x86/pixel.h" +# include "x86/predict.h" +#endif +#if ARCH_PPC +# include "ppc/pixel.h" +#endif +#if ARCH_ARM +# include "arm/pixel.h" +# include "arm/predict.h" +#endif +#if ARCH_AARCH64 +# include "aarch64/pixel.h" +# include "aarch64/predict.h" +#endif +#if ARCH_MIPS +# include "mips/pixel.h" +#endif + + +/**************************************************************************** + * pixel_sad_WxH + ****************************************************************************/ +#define PIXEL_SAD_C( name, lx, ly ) \ +static int name( pixel *pix1, intptr_t i_stride_pix1, \ + pixel *pix2, intptr_t i_stride_pix2 ) \ +{ \ + int i_sum = 0; \ + for( int y = 0; y < ly; y++ ) \ + { \ + for( int x = 0; x < lx; x++ ) \ + { \ + i_sum += abs( pix1[x] - pix2[x] ); \ + } \ + pix1 += i_stride_pix1; \ + pix2 += i_stride_pix2; \ + } \ + return i_sum; \ +} + + +PIXEL_SAD_C( x264_pixel_sad_16x16, 16, 16 ) +PIXEL_SAD_C( x264_pixel_sad_16x8, 16, 8 ) +PIXEL_SAD_C( x264_pixel_sad_8x16, 8, 16 ) +PIXEL_SAD_C( x264_pixel_sad_8x8, 8, 8 ) +PIXEL_SAD_C( x264_pixel_sad_8x4, 8, 4 ) +PIXEL_SAD_C( x264_pixel_sad_4x16, 4, 16 ) +PIXEL_SAD_C( x264_pixel_sad_4x8, 4, 8 ) +PIXEL_SAD_C( x264_pixel_sad_4x4, 4, 4 ) + +/**************************************************************************** + * pixel_ssd_WxH + ****************************************************************************/ +#define PIXEL_SSD_C( name, lx, ly ) \ +static int name( pixel *pix1, intptr_t i_stride_pix1, \ + pixel *pix2, intptr_t i_stride_pix2 ) \ +{ \ + int i_sum = 0; \ + for( int y = 0; y < ly; y++ ) \ + { \ + for( int x = 0; x < lx; x++ ) \ + { \ + int d = pix1[x] - pix2[x]; \ + i_sum += d*d; \ + } \ + pix1 += i_stride_pix1; \ + pix2 += i_stride_pix2; \ + } \ + return i_sum; \ +} + +PIXEL_SSD_C( x264_pixel_ssd_16x16, 16, 16 ) +PIXEL_SSD_C( x264_pixel_ssd_16x8, 16, 8 ) +PIXEL_SSD_C( x264_pixel_ssd_8x16, 8, 16 ) +PIXEL_SSD_C( x264_pixel_ssd_8x8, 8, 8 ) +PIXEL_SSD_C( x264_pixel_ssd_8x4, 8, 4 ) +PIXEL_SSD_C( x264_pixel_ssd_4x16, 4, 16 ) +PIXEL_SSD_C( x264_pixel_ssd_4x8, 4, 8 ) +PIXEL_SSD_C( x264_pixel_ssd_4x4, 4, 4 ) + +uint64_t x264_pixel_ssd_wxh( x264_pixel_function_t *pf, pixel *pix1, intptr_t i_pix1, + pixel *pix2, intptr_t i_pix2, int i_width, int i_height ) +{ + uint64_t i_ssd = 0; + int y; + int align = !(((intptr_t)pix1 | (intptr_t)pix2 | i_pix1 | i_pix2) & 15); + +#define SSD(size) i_ssd += pf->ssd[size]( pix1 + y*i_pix1 + x, i_pix1, \ + pix2 + y*i_pix2 + x, i_pix2 ); + for( y = 0; y < i_height-15; y += 16 ) + { + int x = 0; + if( align ) + for( ; x < i_width-15; x += 16 ) + SSD(PIXEL_16x16); + for( ; x < i_width-7; x += 8 ) + SSD(PIXEL_8x16); + } + if( y < i_height-7 ) + for( int x = 0; x < i_width-7; x += 8 ) + SSD(PIXEL_8x8); +#undef SSD + +#define SSD1 { int d = pix1[y*i_pix1+x] - pix2[y*i_pix2+x]; i_ssd += d*d; } + if( i_width & 7 ) + { + for( y = 0; y < (i_height & ~7); y++ ) + for( int x = i_width & ~7; x < i_width; x++ ) + SSD1; + } + if( i_height & 7 ) + { + for( y = i_height & ~7; y < i_height; y++ ) + for( int x = 0; x < i_width; x++ ) + SSD1; + } +#undef SSD1 + + return i_ssd; +} + +static void pixel_ssd_nv12_core( pixel *pixuv1, intptr_t stride1, pixel *pixuv2, intptr_t stride2, + int width, int height, uint64_t *ssd_u, uint64_t *ssd_v ) +{ + *ssd_u = 0, *ssd_v = 0; + for( int y = 0; y < height; y++, pixuv1+=stride1, pixuv2+=stride2 ) + for( int x = 0; x < width; x++ ) + { + int du = pixuv1[2*x] - pixuv2[2*x]; + int dv = pixuv1[2*x+1] - pixuv2[2*x+1]; + *ssd_u += du*du; + *ssd_v += dv*dv; + } +} + +void x264_pixel_ssd_nv12( x264_pixel_function_t *pf, pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2, + int i_width, int i_height, uint64_t *ssd_u, uint64_t *ssd_v ) +{ + pf->ssd_nv12_core( pix1, i_pix1, pix2, i_pix2, i_width&~7, i_height, ssd_u, ssd_v ); + if( i_width&7 ) + { + uint64_t tmp[2]; + pixel_ssd_nv12_core( pix1+(i_width&~7), i_pix1, pix2+(i_width&~7), i_pix2, i_width&7, i_height, &tmp[0], &tmp[1] ); + *ssd_u += tmp[0]; + *ssd_v += tmp[1]; + } +} + +/**************************************************************************** + * pixel_var_wxh + ****************************************************************************/ +#define PIXEL_VAR_C( name, w, h ) \ +static uint64_t name( pixel *pix, intptr_t i_stride ) \ +{ \ + uint32_t sum = 0, sqr = 0; \ + for( int y = 0; y < h; y++ ) \ + { \ + for( int x = 0; x < w; x++ ) \ + { \ + sum += pix[x]; \ + sqr += pix[x] * pix[x]; \ + } \ + pix += i_stride; \ + } \ + return sum + ((uint64_t)sqr << 32); \ +} + +PIXEL_VAR_C( x264_pixel_var_16x16, 16, 16 ) +PIXEL_VAR_C( x264_pixel_var_8x16, 8, 16 ) +PIXEL_VAR_C( x264_pixel_var_8x8, 8, 8 ) + +/**************************************************************************** + * pixel_var2_wxh + ****************************************************************************/ +#define PIXEL_VAR2_C( name, h, shift ) \ +static int name( pixel *fenc, pixel *fdec, int ssd[2] ) \ +{ \ + int sum_u = 0, sum_v = 0, sqr_u = 0, sqr_v = 0; \ + for( int y = 0; y < h; y++ ) \ + { \ + for( int x = 0; x < 8; x++ ) \ + { \ + int diff_u = fenc[x] - fdec[x]; \ + int diff_v = fenc[x+FENC_STRIDE/2] - fdec[x+FDEC_STRIDE/2]; \ + sum_u += diff_u; \ + sum_v += diff_v; \ + sqr_u += diff_u * diff_u; \ + sqr_v += diff_v * diff_v; \ + } \ + fenc += FENC_STRIDE; \ + fdec += FDEC_STRIDE; \ + } \ + ssd[0] = sqr_u; \ + ssd[1] = sqr_v; \ + return sqr_u - ((int64_t)sum_u * sum_u >> shift) + \ + sqr_v - ((int64_t)sum_v * sum_v >> shift); \ +} + +PIXEL_VAR2_C( x264_pixel_var2_8x16, 16, 7 ) +PIXEL_VAR2_C( x264_pixel_var2_8x8, 8, 6 ) + +#if BIT_DEPTH > 8 + typedef uint32_t sum_t; + typedef uint64_t sum2_t; +#else + typedef uint16_t sum_t; + typedef uint32_t sum2_t; +#endif +#define BITS_PER_SUM (8 * sizeof(sum_t)) + +#define HADAMARD4(d0, d1, d2, d3, s0, s1, s2, s3) {\ + sum2_t t0 = s0 + s1;\ + sum2_t t1 = s0 - s1;\ + sum2_t t2 = s2 + s3;\ + sum2_t t3 = s2 - s3;\ + d0 = t0 + t2;\ + d2 = t0 - t2;\ + d1 = t1 + t3;\ + d3 = t1 - t3;\ +} + +// in: a pseudo-simd number of the form x+(y<<16) +// return: abs(x)+(abs(y)<<16) +static ALWAYS_INLINE sum2_t abs2( sum2_t a ) +{ + sum2_t s = ((a>>(BITS_PER_SUM-1))&(((sum2_t)1<>BITS_PER_SUM); + } + return sum >> 1; +} + +static NOINLINE int x264_pixel_satd_8x4( pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2 ) +{ + sum2_t tmp[4][4]; + sum2_t a0, a1, a2, a3; + sum2_t sum = 0; + for( int i = 0; i < 4; i++, pix1 += i_pix1, pix2 += i_pix2 ) + { + a0 = (pix1[0] - pix2[0]) + ((sum2_t)(pix1[4] - pix2[4]) << BITS_PER_SUM); + a1 = (pix1[1] - pix2[1]) + ((sum2_t)(pix1[5] - pix2[5]) << BITS_PER_SUM); + a2 = (pix1[2] - pix2[2]) + ((sum2_t)(pix1[6] - pix2[6]) << BITS_PER_SUM); + a3 = (pix1[3] - pix2[3]) + ((sum2_t)(pix1[7] - pix2[7]) << BITS_PER_SUM); + HADAMARD4( tmp[i][0], tmp[i][1], tmp[i][2], tmp[i][3], a0,a1,a2,a3 ); + } + for( int i = 0; i < 4; i++ ) + { + HADAMARD4( a0, a1, a2, a3, tmp[0][i], tmp[1][i], tmp[2][i], tmp[3][i] ); + sum += abs2(a0) + abs2(a1) + abs2(a2) + abs2(a3); + } + return (((sum_t)sum) + (sum>>BITS_PER_SUM)) >> 1; +} + +#define PIXEL_SATD_C( w, h, sub )\ +static int x264_pixel_satd_##w##x##h( pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2 )\ +{\ + int sum = sub( pix1, i_pix1, pix2, i_pix2 )\ + + sub( pix1+4*i_pix1, i_pix1, pix2+4*i_pix2, i_pix2 );\ + if( w==16 )\ + sum+= sub( pix1+8, i_pix1, pix2+8, i_pix2 )\ + + sub( pix1+8+4*i_pix1, i_pix1, pix2+8+4*i_pix2, i_pix2 );\ + if( h==16 )\ + sum+= sub( pix1+8*i_pix1, i_pix1, pix2+8*i_pix2, i_pix2 )\ + + sub( pix1+12*i_pix1, i_pix1, pix2+12*i_pix2, i_pix2 );\ + if( w==16 && h==16 )\ + sum+= sub( pix1+8+8*i_pix1, i_pix1, pix2+8+8*i_pix2, i_pix2 )\ + + sub( pix1+8+12*i_pix1, i_pix1, pix2+8+12*i_pix2, i_pix2 );\ + return sum;\ +} +PIXEL_SATD_C( 16, 16, x264_pixel_satd_8x4 ) +PIXEL_SATD_C( 16, 8, x264_pixel_satd_8x4 ) +PIXEL_SATD_C( 8, 16, x264_pixel_satd_8x4 ) +PIXEL_SATD_C( 8, 8, x264_pixel_satd_8x4 ) +PIXEL_SATD_C( 4, 16, x264_pixel_satd_4x4 ) +PIXEL_SATD_C( 4, 8, x264_pixel_satd_4x4 ) + +static NOINLINE int sa8d_8x8( pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2 ) +{ + sum2_t tmp[8][4]; + sum2_t a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3; + sum2_t sum = 0; + for( int i = 0; i < 8; i++, pix1 += i_pix1, pix2 += i_pix2 ) + { + a0 = pix1[0] - pix2[0]; + a1 = pix1[1] - pix2[1]; + b0 = (a0+a1) + ((a0-a1)<>BITS_PER_SUM); + } + return sum; +} + +static int x264_pixel_sa8d_8x8( pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2 ) +{ + int sum = sa8d_8x8( pix1, i_pix1, pix2, i_pix2 ); + return (sum+2)>>2; +} + +static int x264_pixel_sa8d_16x16( pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2 ) +{ + int sum = sa8d_8x8( pix1, i_pix1, pix2, i_pix2 ) + + sa8d_8x8( pix1+8, i_pix1, pix2+8, i_pix2 ) + + sa8d_8x8( pix1+8*i_pix1, i_pix1, pix2+8*i_pix2, i_pix2 ) + + sa8d_8x8( pix1+8+8*i_pix1, i_pix1, pix2+8+8*i_pix2, i_pix2 ); + return (sum+2)>>2; +} + +static NOINLINE uint64_t pixel_hadamard_ac( pixel *pix, intptr_t stride ) +{ + sum2_t tmp[32]; + sum2_t a0, a1, a2, a3, dc; + sum2_t sum4 = 0, sum8 = 0; + for( int i = 0; i < 8; i++, pix+=stride ) + { + sum2_t *t = tmp + (i&3) + (i&4)*4; + a0 = (pix[0]+pix[1]) + ((sum2_t)(pix[0]-pix[1])<>BITS_PER_SUM) - dc; + sum8 = (sum_t)sum8 + (sum8>>BITS_PER_SUM) - dc; + return ((uint64_t)sum8<<32) + sum4; +} + +#define HADAMARD_AC(w,h) \ +static uint64_t x264_pixel_hadamard_ac_##w##x##h( pixel *pix, intptr_t stride )\ +{\ + uint64_t sum = pixel_hadamard_ac( pix, stride );\ + if( w==16 )\ + sum += pixel_hadamard_ac( pix+8, stride );\ + if( h==16 )\ + sum += pixel_hadamard_ac( pix+8*stride, stride );\ + if( w==16 && h==16 )\ + sum += pixel_hadamard_ac( pix+8*stride+8, stride );\ + return ((sum>>34)<<32) + ((uint32_t)sum>>1);\ +} +HADAMARD_AC( 16, 16 ) +HADAMARD_AC( 16, 8 ) +HADAMARD_AC( 8, 16 ) +HADAMARD_AC( 8, 8 ) + + +/**************************************************************************** + * pixel_sad_x4 + ****************************************************************************/ +#define SAD_X( size ) \ +static void x264_pixel_sad_x3_##size( pixel *fenc, pixel *pix0, pixel *pix1, pixel *pix2,\ + intptr_t i_stride, int scores[3] )\ +{\ + scores[0] = x264_pixel_sad_##size( fenc, FENC_STRIDE, pix0, i_stride );\ + scores[1] = x264_pixel_sad_##size( fenc, FENC_STRIDE, pix1, i_stride );\ + scores[2] = x264_pixel_sad_##size( fenc, FENC_STRIDE, pix2, i_stride );\ +}\ +static void x264_pixel_sad_x4_##size( pixel *fenc, pixel *pix0, pixel *pix1,pixel *pix2, pixel *pix3,\ + intptr_t i_stride, int scores[4] )\ +{\ + scores[0] = x264_pixel_sad_##size( fenc, FENC_STRIDE, pix0, i_stride );\ + scores[1] = x264_pixel_sad_##size( fenc, FENC_STRIDE, pix1, i_stride );\ + scores[2] = x264_pixel_sad_##size( fenc, FENC_STRIDE, pix2, i_stride );\ + scores[3] = x264_pixel_sad_##size( fenc, FENC_STRIDE, pix3, i_stride );\ +} + +SAD_X( 16x16 ) +SAD_X( 16x8 ) +SAD_X( 8x16 ) +SAD_X( 8x8 ) +SAD_X( 8x4 ) +SAD_X( 4x8 ) +SAD_X( 4x4 ) + +/**************************************************************************** + * pixel_satd_x4 + * no faster than single satd, but needed for satd to be a drop-in replacement for sad + ****************************************************************************/ + +#define SATD_X( size, cpu ) \ +static void x264_pixel_satd_x3_##size##cpu( pixel *fenc, pixel *pix0, pixel *pix1, pixel *pix2,\ + intptr_t i_stride, int scores[3] )\ +{\ + scores[0] = x264_pixel_satd_##size##cpu( fenc, FENC_STRIDE, pix0, i_stride );\ + scores[1] = x264_pixel_satd_##size##cpu( fenc, FENC_STRIDE, pix1, i_stride );\ + scores[2] = x264_pixel_satd_##size##cpu( fenc, FENC_STRIDE, pix2, i_stride );\ +}\ +static void x264_pixel_satd_x4_##size##cpu( pixel *fenc, pixel *pix0, pixel *pix1, pixel *pix2, pixel *pix3,\ + intptr_t i_stride, int scores[4] )\ +{\ + scores[0] = x264_pixel_satd_##size##cpu( fenc, FENC_STRIDE, pix0, i_stride );\ + scores[1] = x264_pixel_satd_##size##cpu( fenc, FENC_STRIDE, pix1, i_stride );\ + scores[2] = x264_pixel_satd_##size##cpu( fenc, FENC_STRIDE, pix2, i_stride );\ + scores[3] = x264_pixel_satd_##size##cpu( fenc, FENC_STRIDE, pix3, i_stride );\ +} +#define SATD_X_DECL6( cpu )\ +SATD_X( 16x16, cpu )\ +SATD_X( 16x8, cpu )\ +SATD_X( 8x16, cpu )\ +SATD_X( 8x8, cpu )\ +SATD_X( 8x4, cpu )\ +SATD_X( 4x8, cpu ) +#define SATD_X_DECL7( cpu )\ +SATD_X_DECL6( cpu )\ +SATD_X( 4x4, cpu ) + +SATD_X_DECL7() +#if HAVE_MMX +SATD_X_DECL7( _mmx2 ) +#if !HIGH_BIT_DEPTH +SATD_X_DECL6( _sse2 ) +SATD_X_DECL7( _ssse3 ) +SATD_X_DECL6( _ssse3_atom ) +SATD_X_DECL7( _sse4 ) +SATD_X_DECL7( _avx ) +SATD_X_DECL7( _xop ) +#endif // !HIGH_BIT_DEPTH +#endif + +#if !HIGH_BIT_DEPTH +#if HAVE_ARMV6 || ARCH_AARCH64 +SATD_X_DECL7( _neon ) +#endif +#endif // !HIGH_BIT_DEPTH + +#define INTRA_MBCMP_8x8( mbcmp, cpu, cpu2 )\ +void x264_intra_##mbcmp##_x3_8x8##cpu( pixel *fenc, pixel edge[36], int res[3] )\ +{\ + ALIGNED_ARRAY_16( pixel, pix, [8*FDEC_STRIDE] );\ + x264_predict_8x8_v##cpu2( pix, edge );\ + res[0] = x264_pixel_##mbcmp##_8x8##cpu( pix, FDEC_STRIDE, fenc, FENC_STRIDE );\ + x264_predict_8x8_h##cpu2( pix, edge );\ + res[1] = x264_pixel_##mbcmp##_8x8##cpu( pix, FDEC_STRIDE, fenc, FENC_STRIDE );\ + x264_predict_8x8_dc##cpu2( pix, edge );\ + res[2] = x264_pixel_##mbcmp##_8x8##cpu( pix, FDEC_STRIDE, fenc, FENC_STRIDE );\ +} + +INTRA_MBCMP_8x8( sad,, _c ) +INTRA_MBCMP_8x8(sa8d,, _c ) +#if HIGH_BIT_DEPTH && HAVE_MMX +#define x264_predict_8x8_v_sse2 x264_predict_8x8_v_sse +INTRA_MBCMP_8x8( sad, _mmx2, _c ) +INTRA_MBCMP_8x8(sa8d, _sse2, _sse2 ) +#endif +#if !HIGH_BIT_DEPTH && (HAVE_ARMV6 || ARCH_AARCH64) +INTRA_MBCMP_8x8( sad, _neon, _neon ) +INTRA_MBCMP_8x8(sa8d, _neon, _neon ) +#endif + +#define INTRA_MBCMP( mbcmp, size, pred1, pred2, pred3, chroma, cpu, cpu2 )\ +void x264_intra_##mbcmp##_x3_##size##chroma##cpu( pixel *fenc, pixel *fdec, int res[3] )\ +{\ + x264_predict_##size##chroma##_##pred1##cpu2( fdec );\ + res[0] = x264_pixel_##mbcmp##_##size##cpu( fdec, FDEC_STRIDE, fenc, FENC_STRIDE );\ + x264_predict_##size##chroma##_##pred2##cpu2( fdec );\ + res[1] = x264_pixel_##mbcmp##_##size##cpu( fdec, FDEC_STRIDE, fenc, FENC_STRIDE );\ + x264_predict_##size##chroma##_##pred3##cpu2( fdec );\ + res[2] = x264_pixel_##mbcmp##_##size##cpu( fdec, FDEC_STRIDE, fenc, FENC_STRIDE );\ +} + +INTRA_MBCMP( sad, 4x4, v, h, dc, ,, _c ) +INTRA_MBCMP(satd, 4x4, v, h, dc, ,, _c ) +INTRA_MBCMP( sad, 8x8, dc, h, v, c,, _c ) +INTRA_MBCMP(satd, 8x8, dc, h, v, c,, _c ) +INTRA_MBCMP( sad, 8x16, dc, h, v, c,, _c ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c,, _c ) +INTRA_MBCMP( sad, 16x16, v, h, dc, ,, _c ) +INTRA_MBCMP(satd, 16x16, v, h, dc, ,, _c ) + +#if HAVE_MMX +#if HIGH_BIT_DEPTH +#define x264_predict_8x8c_v_mmx2 x264_predict_8x8c_v_mmx +#define x264_predict_8x16c_v_mmx2 x264_predict_8x16c_v_c +#define x264_predict_16x16_dc_mmx2 x264_predict_16x16_dc_c +#define x264_predict_8x8c_v_sse2 x264_predict_8x8c_v_sse +#define x264_predict_8x16c_v_sse2 x264_predict_8x16c_v_sse +#define x264_predict_16x16_v_sse2 x264_predict_16x16_v_sse +INTRA_MBCMP( sad, 4x4, v, h, dc, , _mmx2, _c ) +INTRA_MBCMP( sad, 8x8, dc, h, v, c, _mmx2, _mmx2 ) +INTRA_MBCMP( sad, 8x16, dc, h, v, c, _mmx2, _mmx2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _mmx2, _mmx2 ) +INTRA_MBCMP( sad, 16x16, v, h, dc, , _mmx2, _mmx2 ) +INTRA_MBCMP( sad, 8x8, dc, h, v, c, _sse2, _sse2 ) +INTRA_MBCMP( sad, 8x16, dc, h, v, c, _sse2, _sse2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _sse2, _sse2 ) +INTRA_MBCMP( sad, 16x16, v, h, dc, , _sse2, _sse2 ) +INTRA_MBCMP( sad, 8x8, dc, h, v, c, _ssse3, _sse2 ) +INTRA_MBCMP( sad, 8x16, dc, h, v, c, _ssse3, _sse2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _ssse3, _sse2 ) +INTRA_MBCMP( sad, 16x16, v, h, dc, , _ssse3, _sse2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _sse4, _sse2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _avx, _sse2 ) +#else +#define x264_predict_8x16c_v_mmx2 x264_predict_8x16c_v_mmx +INTRA_MBCMP( sad, 8x16, dc, h, v, c, _mmx2, _mmx2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _mmx2, _mmx2 ) +INTRA_MBCMP( sad, 8x16, dc, h, v, c, _sse2, _mmx2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _sse2, _mmx2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _ssse3, _mmx2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _sse4, _mmx2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _avx, _mmx2 ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _xop, _mmx2 ) +#endif +#endif +#if !HIGH_BIT_DEPTH && HAVE_ARMV6 +INTRA_MBCMP( sad, 4x4, v, h, dc, , _neon, _armv6 ) +INTRA_MBCMP(satd, 4x4, v, h, dc, , _neon, _armv6 ) +INTRA_MBCMP( sad, 8x8, dc, h, v, c, _neon, _neon ) +INTRA_MBCMP(satd, 8x8, dc, h, v, c, _neon, _neon ) +INTRA_MBCMP( sad, 8x16, dc, h, v, c, _neon, _c ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _neon, _c ) +INTRA_MBCMP( sad, 16x16, v, h, dc, , _neon, _neon ) +INTRA_MBCMP(satd, 16x16, v, h, dc, , _neon, _neon ) +#endif +#if !HIGH_BIT_DEPTH && ARCH_AARCH64 +INTRA_MBCMP( sad, 4x4, v, h, dc, , _neon, _neon ) +INTRA_MBCMP(satd, 4x4, v, h, dc, , _neon, _neon ) +INTRA_MBCMP( sad, 8x8, dc, h, v, c, _neon, _neon ) +INTRA_MBCMP(satd, 8x8, dc, h, v, c, _neon, _neon ) +INTRA_MBCMP( sad, 8x16, dc, h, v, c, _neon, _neon ) +INTRA_MBCMP(satd, 8x16, dc, h, v, c, _neon, _neon ) +INTRA_MBCMP( sad, 16x16, v, h, dc, , _neon, _neon ) +INTRA_MBCMP(satd, 16x16, v, h, dc, , _neon, _neon ) +#endif + +// No C implementation of intra_satd_x9. See checkasm for its behavior, +// or see x264_mb_analyse_intra for the entirely different algorithm we +// use when lacking an asm implementation of it. + + + +/**************************************************************************** + * structural similarity metric + ****************************************************************************/ +static void ssim_4x4x2_core( const pixel *pix1, intptr_t stride1, + const pixel *pix2, intptr_t stride2, + int sums[2][4] ) +{ + for( int z = 0; z < 2; z++ ) + { + uint32_t s1 = 0, s2 = 0, ss = 0, s12 = 0; + for( int y = 0; y < 4; y++ ) + for( int x = 0; x < 4; x++ ) + { + int a = pix1[x+y*stride1]; + int b = pix2[x+y*stride2]; + s1 += a; + s2 += b; + ss += a*a; + ss += b*b; + s12 += a*b; + } + sums[z][0] = s1; + sums[z][1] = s2; + sums[z][2] = ss; + sums[z][3] = s12; + pix1 += 4; + pix2 += 4; + } +} + +static float ssim_end1( int s1, int s2, int ss, int s12 ) +{ +/* Maximum value for 10-bit is: ss*64 = (2^10-1)^2*16*4*64 = 4286582784, which will overflow in some cases. + * s1*s1, s2*s2, and s1*s2 also obtain this value for edge cases: ((2^10-1)*16*4)^2 = 4286582784. + * Maximum value for 9-bit is: ss*64 = (2^9-1)^2*16*4*64 = 1069551616, which will not overflow. */ +#if BIT_DEPTH > 9 +#define type float + static const float ssim_c1 = .01*.01*PIXEL_MAX*PIXEL_MAX*64; + static const float ssim_c2 = .03*.03*PIXEL_MAX*PIXEL_MAX*64*63; +#else +#define type int + static const int ssim_c1 = (int)(.01*.01*PIXEL_MAX*PIXEL_MAX*64 + .5); + static const int ssim_c2 = (int)(.03*.03*PIXEL_MAX*PIXEL_MAX*64*63 + .5); +#endif + type fs1 = s1; + type fs2 = s2; + type fss = ss; + type fs12 = s12; + type vars = fss*64 - fs1*fs1 - fs2*fs2; + type covar = fs12*64 - fs1*fs2; + return (float)(2*fs1*fs2 + ssim_c1) * (float)(2*covar + ssim_c2) + / ((float)(fs1*fs1 + fs2*fs2 + ssim_c1) * (float)(vars + ssim_c2)); +#undef type +} + +static float ssim_end4( int sum0[5][4], int sum1[5][4], int width ) +{ + float ssim = 0.0; + for( int i = 0; i < width; i++ ) + ssim += ssim_end1( sum0[i][0] + sum0[i+1][0] + sum1[i][0] + sum1[i+1][0], + sum0[i][1] + sum0[i+1][1] + sum1[i][1] + sum1[i+1][1], + sum0[i][2] + sum0[i+1][2] + sum1[i][2] + sum1[i+1][2], + sum0[i][3] + sum0[i+1][3] + sum1[i][3] + sum1[i+1][3] ); + return ssim; +} + +float x264_pixel_ssim_wxh( x264_pixel_function_t *pf, + pixel *pix1, intptr_t stride1, + pixel *pix2, intptr_t stride2, + int width, int height, void *buf, int *cnt ) +{ + int z = 0; + float ssim = 0.0; + int (*sum0)[4] = buf; + int (*sum1)[4] = sum0 + (width >> 2) + 3; + width >>= 2; + height >>= 2; + for( int y = 1; y < height; y++ ) + { + for( ; z <= y; z++ ) + { + XCHG( void*, sum0, sum1 ); + for( int x = 0; x < width; x+=2 ) + pf->ssim_4x4x2_core( &pix1[4*(x+z*stride1)], stride1, &pix2[4*(x+z*stride2)], stride2, &sum0[x] ); + } + for( int x = 0; x < width-1; x += 4 ) + ssim += pf->ssim_end4( sum0+x, sum1+x, X264_MIN(4,width-x-1) ); + } + *cnt = (height-1) * (width-1); + return ssim; +} + +static int pixel_vsad( pixel *src, intptr_t stride, int height ) +{ + int score = 0; + for( int i = 1; i < height; i++, src += stride ) + for( int j = 0; j < 16; j++ ) + score += abs(src[j] - src[j+stride]); + return score; +} + +int x264_field_vsad( x264_t *h, int mb_x, int mb_y ) +{ + int score_field, score_frame; + int stride = h->fenc->i_stride[0]; + int mb_stride = h->mb.i_mb_stride; + pixel *fenc = h->fenc->plane[0] + 16 * (mb_x + mb_y * stride); + int mb_xy = mb_x + mb_y*mb_stride; + + /* We don't want to analyze pixels outside the frame, as it gives inaccurate results. */ + int mbpair_height = X264_MIN( h->param.i_height - mb_y * 16, 32 ); + score_frame = h->pixf.vsad( fenc, stride, mbpair_height ); + score_field = h->pixf.vsad( fenc, stride*2, mbpair_height >> 1 ); + score_field += h->pixf.vsad( fenc+stride, stride*2, mbpair_height >> 1 ); + + if( mb_x > 0 ) + score_field += 512 - h->mb.field[mb_xy -1]*1024; + if( mb_y > 0 ) + score_field += 512 - h->mb.field[mb_xy-mb_stride]*1024; + + return (score_field < score_frame); +} + +static int pixel_asd8( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ) +{ + int sum = 0; + for( int y = 0; y < height; y++, pix1 += stride1, pix2 += stride2 ) + for( int x = 0; x < 8; x++ ) + sum += pix1[x] - pix2[x]; + return abs( sum ); +} + +/**************************************************************************** + * successive elimination + ****************************************************************************/ +static int x264_pixel_ads4( int enc_dc[4], uint16_t *sums, int delta, + uint16_t *cost_mvx, int16_t *mvs, int width, int thresh ) +{ + int nmv = 0; + for( int i = 0; i < width; i++, sums++ ) + { + int ads = abs( enc_dc[0] - sums[0] ) + + abs( enc_dc[1] - sums[8] ) + + abs( enc_dc[2] - sums[delta] ) + + abs( enc_dc[3] - sums[delta+8] ) + + cost_mvx[i]; + if( ads < thresh ) + mvs[nmv++] = i; + } + return nmv; +} + +static int x264_pixel_ads2( int enc_dc[2], uint16_t *sums, int delta, + uint16_t *cost_mvx, int16_t *mvs, int width, int thresh ) +{ + int nmv = 0; + for( int i = 0; i < width; i++, sums++ ) + { + int ads = abs( enc_dc[0] - sums[0] ) + + abs( enc_dc[1] - sums[delta] ) + + cost_mvx[i]; + if( ads < thresh ) + mvs[nmv++] = i; + } + return nmv; +} + +static int x264_pixel_ads1( int enc_dc[1], uint16_t *sums, int delta, + uint16_t *cost_mvx, int16_t *mvs, int width, int thresh ) +{ + int nmv = 0; + for( int i = 0; iname1[PIXEL_16x16] = x264_pixel_##name2##_16x16##cpu;\ + pixf->name1[PIXEL_16x8] = x264_pixel_##name2##_16x8##cpu; +#define INIT4_NAME( name1, name2, cpu ) \ + INIT2_NAME( name1, name2, cpu ) \ + pixf->name1[PIXEL_8x16] = x264_pixel_##name2##_8x16##cpu;\ + pixf->name1[PIXEL_8x8] = x264_pixel_##name2##_8x8##cpu; +#define INIT5_NAME( name1, name2, cpu ) \ + INIT4_NAME( name1, name2, cpu ) \ + pixf->name1[PIXEL_8x4] = x264_pixel_##name2##_8x4##cpu; +#define INIT6_NAME( name1, name2, cpu ) \ + INIT5_NAME( name1, name2, cpu ) \ + pixf->name1[PIXEL_4x8] = x264_pixel_##name2##_4x8##cpu; +#define INIT7_NAME( name1, name2, cpu ) \ + INIT6_NAME( name1, name2, cpu ) \ + pixf->name1[PIXEL_4x4] = x264_pixel_##name2##_4x4##cpu; +#define INIT8_NAME( name1, name2, cpu ) \ + INIT7_NAME( name1, name2, cpu ) \ + pixf->name1[PIXEL_4x16] = x264_pixel_##name2##_4x16##cpu; +#define INIT2( name, cpu ) INIT2_NAME( name, name, cpu ) +#define INIT4( name, cpu ) INIT4_NAME( name, name, cpu ) +#define INIT5( name, cpu ) INIT5_NAME( name, name, cpu ) +#define INIT6( name, cpu ) INIT6_NAME( name, name, cpu ) +#define INIT7( name, cpu ) INIT7_NAME( name, name, cpu ) +#define INIT8( name, cpu ) INIT8_NAME( name, name, cpu ) + +#define INIT_ADS( cpu ) \ + pixf->ads[PIXEL_16x16] = x264_pixel_ads4##cpu;\ + pixf->ads[PIXEL_16x8] = x264_pixel_ads2##cpu;\ + pixf->ads[PIXEL_8x8] = x264_pixel_ads1##cpu; + + INIT8( sad, ); + INIT8_NAME( sad_aligned, sad, ); + INIT7( sad_x3, ); + INIT7( sad_x4, ); + INIT8( ssd, ); + INIT8( satd, ); + INIT7( satd_x3, ); + INIT7( satd_x4, ); + INIT4( hadamard_ac, ); + INIT_ADS( ); + + pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16; + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16; + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8; + + pixf->ssd_nv12_core = pixel_ssd_nv12_core; + pixf->ssim_4x4x2_core = ssim_4x4x2_core; + pixf->ssim_end4 = ssim_end4; + pixf->vsad = pixel_vsad; + pixf->asd8 = pixel_asd8; + + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4; + pixf->intra_satd_x3_4x4 = x264_intra_satd_x3_4x4; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8; + pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c; + pixf->intra_satd_x3_8x8c = x264_intra_satd_x3_8x8c; + pixf->intra_sad_x3_8x16c = x264_intra_sad_x3_8x16c; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16; + pixf->intra_satd_x3_16x16 = x264_intra_satd_x3_16x16; + +#if HIGH_BIT_DEPTH +#if HAVE_MMX + if( cpu&X264_CPU_MMX2 ) + { + INIT7( sad, _mmx2 ); + INIT7_NAME( sad_aligned, sad, _mmx2 ); + INIT7( sad_x3, _mmx2 ); + INIT7( sad_x4, _mmx2 ); + INIT8( satd, _mmx2 ); + INIT7( satd_x3, _mmx2 ); + INIT7( satd_x4, _mmx2 ); + INIT4( hadamard_ac, _mmx2 ); + INIT8( ssd, _mmx2 ); + INIT_ADS( _mmx2 ); + + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_mmx2; + pixf->intra_satd_x3_4x4 = x264_intra_satd_x3_4x4_mmx2; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_mmx2; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_mmx2; + pixf->intra_satd_x3_8x8c = x264_intra_satd_x3_8x8c_mmx2; + pixf->intra_sad_x3_8x16c = x264_intra_sad_x3_8x16c_mmx2; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_mmx2; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_mmx2; + pixf->intra_satd_x3_16x16 = x264_intra_satd_x3_16x16_mmx2; + } + if( cpu&X264_CPU_SSE2 ) + { + INIT4_NAME( sad_aligned, sad, _sse2_aligned ); + INIT5( ssd, _sse2 ); + INIT6( satd, _sse2 ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_sse2; + + pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16_sse2; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_sse2; +#if ARCH_X86_64 + pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_sse2; + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_sse2; +#endif + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_sse2; + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_sse2; + pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_sse2; + pixf->ssim_end4 = x264_pixel_ssim_end4_sse2; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_sse2; + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_sse2; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_sse2; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_sse2; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_sse2; + } + if( (cpu&X264_CPU_SSE2) && !(cpu&X264_CPU_SSE2_IS_SLOW) ) + { + INIT5( sad, _sse2 ); + INIT2( sad_x3, _sse2 ); + INIT2( sad_x4, _sse2 ); + INIT_ADS( _sse2 ); + + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + INIT4( hadamard_ac, _sse2 ); + } + pixf->vsad = x264_pixel_vsad_sse2; + pixf->asd8 = x264_pixel_asd8_sse2; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_sse2; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_sse2; + pixf->intra_sad_x3_8x16c = x264_intra_sad_x3_8x16c_sse2; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_sse2; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_sse2; + } + if( cpu&X264_CPU_SSE2_IS_FAST ) + { + pixf->sad[PIXEL_8x16] = x264_pixel_sad_8x16_sse2; + pixf->sad_x3[PIXEL_8x16] = x264_pixel_sad_x3_8x16_sse2; + pixf->sad_x3[PIXEL_8x8] = x264_pixel_sad_x3_8x8_sse2; + pixf->sad_x3[PIXEL_8x4] = x264_pixel_sad_x3_8x4_sse2; + pixf->sad_x4[PIXEL_8x16] = x264_pixel_sad_x4_8x16_sse2; + pixf->sad_x4[PIXEL_8x8] = x264_pixel_sad_x4_8x8_sse2; + pixf->sad_x4[PIXEL_8x4] = x264_pixel_sad_x4_8x4_sse2; + } + if( cpu&X264_CPU_SSSE3 ) + { + INIT4_NAME( sad_aligned, sad, _ssse3_aligned ); + pixf->sad_aligned[PIXEL_4x4] = x264_pixel_sad_4x4_ssse3; + pixf->sad_aligned[PIXEL_4x8] = x264_pixel_sad_4x8_ssse3; + INIT7( sad, _ssse3 ); + INIT7( sad_x3, _ssse3 ); + INIT7( sad_x4, _ssse3 ); +#if ARCH_X86 || !defined( __MACH__ ) + INIT_ADS( _ssse3 ); +#endif + INIT6( satd, _ssse3 ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_ssse3; + + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + INIT4( hadamard_ac, _ssse3 ); + } + pixf->vsad = x264_pixel_vsad_ssse3; + pixf->asd8 = x264_pixel_asd8_ssse3; + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_ssse3; + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_ssse3; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_ssse3; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_ssse3; +#endif + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_ssse3; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_ssse3; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_ssse3; + pixf->intra_sad_x3_8x16c = x264_intra_sad_x3_8x16c_ssse3; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_ssse3; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_ssse3; + } + if( cpu&X264_CPU_SSE4 ) + { + INIT6( satd, _sse4 ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_sse4; + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + INIT4( hadamard_ac, _sse4 ); + } + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_sse4; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_sse4; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_sse4; +#endif + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_sse4; + } + if( cpu&X264_CPU_AVX ) + { + INIT5_NAME( sad_aligned, sad, _ssse3 ); /* AVX-capable CPUs doesn't benefit from an aligned version */ +#if ARCH_X86 || !defined( __MACH__ ) + INIT_ADS( _avx ); +#endif + INIT6( satd, _avx ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_avx; + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + INIT4( hadamard_ac, _avx ); + } + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_avx; + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_avx; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_avx; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx; + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_avx; + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_avx; + pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_avx; + pixf->ssim_end4 = x264_pixel_ssim_end4_avx; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_avx; +#endif + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_avx; + } + if( cpu&X264_CPU_XOP ) + { + INIT5( sad_x3, _xop ); + INIT5( sad_x4, _xop ); + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_xop; + pixf->vsad = x264_pixel_vsad_xop; + pixf->asd8 = x264_pixel_asd8_xop; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_xop; +#endif + } + if( cpu&X264_CPU_AVX2 ) + { + INIT2( ssd, _avx2 ); + INIT2( sad, _avx2 ); + INIT2_NAME( sad_aligned, sad, _avx2 ); + INIT2( sad_x3, _avx2 ); + INIT2( sad_x4, _avx2 ); + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx2; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_avx2; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_avx2; + pixf->vsad = x264_pixel_vsad_avx2; + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_avx2; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_avx2; + } + if( cpu&X264_CPU_AVX512 ) + { + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_avx512; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx512; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_avx512; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_avx512; + } +#endif // HAVE_MMX +#else // !HIGH_BIT_DEPTH +#if HAVE_MMX + if( cpu&X264_CPU_MMX ) + { + INIT8( ssd, _mmx ); + } + + if( cpu&X264_CPU_MMX2 ) + { + INIT8( sad, _mmx2 ); + INIT8_NAME( sad_aligned, sad, _mmx2 ); + INIT7( sad_x3, _mmx2 ); + INIT7( sad_x4, _mmx2 ); + INIT8( satd, _mmx2 ); + INIT7( satd_x3, _mmx2 ); + INIT7( satd_x4, _mmx2 ); + INIT4( hadamard_ac, _mmx2 ); + INIT_ADS( _mmx2 ); +#if ARCH_X86 + pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16_mmx2; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_mmx2; + pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_mmx2; + pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_mmx2; + pixf->vsad = x264_pixel_vsad_mmx2; + + if( cpu&X264_CPU_CACHELINE_32 ) + { + INIT5( sad, _cache32_mmx2 ); + INIT4( sad_x3, _cache32_mmx2 ); + INIT4( sad_x4, _cache32_mmx2 ); + } + else if( cpu&X264_CPU_CACHELINE_64 && !(cpu&X264_CPU_SLOW_ATOM) ) + { + INIT5( sad, _cache64_mmx2 ); + INIT4( sad_x3, _cache64_mmx2 ); + INIT4( sad_x4, _cache64_mmx2 ); + } +#else + if( cpu&X264_CPU_CACHELINE_64 && !(cpu&X264_CPU_SLOW_ATOM) ) + { + pixf->sad[PIXEL_8x16] = x264_pixel_sad_8x16_cache64_mmx2; + pixf->sad[PIXEL_8x8] = x264_pixel_sad_8x8_cache64_mmx2; + pixf->sad[PIXEL_8x4] = x264_pixel_sad_8x4_cache64_mmx2; + pixf->sad_x3[PIXEL_8x16] = x264_pixel_sad_x3_8x16_cache64_mmx2; + pixf->sad_x3[PIXEL_8x8] = x264_pixel_sad_x3_8x8_cache64_mmx2; + pixf->sad_x4[PIXEL_8x16] = x264_pixel_sad_x4_8x16_cache64_mmx2; + pixf->sad_x4[PIXEL_8x8] = x264_pixel_sad_x4_8x8_cache64_mmx2; + } +#endif + pixf->intra_satd_x3_16x16 = x264_intra_satd_x3_16x16_mmx2; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_mmx2; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_mmx2; + pixf->intra_sad_x3_8x16c = x264_intra_sad_x3_8x16c_mmx2; + pixf->intra_satd_x3_8x8c = x264_intra_satd_x3_8x8c_mmx2; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_mmx2; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_mmx2; + pixf->intra_satd_x3_4x4 = x264_intra_satd_x3_4x4_mmx2; + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_mmx2; + } + + if( cpu&X264_CPU_SSE2 ) + { + INIT5( ssd, _sse2slow ); + INIT2_NAME( sad_aligned, sad, _sse2_aligned ); + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_sse2; + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_sse2; + pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_sse2; + pixf->ssim_end4 = x264_pixel_ssim_end4_sse2; + pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16_sse2; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_sse2; +#if ARCH_X86_64 + pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_sse2; + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_sse2; +#endif + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_sse2; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_sse2; + pixf->vsad = x264_pixel_vsad_sse2; + pixf->asd8 = x264_pixel_asd8_sse2; + } + + if( (cpu&X264_CPU_SSE2) && !(cpu&X264_CPU_SSE2_IS_SLOW) ) + { + INIT2( sad, _sse2 ); + INIT2( sad_x3, _sse2 ); + INIT2( sad_x4, _sse2 ); + INIT6( satd, _sse2 ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_sse2; + INIT6( satd_x3, _sse2 ); + INIT6( satd_x4, _sse2 ); + INIT4( hadamard_ac, _sse2 ); + INIT_ADS( _sse2 ); + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_sse2; + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_sse2; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_sse2; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_sse2; + pixf->intra_sad_x3_8x16c = x264_intra_sad_x3_8x16c_sse2; + if( cpu&X264_CPU_CACHELINE_64 ) + { + INIT2( ssd, _sse2); /* faster for width 16 on p4 */ +#if ARCH_X86 + INIT2( sad, _cache64_sse2 ); + INIT2( sad_x3, _cache64_sse2 ); + INIT2( sad_x4, _cache64_sse2 ); +#endif + if( cpu&X264_CPU_SSE2_IS_FAST ) + { + pixf->sad_x3[PIXEL_8x16] = x264_pixel_sad_x3_8x16_cache64_sse2; + pixf->sad_x4[PIXEL_8x16] = x264_pixel_sad_x4_8x16_cache64_sse2; + } + } + } + + if( cpu&X264_CPU_SSE2_IS_FAST && !(cpu&X264_CPU_CACHELINE_64) ) + { + pixf->sad_aligned[PIXEL_8x16] = x264_pixel_sad_8x16_sse2; + pixf->sad[PIXEL_8x16] = x264_pixel_sad_8x16_sse2; + pixf->sad_x3[PIXEL_8x16] = x264_pixel_sad_x3_8x16_sse2; + pixf->sad_x3[PIXEL_8x8] = x264_pixel_sad_x3_8x8_sse2; + pixf->sad_x3[PIXEL_8x4] = x264_pixel_sad_x3_8x4_sse2; + pixf->sad_x4[PIXEL_8x16] = x264_pixel_sad_x4_8x16_sse2; + pixf->sad_x4[PIXEL_8x8] = x264_pixel_sad_x4_8x8_sse2; + pixf->sad_x4[PIXEL_8x4] = x264_pixel_sad_x4_8x4_sse2; + } + + if( (cpu&X264_CPU_SSE3) && (cpu&X264_CPU_CACHELINE_64) ) + { + INIT2( sad, _sse3 ); + INIT2( sad_x3, _sse3 ); + INIT2( sad_x4, _sse3 ); + } + + if( cpu&X264_CPU_SSSE3 ) + { + INIT4( hadamard_ac, _ssse3 ); + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + pixf->intra_sad_x9_4x4 = x264_intra_sad_x9_4x4_ssse3; + pixf->intra_satd_x9_4x4 = x264_intra_satd_x9_4x4_ssse3; + pixf->intra_sad_x9_8x8 = x264_intra_sad_x9_8x8_ssse3; +#if ARCH_X86_64 + pixf->intra_sa8d_x9_8x8 = x264_intra_sa8d_x9_8x8_ssse3; +#endif + } +#if ARCH_X86 || !defined( __MACH__ ) + INIT_ADS( _ssse3 ); +#endif + if( cpu&X264_CPU_SLOW_ATOM ) + { + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_ssse3_atom; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_ssse3_atom; + INIT6( satd, _ssse3_atom ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_ssse3_atom; + INIT6( satd_x3, _ssse3_atom ); + INIT6( satd_x4, _ssse3_atom ); + INIT4( hadamard_ac, _ssse3_atom ); +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_ssse3_atom; +#endif + } + else + { + INIT8( ssd, _ssse3 ); + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_ssse3; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_ssse3; + INIT8( satd, _ssse3 ); + INIT7( satd_x3, _ssse3 ); + INIT7( satd_x4, _ssse3 ); +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_ssse3; +#endif + } + pixf->intra_satd_x3_16x16 = x264_intra_satd_x3_16x16_ssse3; + if( !(cpu&X264_CPU_SLOW_PSHUFB) ) + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_ssse3; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_ssse3; + pixf->intra_satd_x3_8x8c = x264_intra_satd_x3_8x8c_ssse3; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_ssse3; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_ssse3; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_ssse3; + pixf->asd8 = x264_pixel_asd8_ssse3; + if( cpu&X264_CPU_CACHELINE_64 ) + { + INIT2( sad, _cache64_ssse3 ); + INIT2( sad_x3, _cache64_ssse3 ); + INIT2( sad_x4, _cache64_ssse3 ); + } + else + { + INIT2( sad_x3, _ssse3 ); + INIT5( sad_x4, _ssse3 ); + } + if( (cpu&X264_CPU_SLOW_ATOM) || (cpu&X264_CPU_SLOW_SHUFFLE) ) + { + INIT5( ssd, _sse2 ); /* on conroe, sse2 is faster for width8/16 */ + } + } + + if( cpu&X264_CPU_SSE4 ) + { + INIT8( satd, _sse4 ); + INIT7( satd_x3, _sse4 ); + INIT7( satd_x4, _sse4 ); + INIT4( hadamard_ac, _sse4 ); + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + pixf->intra_sad_x9_4x4 = x264_intra_sad_x9_4x4_sse4; + pixf->intra_satd_x9_4x4 = x264_intra_satd_x9_4x4_sse4; + pixf->intra_sad_x9_8x8 = x264_intra_sad_x9_8x8_sse4; +#if ARCH_X86_64 + pixf->intra_sa8d_x9_8x8 = x264_intra_sa8d_x9_8x8_sse4; +#endif + } + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_sse4; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_sse4; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_sse4; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_sse4; +#endif + } + + if( cpu&X264_CPU_AVX ) + { + INIT2_NAME( sad_aligned, sad, _sse2 ); /* AVX-capable CPUs doesn't benefit from an aligned version */ + INIT2( sad_x3, _avx ); + INIT2( sad_x4, _avx ); + INIT8( satd, _avx ); + INIT7( satd_x3, _avx ); + INIT7( satd_x4, _avx ); +#if ARCH_X86 || !defined( __MACH__ ) + INIT_ADS( _avx ); +#endif + INIT4( hadamard_ac, _avx ); + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + pixf->intra_sad_x9_4x4 = x264_intra_sad_x9_4x4_avx; + pixf->intra_satd_x9_4x4 = x264_intra_satd_x9_4x4_avx; + pixf->intra_sad_x9_8x8 = x264_intra_sad_x9_8x8_avx; +#if ARCH_X86_64 + pixf->intra_sa8d_x9_8x8 = x264_intra_sa8d_x9_8x8_avx; +#endif + } + INIT5( ssd, _avx ); + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_avx; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_avx; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_avx; + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_avx; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx; + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_avx; + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_avx; + pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_avx; + pixf->ssim_end4 = x264_pixel_ssim_end4_avx; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_avx; +#endif + } + + if( cpu&X264_CPU_XOP ) + { + INIT7( satd, _xop ); + INIT7( satd_x3, _xop ); + INIT7( satd_x4, _xop ); + INIT4( hadamard_ac, _xop ); + if( !(cpu&X264_CPU_STACK_MOD4) ) + { + pixf->intra_satd_x9_4x4 = x264_intra_satd_x9_4x4_xop; + } + INIT5( ssd, _xop ); + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_xop; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_xop; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_xop; + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_xop; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_xop; +#endif + } + + if( cpu&X264_CPU_AVX2 ) + { + INIT2( ssd, _avx2 ); + INIT2( sad_x3, _avx2 ); + INIT2( sad_x4, _avx2 ); + INIT4( satd, _avx2 ); + INIT2( hadamard_ac, _avx2 ); +#if ARCH_X86 || !defined( __MACH__ ) + INIT_ADS( _avx2 ); +#endif + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_avx2; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx2; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_avx2; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_avx2; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_avx2; + pixf->intra_sad_x9_8x8 = x264_intra_sad_x9_8x8_avx2; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_avx2; + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_avx2; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_avx2; +#endif + } + + if( cpu&X264_CPU_AVX512 ) + { + INIT8( sad, _avx512 ); + INIT8_NAME( sad_aligned, sad, _avx512 ); + INIT7( sad_x3, _avx512 ); + INIT7( sad_x4, _avx512 ); + INIT8( satd, _avx512 ); + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_avx512; + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_avx512; + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_avx512; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_avx512; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_avx512; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_avx512; + } +#endif //HAVE_MMX + +#if HAVE_ARMV6 + if( cpu&X264_CPU_ARMV6 ) + { + pixf->sad[PIXEL_4x8] = x264_pixel_sad_4x8_armv6; + pixf->sad[PIXEL_4x4] = x264_pixel_sad_4x4_armv6; + pixf->sad_aligned[PIXEL_4x8] = x264_pixel_sad_4x8_armv6; + pixf->sad_aligned[PIXEL_4x4] = x264_pixel_sad_4x4_armv6; + } + if( cpu&X264_CPU_NEON ) + { + INIT5( sad, _neon ); + INIT5( sad_aligned, _neon ); + INIT7( sad_x3, _neon ); + INIT7( sad_x4, _neon ); + INIT7( ssd, _neon ); + INIT7( satd, _neon ); + INIT7( satd_x3, _neon ); + INIT7( satd_x4, _neon ); + INIT4( hadamard_ac, _neon ); + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_neon; + pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16_neon; + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_neon; + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_neon; + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_neon; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_neon; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_neon; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_neon; + pixf->vsad = x264_pixel_vsad_neon; + pixf->asd8 = x264_pixel_asd8_neon; + + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_neon; + pixf->intra_satd_x3_4x4 = x264_intra_satd_x3_4x4_neon; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_neon; + pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_neon; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_neon; + pixf->intra_satd_x3_8x8c = x264_intra_satd_x3_8x8c_neon; + pixf->intra_sad_x3_8x16c = x264_intra_sad_x3_8x16c_neon; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_neon; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_neon; + pixf->intra_satd_x3_16x16 = x264_intra_satd_x3_16x16_neon; + + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_neon; + pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_neon; + pixf->ssim_end4 = x264_pixel_ssim_end4_neon; + + if( cpu&X264_CPU_FAST_NEON_MRC ) + { + pixf->sad[PIXEL_4x8] = x264_pixel_sad_4x8_neon; + pixf->sad[PIXEL_4x4] = x264_pixel_sad_4x4_neon; + pixf->sad_aligned[PIXEL_4x8] = x264_pixel_sad_aligned_4x8_neon; + pixf->sad_aligned[PIXEL_4x4] = x264_pixel_sad_aligned_4x4_neon; + } + else // really just scheduled for dual issue / A8 + { + INIT5( sad_aligned, _neon_dual ); + } + } +#endif + +#if ARCH_AARCH64 + if( cpu&X264_CPU_NEON ) + { + INIT8( sad, _neon ); + // AArch64 has no distinct instructions for aligned load/store + INIT8_NAME( sad_aligned, sad, _neon ); + INIT7( sad_x3, _neon ); + INIT7( sad_x4, _neon ); + INIT8( ssd, _neon ); + INIT8( satd, _neon ); + INIT7( satd_x3, _neon ); + INIT7( satd_x4, _neon ); + INIT4( hadamard_ac, _neon ); + + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_neon; + pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16_neon; + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_neon; + + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_neon; + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_neon; + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_neon; + pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_neon; + pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_neon; + pixf->vsad = x264_pixel_vsad_neon; + pixf->asd8 = x264_pixel_asd8_neon; + + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_neon; + pixf->intra_satd_x3_4x4 = x264_intra_satd_x3_4x4_neon; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_neon; + pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_neon; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_neon; + pixf->intra_satd_x3_8x8c = x264_intra_satd_x3_8x8c_neon; + pixf->intra_sad_x3_8x16c = x264_intra_sad_x3_8x16c_neon; + pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_neon; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_neon; + pixf->intra_satd_x3_16x16 = x264_intra_satd_x3_16x16_neon; + + pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_neon; + pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_neon; + pixf->ssim_end4 = x264_pixel_ssim_end4_neon; + } +#endif // ARCH_AARCH64 + +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + { + INIT8( sad, _msa ); + INIT8_NAME( sad_aligned, sad, _msa ); + INIT8( ssd, _msa ); + INIT7( sad_x3, _msa ); + INIT7( sad_x4, _msa ); + INIT8( satd, _msa ); + INIT4( hadamard_ac, _msa ); + + pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_msa; + pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_msa; + pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_msa; + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_msa; + pixf->intra_satd_x3_4x4 = x264_intra_satd_x3_4x4_msa; + pixf->intra_satd_x3_16x16 = x264_intra_satd_x3_16x16_msa; + pixf->intra_satd_x3_8x8c = x264_intra_satd_x3_8x8c_msa; + pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_msa; + + pixf->ssim_4x4x2_core = x264_ssim_4x4x2_core_msa; + + pixf->var[PIXEL_16x16] = x264_pixel_var_16x16_msa; + pixf->var[PIXEL_8x16] = x264_pixel_var_8x16_msa; + pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_msa; + //pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_msa; + //pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_msa; + pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16_msa; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_msa; + } +#endif // HAVE_MSA + +#endif // HIGH_BIT_DEPTH +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + { + x264_pixel_init_altivec( pixf ); + } +#endif + + pixf->ads[PIXEL_8x16] = + pixf->ads[PIXEL_8x4] = + pixf->ads[PIXEL_4x8] = pixf->ads[PIXEL_16x8]; + pixf->ads[PIXEL_4x4] = pixf->ads[PIXEL_8x8]; +} + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/pixel.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/pixel.h new file mode 100644 index 00000000..d4dbfaf2 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/pixel.h @@ -0,0 +1,155 @@ +/***************************************************************************** + * pixel.c: pixel metrics + ***************************************************************************** + * Copyright (C) 2004-2017 x264 project + * + * Authors: Loren Merritt + * Fiona Glaser + Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_PIXEL_H +#define X264_PIXEL_H + +// SSD assumes all args aligned +// other cmp functions assume first arg aligned +typedef int (*x264_pixel_cmp_t)( pixel *, intptr_t, pixel *, intptr_t ); +typedef void (*x264_pixel_cmp_x3_t)( pixel *, pixel *, pixel *, pixel *, intptr_t, int[3] ); +typedef void (*x264_pixel_cmp_x4_t)( pixel *, pixel *, pixel *, pixel *, pixel *, intptr_t, int[4] ); + +enum +{ + PIXEL_16x16 = 0, + PIXEL_16x8 = 1, + PIXEL_8x16 = 2, + PIXEL_8x8 = 3, + PIXEL_8x4 = 4, + PIXEL_4x8 = 5, + PIXEL_4x4 = 6, + + /* Subsampled chroma only */ + PIXEL_4x16 = 7, /* 4:2:2 */ + PIXEL_4x2 = 8, + PIXEL_2x8 = 9, /* 4:2:2 */ + PIXEL_2x4 = 10, + PIXEL_2x2 = 11, +}; + +static const struct { uint8_t w, h; } x264_pixel_size[12] = +{ + { 16, 16 }, { 16, 8 }, { 8, 16 }, { 8, 8 }, { 8, 4 }, { 4, 8 }, { 4, 4 }, + { 4, 16 }, { 4, 2 }, { 2, 8 }, { 2, 4 }, { 2, 2 }, +}; + +static const uint8_t x264_size2pixel[5][5] = +{ + { 0, }, + { 0, PIXEL_4x4, PIXEL_8x4, 0, 0 }, + { 0, PIXEL_4x8, PIXEL_8x8, 0, PIXEL_16x8 }, + { 0, }, + { 0, 0, PIXEL_8x16, 0, PIXEL_16x16 } +}; + +static const uint8_t x264_luma2chroma_pixel[4][7] = +{ + { 0 }, + { PIXEL_8x8, PIXEL_8x4, PIXEL_4x8, PIXEL_4x4, PIXEL_4x2, PIXEL_2x4, PIXEL_2x2 }, /* 4:2:0 */ + { PIXEL_8x16, PIXEL_8x8, PIXEL_4x16, PIXEL_4x8, PIXEL_4x4, PIXEL_2x8, PIXEL_2x4 }, /* 4:2:2 */ + { PIXEL_16x16, PIXEL_16x8, PIXEL_8x16, PIXEL_8x8, PIXEL_8x4, PIXEL_4x8, PIXEL_4x4 }, /* 4:4:4 */ +}; + +typedef struct +{ + x264_pixel_cmp_t sad[8]; + x264_pixel_cmp_t ssd[8]; + x264_pixel_cmp_t satd[8]; + x264_pixel_cmp_t ssim[7]; + x264_pixel_cmp_t sa8d[4]; + x264_pixel_cmp_t mbcmp[8]; /* either satd or sad for subpel refine and mode decision */ + x264_pixel_cmp_t mbcmp_unaligned[8]; /* unaligned mbcmp for subpel */ + x264_pixel_cmp_t fpelcmp[8]; /* either satd or sad for fullpel motion search */ + x264_pixel_cmp_x3_t fpelcmp_x3[7]; + x264_pixel_cmp_x4_t fpelcmp_x4[7]; + x264_pixel_cmp_t sad_aligned[8]; /* Aligned SAD for mbcmp */ + int (*vsad)( pixel *, intptr_t, int ); + int (*asd8)( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); + uint64_t (*sa8d_satd[1])( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); + + uint64_t (*var[4])( pixel *pix, intptr_t stride ); + int (*var2[4])( pixel *fenc, pixel *fdec, int ssd[2] ); + uint64_t (*hadamard_ac[4])( pixel *pix, intptr_t stride ); + + void (*ssd_nv12_core)( pixel *pixuv1, intptr_t stride1, + pixel *pixuv2, intptr_t stride2, int width, int height, + uint64_t *ssd_u, uint64_t *ssd_v ); + void (*ssim_4x4x2_core)( const pixel *pix1, intptr_t stride1, + const pixel *pix2, intptr_t stride2, int sums[2][4] ); + float (*ssim_end4)( int sum0[5][4], int sum1[5][4], int width ); + + /* multiple parallel calls to cmp. */ + x264_pixel_cmp_x3_t sad_x3[7]; + x264_pixel_cmp_x4_t sad_x4[7]; + x264_pixel_cmp_x3_t satd_x3[7]; + x264_pixel_cmp_x4_t satd_x4[7]; + + /* abs-diff-sum for successive elimination. + * may round width up to a multiple of 16. */ + int (*ads[7])( int enc_dc[4], uint16_t *sums, int delta, + uint16_t *cost_mvx, int16_t *mvs, int width, int thresh ); + + /* calculate satd or sad of V, H, and DC modes. */ + void (*intra_mbcmp_x3_16x16)( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_satd_x3_16x16) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_sad_x3_16x16) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_mbcmp_x3_4x4) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_satd_x3_4x4) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_sad_x3_4x4) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_mbcmp_x3_chroma)( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_satd_x3_chroma) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_sad_x3_chroma) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_mbcmp_x3_8x16c) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_satd_x3_8x16c) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_sad_x3_8x16c) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_mbcmp_x3_8x8c) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_satd_x3_8x8c) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_sad_x3_8x8c) ( pixel *fenc, pixel *fdec, int res[3] ); + void (*intra_mbcmp_x3_8x8) ( pixel *fenc, pixel edge[36], int res[3] ); + void (*intra_sa8d_x3_8x8) ( pixel *fenc, pixel edge[36], int res[3] ); + void (*intra_sad_x3_8x8) ( pixel *fenc, pixel edge[36], int res[3] ); + /* find minimum satd or sad of all modes, and set fdec. + * may be NULL, in which case just use pred+satd instead. */ + int (*intra_mbcmp_x9_4x4)( pixel *fenc, pixel *fdec, uint16_t *bitcosts ); + int (*intra_satd_x9_4x4) ( pixel *fenc, pixel *fdec, uint16_t *bitcosts ); + int (*intra_sad_x9_4x4) ( pixel *fenc, pixel *fdec, uint16_t *bitcosts ); + int (*intra_mbcmp_x9_8x8)( pixel *fenc, pixel *fdec, pixel edge[36], uint16_t *bitcosts, uint16_t *satds ); + int (*intra_sa8d_x9_8x8) ( pixel *fenc, pixel *fdec, pixel edge[36], uint16_t *bitcosts, uint16_t *satds ); + int (*intra_sad_x9_8x8) ( pixel *fenc, pixel *fdec, pixel edge[36], uint16_t *bitcosts, uint16_t *satds ); +} x264_pixel_function_t; + +void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ); +void x264_pixel_ssd_nv12 ( x264_pixel_function_t *pf, pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2, + int i_width, int i_height, uint64_t *ssd_u, uint64_t *ssd_v ); +uint64_t x264_pixel_ssd_wxh( x264_pixel_function_t *pf, pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2, + int i_width, int i_height ); +float x264_pixel_ssim_wxh ( x264_pixel_function_t *pf, pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2, + int i_width, int i_height, void *buf, int *cnt ); +int x264_field_vsad( x264_t *h, int mb_x, int mb_y ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/predict.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/predict.c new file mode 100644 index 00000000..8163f942 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/predict.c @@ -0,0 +1,1054 @@ +/***************************************************************************** + * predict.c: intra prediction + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +/* predict4x4 are inspired from ffmpeg h264 decoder */ + + +#include "common.h" + +#if HAVE_MMX +# include "x86/predict.h" +#endif +#if ARCH_PPC +# include "ppc/predict.h" +#endif +#if ARCH_ARM +# include "arm/predict.h" +#endif +#if ARCH_AARCH64 +# include "aarch64/predict.h" +#endif +#if ARCH_MIPS +# include "mips/predict.h" +#endif + +/**************************************************************************** + * 16x16 prediction for intra luma block + ****************************************************************************/ + +#define PREDICT_16x16_DC(v)\ + for( int i = 0; i < 16; i++ )\ + {\ + MPIXEL_X4( src+ 0 ) = v;\ + MPIXEL_X4( src+ 4 ) = v;\ + MPIXEL_X4( src+ 8 ) = v;\ + MPIXEL_X4( src+12 ) = v;\ + src += FDEC_STRIDE;\ + } + +void x264_predict_16x16_dc_c( pixel *src ) +{ + int dc = 0; + + for( int i = 0; i < 16; i++ ) + { + dc += src[-1 + i * FDEC_STRIDE]; + dc += src[i - FDEC_STRIDE]; + } + pixel4 dcsplat = PIXEL_SPLAT_X4( ( dc + 16 ) >> 5 ); + + PREDICT_16x16_DC( dcsplat ); +} +static void x264_predict_16x16_dc_left_c( pixel *src ) +{ + int dc = 0; + + for( int i = 0; i < 16; i++ ) + dc += src[-1 + i * FDEC_STRIDE]; + pixel4 dcsplat = PIXEL_SPLAT_X4( ( dc + 8 ) >> 4 ); + + PREDICT_16x16_DC( dcsplat ); +} +static void x264_predict_16x16_dc_top_c( pixel *src ) +{ + int dc = 0; + + for( int i = 0; i < 16; i++ ) + dc += src[i - FDEC_STRIDE]; + pixel4 dcsplat = PIXEL_SPLAT_X4( ( dc + 8 ) >> 4 ); + + PREDICT_16x16_DC( dcsplat ); +} +static void x264_predict_16x16_dc_128_c( pixel *src ) +{ + PREDICT_16x16_DC( PIXEL_SPLAT_X4( 1 << (BIT_DEPTH-1) ) ); +} +void x264_predict_16x16_h_c( pixel *src ) +{ + for( int i = 0; i < 16; i++ ) + { + const pixel4 v = PIXEL_SPLAT_X4( src[-1] ); + MPIXEL_X4( src+ 0 ) = v; + MPIXEL_X4( src+ 4 ) = v; + MPIXEL_X4( src+ 8 ) = v; + MPIXEL_X4( src+12 ) = v; + src += FDEC_STRIDE; + } +} +void x264_predict_16x16_v_c( pixel *src ) +{ + pixel4 v0 = MPIXEL_X4( &src[ 0-FDEC_STRIDE] ); + pixel4 v1 = MPIXEL_X4( &src[ 4-FDEC_STRIDE] ); + pixel4 v2 = MPIXEL_X4( &src[ 8-FDEC_STRIDE] ); + pixel4 v3 = MPIXEL_X4( &src[12-FDEC_STRIDE] ); + + for( int i = 0; i < 16; i++ ) + { + MPIXEL_X4( src+ 0 ) = v0; + MPIXEL_X4( src+ 4 ) = v1; + MPIXEL_X4( src+ 8 ) = v2; + MPIXEL_X4( src+12 ) = v3; + src += FDEC_STRIDE; + } +} +void x264_predict_16x16_p_c( pixel *src ) +{ + int H = 0, V = 0; + + /* calculate H and V */ + for( int i = 0; i <= 7; i++ ) + { + H += ( i + 1 ) * ( src[ 8 + i - FDEC_STRIDE ] - src[6 -i -FDEC_STRIDE] ); + V += ( i + 1 ) * ( src[-1 + (8+i)*FDEC_STRIDE] - src[-1 + (6-i)*FDEC_STRIDE] ); + } + + int a = 16 * ( src[-1 + 15*FDEC_STRIDE] + src[15 - FDEC_STRIDE] ); + int b = ( 5 * H + 32 ) >> 6; + int c = ( 5 * V + 32 ) >> 6; + + int i00 = a - b * 7 - c * 7 + 16; + + for( int y = 0; y < 16; y++ ) + { + int pix = i00; + for( int x = 0; x < 16; x++ ) + { + src[x] = x264_clip_pixel( pix>>5 ); + pix += b; + } + src += FDEC_STRIDE; + i00 += c; + } +} + + +/**************************************************************************** + * 8x8 prediction for intra chroma block (4:2:0) + ****************************************************************************/ + +static void x264_predict_8x8c_dc_128_c( pixel *src ) +{ + for( int y = 0; y < 8; y++ ) + { + MPIXEL_X4( src+0 ) = PIXEL_SPLAT_X4( 1 << (BIT_DEPTH-1) ); + MPIXEL_X4( src+4 ) = PIXEL_SPLAT_X4( 1 << (BIT_DEPTH-1) ); + src += FDEC_STRIDE; + } +} +static void x264_predict_8x8c_dc_left_c( pixel *src ) +{ + int dc0 = 0, dc1 = 0; + + for( int y = 0; y < 4; y++ ) + { + dc0 += src[y * FDEC_STRIDE - 1]; + dc1 += src[(y+4) * FDEC_STRIDE - 1]; + } + pixel4 dc0splat = PIXEL_SPLAT_X4( ( dc0 + 2 ) >> 2 ); + pixel4 dc1splat = PIXEL_SPLAT_X4( ( dc1 + 2 ) >> 2 ); + + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dc0splat; + MPIXEL_X4( src+4 ) = dc0splat; + src += FDEC_STRIDE; + } + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dc1splat; + MPIXEL_X4( src+4 ) = dc1splat; + src += FDEC_STRIDE; + } + +} +static void x264_predict_8x8c_dc_top_c( pixel *src ) +{ + int dc0 = 0, dc1 = 0; + + for( int x = 0; x < 4; x++ ) + { + dc0 += src[x - FDEC_STRIDE]; + dc1 += src[x + 4 - FDEC_STRIDE]; + } + pixel4 dc0splat = PIXEL_SPLAT_X4( ( dc0 + 2 ) >> 2 ); + pixel4 dc1splat = PIXEL_SPLAT_X4( ( dc1 + 2 ) >> 2 ); + + for( int y = 0; y < 8; y++ ) + { + MPIXEL_X4( src+0 ) = dc0splat; + MPIXEL_X4( src+4 ) = dc1splat; + src += FDEC_STRIDE; + } +} +void x264_predict_8x8c_dc_c( pixel *src ) +{ + int s0 = 0, s1 = 0, s2 = 0, s3 = 0; + + /* + s0 s1 + s2 + s3 + */ + for( int i = 0; i < 4; i++ ) + { + s0 += src[i - FDEC_STRIDE]; + s1 += src[i + 4 - FDEC_STRIDE]; + s2 += src[-1 + i * FDEC_STRIDE]; + s3 += src[-1 + (i+4)*FDEC_STRIDE]; + } + /* + dc0 dc1 + dc2 dc3 + */ + pixel4 dc0 = PIXEL_SPLAT_X4( ( s0 + s2 + 4 ) >> 3 ); + pixel4 dc1 = PIXEL_SPLAT_X4( ( s1 + 2 ) >> 2 ); + pixel4 dc2 = PIXEL_SPLAT_X4( ( s3 + 2 ) >> 2 ); + pixel4 dc3 = PIXEL_SPLAT_X4( ( s1 + s3 + 4 ) >> 3 ); + + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dc0; + MPIXEL_X4( src+4 ) = dc1; + src += FDEC_STRIDE; + } + + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dc2; + MPIXEL_X4( src+4 ) = dc3; + src += FDEC_STRIDE; + } +} +void x264_predict_8x8c_h_c( pixel *src ) +{ + for( int i = 0; i < 8; i++ ) + { + pixel4 v = PIXEL_SPLAT_X4( src[-1] ); + MPIXEL_X4( src+0 ) = v; + MPIXEL_X4( src+4 ) = v; + src += FDEC_STRIDE; + } +} +void x264_predict_8x8c_v_c( pixel *src ) +{ + pixel4 v0 = MPIXEL_X4( src+0-FDEC_STRIDE ); + pixel4 v1 = MPIXEL_X4( src+4-FDEC_STRIDE ); + + for( int i = 0; i < 8; i++ ) + { + MPIXEL_X4( src+0 ) = v0; + MPIXEL_X4( src+4 ) = v1; + src += FDEC_STRIDE; + } +} +void x264_predict_8x8c_p_c( pixel *src ) +{ + int H = 0, V = 0; + + for( int i = 0; i < 4; i++ ) + { + H += ( i + 1 ) * ( src[4+i - FDEC_STRIDE] - src[2 - i -FDEC_STRIDE] ); + V += ( i + 1 ) * ( src[-1 +(i+4)*FDEC_STRIDE] - src[-1+(2-i)*FDEC_STRIDE] ); + } + + int a = 16 * ( src[-1+7*FDEC_STRIDE] + src[7 - FDEC_STRIDE] ); + int b = ( 17 * H + 16 ) >> 5; + int c = ( 17 * V + 16 ) >> 5; + int i00 = a -3*b -3*c + 16; + + for( int y = 0; y < 8; y++ ) + { + int pix = i00; + for( int x = 0; x < 8; x++ ) + { + src[x] = x264_clip_pixel( pix>>5 ); + pix += b; + } + src += FDEC_STRIDE; + i00 += c; + } +} + +/**************************************************************************** + * 8x16 prediction for intra chroma block (4:2:2) + ****************************************************************************/ + +static void x264_predict_8x16c_dc_128_c( pixel *src ) +{ + for( int y = 0; y < 16; y++ ) + { + MPIXEL_X4( src+0 ) = PIXEL_SPLAT_X4( 1 << (BIT_DEPTH-1) ); + MPIXEL_X4( src+4 ) = PIXEL_SPLAT_X4( 1 << (BIT_DEPTH-1) ); + src += FDEC_STRIDE; + } +} +static void x264_predict_8x16c_dc_left_c( pixel *src ) +{ + for( int i = 0; i < 4; i++ ) + { + int dc = 0; + + for( int y = 0; y < 4; y++ ) + dc += src[y*FDEC_STRIDE - 1]; + + pixel4 dcsplat = PIXEL_SPLAT_X4( (dc + 2) >> 2 ); + + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dcsplat; + MPIXEL_X4( src+4 ) = dcsplat; + src += FDEC_STRIDE; + } + } +} +static void x264_predict_8x16c_dc_top_c( pixel *src ) +{ + int dc0 = 0, dc1 = 0; + + for( int x = 0; x < 4; x++ ) + { + dc0 += src[x - FDEC_STRIDE]; + dc1 += src[x + 4 - FDEC_STRIDE]; + } + pixel4 dc0splat = PIXEL_SPLAT_X4( ( dc0 + 2 ) >> 2 ); + pixel4 dc1splat = PIXEL_SPLAT_X4( ( dc1 + 2 ) >> 2 ); + + for( int y = 0; y < 16; y++ ) + { + MPIXEL_X4( src+0 ) = dc0splat; + MPIXEL_X4( src+4 ) = dc1splat; + src += FDEC_STRIDE; + } +} +void x264_predict_8x16c_dc_c( pixel *src ) +{ + int s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0; + + /* + s0 s1 + s2 + s3 + s4 + s5 + */ + for( int i = 0; i < 4; i++ ) + { + s0 += src[i+0 - FDEC_STRIDE]; + s1 += src[i+4 - FDEC_STRIDE]; + s2 += src[-1 + (i+0) * FDEC_STRIDE]; + s3 += src[-1 + (i+4) * FDEC_STRIDE]; + s4 += src[-1 + (i+8) * FDEC_STRIDE]; + s5 += src[-1 + (i+12) * FDEC_STRIDE]; + } + /* + dc0 dc1 + dc2 dc3 + dc4 dc5 + dc6 dc7 + */ + pixel4 dc0 = PIXEL_SPLAT_X4( ( s0 + s2 + 4 ) >> 3 ); + pixel4 dc1 = PIXEL_SPLAT_X4( ( s1 + 2 ) >> 2 ); + pixel4 dc2 = PIXEL_SPLAT_X4( ( s3 + 2 ) >> 2 ); + pixel4 dc3 = PIXEL_SPLAT_X4( ( s1 + s3 + 4 ) >> 3 ); + pixel4 dc4 = PIXEL_SPLAT_X4( ( s4 + 2 ) >> 2 ); + pixel4 dc5 = PIXEL_SPLAT_X4( ( s1 + s4 + 4 ) >> 3 ); + pixel4 dc6 = PIXEL_SPLAT_X4( ( s5 + 2 ) >> 2 ); + pixel4 dc7 = PIXEL_SPLAT_X4( ( s1 + s5 + 4 ) >> 3 ); + + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dc0; + MPIXEL_X4( src+4 ) = dc1; + src += FDEC_STRIDE; + } + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dc2; + MPIXEL_X4( src+4 ) = dc3; + src += FDEC_STRIDE; + } + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dc4; + MPIXEL_X4( src+4 ) = dc5; + src += FDEC_STRIDE; + } + for( int y = 0; y < 4; y++ ) + { + MPIXEL_X4( src+0 ) = dc6; + MPIXEL_X4( src+4 ) = dc7; + src += FDEC_STRIDE; + } +} +void x264_predict_8x16c_h_c( pixel *src ) +{ + for( int i = 0; i < 16; i++ ) + { + pixel4 v = PIXEL_SPLAT_X4( src[-1] ); + MPIXEL_X4( src+0 ) = v; + MPIXEL_X4( src+4 ) = v; + src += FDEC_STRIDE; + } +} +void x264_predict_8x16c_v_c( pixel *src ) +{ + pixel4 v0 = MPIXEL_X4( src+0-FDEC_STRIDE ); + pixel4 v1 = MPIXEL_X4( src+4-FDEC_STRIDE ); + + for( int i = 0; i < 16; i++ ) + { + MPIXEL_X4( src+0 ) = v0; + MPIXEL_X4( src+4 ) = v1; + src += FDEC_STRIDE; + } +} +void x264_predict_8x16c_p_c( pixel *src ) +{ + int H = 0; + int V = 0; + + for( int i = 0; i < 4; i++ ) + H += ( i + 1 ) * ( src[4 + i - FDEC_STRIDE] - src[2 - i - FDEC_STRIDE] ); + for( int i = 0; i < 8; i++ ) + V += ( i + 1 ) * ( src[-1 + (i+8)*FDEC_STRIDE] - src[-1 + (6-i)*FDEC_STRIDE] ); + + int a = 16 * ( src[-1 + 15*FDEC_STRIDE] + src[7 - FDEC_STRIDE] ); + int b = ( 17 * H + 16 ) >> 5; + int c = ( 5 * V + 32 ) >> 6; + int i00 = a -3*b -7*c + 16; + + for( int y = 0; y < 16; y++ ) + { + int pix = i00; + for( int x = 0; x < 8; x++ ) + { + src[x] = x264_clip_pixel( pix>>5 ); + pix += b; + } + src += FDEC_STRIDE; + i00 += c; + } +} + +/**************************************************************************** + * 4x4 prediction for intra luma block + ****************************************************************************/ + +#define SRC(x,y) src[(x)+(y)*FDEC_STRIDE] +#define SRC_X4(x,y) MPIXEL_X4( &SRC(x,y) ) + +#define PREDICT_4x4_DC(v)\ + SRC_X4(0,0) = SRC_X4(0,1) = SRC_X4(0,2) = SRC_X4(0,3) = v; + +static void x264_predict_4x4_dc_128_c( pixel *src ) +{ + PREDICT_4x4_DC( PIXEL_SPLAT_X4( 1 << (BIT_DEPTH-1) ) ); +} +static void x264_predict_4x4_dc_left_c( pixel *src ) +{ + pixel4 dc = PIXEL_SPLAT_X4( (SRC(-1,0) + SRC(-1,1) + SRC(-1,2) + SRC(-1,3) + 2) >> 2 ); + PREDICT_4x4_DC( dc ); +} +static void x264_predict_4x4_dc_top_c( pixel *src ) +{ + pixel4 dc = PIXEL_SPLAT_X4( (SRC(0,-1) + SRC(1,-1) + SRC(2,-1) + SRC(3,-1) + 2) >> 2 ); + PREDICT_4x4_DC( dc ); +} +void x264_predict_4x4_dc_c( pixel *src ) +{ + pixel4 dc = PIXEL_SPLAT_X4( (SRC(-1,0) + SRC(-1,1) + SRC(-1,2) + SRC(-1,3) + + SRC(0,-1) + SRC(1,-1) + SRC(2,-1) + SRC(3,-1) + 4) >> 3 ); + PREDICT_4x4_DC( dc ); +} +void x264_predict_4x4_h_c( pixel *src ) +{ + SRC_X4(0,0) = PIXEL_SPLAT_X4( SRC(-1,0) ); + SRC_X4(0,1) = PIXEL_SPLAT_X4( SRC(-1,1) ); + SRC_X4(0,2) = PIXEL_SPLAT_X4( SRC(-1,2) ); + SRC_X4(0,3) = PIXEL_SPLAT_X4( SRC(-1,3) ); +} +void x264_predict_4x4_v_c( pixel *src ) +{ + PREDICT_4x4_DC(SRC_X4(0,-1)); +} + +#define PREDICT_4x4_LOAD_LEFT\ + int l0 = SRC(-1,0);\ + int l1 = SRC(-1,1);\ + int l2 = SRC(-1,2);\ + UNUSED int l3 = SRC(-1,3); + +#define PREDICT_4x4_LOAD_TOP\ + int t0 = SRC(0,-1);\ + int t1 = SRC(1,-1);\ + int t2 = SRC(2,-1);\ + UNUSED int t3 = SRC(3,-1); + +#define PREDICT_4x4_LOAD_TOP_RIGHT\ + int t4 = SRC(4,-1);\ + int t5 = SRC(5,-1);\ + int t6 = SRC(6,-1);\ + UNUSED int t7 = SRC(7,-1); + +#define F1(a,b) (((a)+(b)+1)>>1) +#define F2(a,b,c) (((a)+2*(b)+(c)+2)>>2) + +static void x264_predict_4x4_ddl_c( pixel *src ) +{ + PREDICT_4x4_LOAD_TOP + PREDICT_4x4_LOAD_TOP_RIGHT + SRC(0,0)= F2(t0,t1,t2); + SRC(1,0)=SRC(0,1)= F2(t1,t2,t3); + SRC(2,0)=SRC(1,1)=SRC(0,2)= F2(t2,t3,t4); + SRC(3,0)=SRC(2,1)=SRC(1,2)=SRC(0,3)= F2(t3,t4,t5); + SRC(3,1)=SRC(2,2)=SRC(1,3)= F2(t4,t5,t6); + SRC(3,2)=SRC(2,3)= F2(t5,t6,t7); + SRC(3,3)= F2(t6,t7,t7); +} +static void x264_predict_4x4_ddr_c( pixel *src ) +{ + int lt = SRC(-1,-1); + PREDICT_4x4_LOAD_LEFT + PREDICT_4x4_LOAD_TOP + SRC(3,0)= F2(t3,t2,t1); + SRC(2,0)=SRC(3,1)= F2(t2,t1,t0); + SRC(1,0)=SRC(2,1)=SRC(3,2)= F2(t1,t0,lt); + SRC(0,0)=SRC(1,1)=SRC(2,2)=SRC(3,3)= F2(t0,lt,l0); + SRC(0,1)=SRC(1,2)=SRC(2,3)= F2(lt,l0,l1); + SRC(0,2)=SRC(1,3)= F2(l0,l1,l2); + SRC(0,3)= F2(l1,l2,l3); +} + +static void x264_predict_4x4_vr_c( pixel *src ) +{ + int lt = SRC(-1,-1); + PREDICT_4x4_LOAD_LEFT + PREDICT_4x4_LOAD_TOP + SRC(0,3)= F2(l2,l1,l0); + SRC(0,2)= F2(l1,l0,lt); + SRC(0,1)=SRC(1,3)= F2(l0,lt,t0); + SRC(0,0)=SRC(1,2)= F1(lt,t0); + SRC(1,1)=SRC(2,3)= F2(lt,t0,t1); + SRC(1,0)=SRC(2,2)= F1(t0,t1); + SRC(2,1)=SRC(3,3)= F2(t0,t1,t2); + SRC(2,0)=SRC(3,2)= F1(t1,t2); + SRC(3,1)= F2(t1,t2,t3); + SRC(3,0)= F1(t2,t3); +} + +static void x264_predict_4x4_hd_c( pixel *src ) +{ + int lt= SRC(-1,-1); + PREDICT_4x4_LOAD_LEFT + PREDICT_4x4_LOAD_TOP + SRC(0,3)= F1(l2,l3); + SRC(1,3)= F2(l1,l2,l3); + SRC(0,2)=SRC(2,3)= F1(l1,l2); + SRC(1,2)=SRC(3,3)= F2(l0,l1,l2); + SRC(0,1)=SRC(2,2)= F1(l0,l1); + SRC(1,1)=SRC(3,2)= F2(lt,l0,l1); + SRC(0,0)=SRC(2,1)= F1(lt,l0); + SRC(1,0)=SRC(3,1)= F2(t0,lt,l0); + SRC(2,0)= F2(t1,t0,lt); + SRC(3,0)= F2(t2,t1,t0); +} + +static void x264_predict_4x4_vl_c( pixel *src ) +{ + PREDICT_4x4_LOAD_TOP + PREDICT_4x4_LOAD_TOP_RIGHT + SRC(0,0)= F1(t0,t1); + SRC(0,1)= F2(t0,t1,t2); + SRC(1,0)=SRC(0,2)= F1(t1,t2); + SRC(1,1)=SRC(0,3)= F2(t1,t2,t3); + SRC(2,0)=SRC(1,2)= F1(t2,t3); + SRC(2,1)=SRC(1,3)= F2(t2,t3,t4); + SRC(3,0)=SRC(2,2)= F1(t3,t4); + SRC(3,1)=SRC(2,3)= F2(t3,t4,t5); + SRC(3,2)= F1(t4,t5); + SRC(3,3)= F2(t4,t5,t6); +} + +static void x264_predict_4x4_hu_c( pixel *src ) +{ + PREDICT_4x4_LOAD_LEFT + SRC(0,0)= F1(l0,l1); + SRC(1,0)= F2(l0,l1,l2); + SRC(2,0)=SRC(0,1)= F1(l1,l2); + SRC(3,0)=SRC(1,1)= F2(l1,l2,l3); + SRC(2,1)=SRC(0,2)= F1(l2,l3); + SRC(3,1)=SRC(1,2)= F2(l2,l3,l3); + SRC(3,2)=SRC(1,3)=SRC(0,3)= + SRC(2,2)=SRC(2,3)=SRC(3,3)= l3; +} + +/**************************************************************************** + * 8x8 prediction for intra luma block + ****************************************************************************/ + +#define PL(y) \ + edge[14-y] = F2(SRC(-1,y-1), SRC(-1,y), SRC(-1,y+1)); +#define PT(x) \ + edge[16+x] = F2(SRC(x-1,-1), SRC(x,-1), SRC(x+1,-1)); + +static void x264_predict_8x8_filter_c( pixel *src, pixel edge[36], int i_neighbor, int i_filters ) +{ + /* edge[7..14] = l7..l0 + * edge[15] = lt + * edge[16..31] = t0 .. t15 + * edge[32] = t15 */ + + int have_lt = i_neighbor & MB_TOPLEFT; + if( i_filters & MB_LEFT ) + { + edge[15] = (SRC(0,-1) + 2*SRC(-1,-1) + SRC(-1,0) + 2) >> 2; + edge[14] = ((have_lt ? SRC(-1,-1) : SRC(-1,0)) + + 2*SRC(-1,0) + SRC(-1,1) + 2) >> 2; + PL(1) PL(2) PL(3) PL(4) PL(5) PL(6) + edge[6] = + edge[7] = (SRC(-1,6) + 3*SRC(-1,7) + 2) >> 2; + } + + if( i_filters & MB_TOP ) + { + int have_tr = i_neighbor & MB_TOPRIGHT; + edge[16] = ((have_lt ? SRC(-1,-1) : SRC(0,-1)) + + 2*SRC(0,-1) + SRC(1,-1) + 2) >> 2; + PT(1) PT(2) PT(3) PT(4) PT(5) PT(6) + edge[23] = (SRC(6,-1) + 2*SRC(7,-1) + + (have_tr ? SRC(8,-1) : SRC(7,-1)) + 2) >> 2; + + if( i_filters & MB_TOPRIGHT ) + { + if( have_tr ) + { + PT(8) PT(9) PT(10) PT(11) PT(12) PT(13) PT(14) + edge[31] = + edge[32] = (SRC(14,-1) + 3*SRC(15,-1) + 2) >> 2; + } + else + { + MPIXEL_X4( edge+24 ) = PIXEL_SPLAT_X4( SRC(7,-1) ); + MPIXEL_X4( edge+28 ) = PIXEL_SPLAT_X4( SRC(7,-1) ); + edge[32] = SRC(7,-1); + } + } + } +} + +#undef PL +#undef PT + +#define PL(y) \ + UNUSED int l##y = edge[14-y]; +#define PT(x) \ + UNUSED int t##x = edge[16+x]; +#define PREDICT_8x8_LOAD_TOPLEFT \ + int lt = edge[15]; +#define PREDICT_8x8_LOAD_LEFT \ + PL(0) PL(1) PL(2) PL(3) PL(4) PL(5) PL(6) PL(7) +#define PREDICT_8x8_LOAD_TOP \ + PT(0) PT(1) PT(2) PT(3) PT(4) PT(5) PT(6) PT(7) +#define PREDICT_8x8_LOAD_TOPRIGHT \ + PT(8) PT(9) PT(10) PT(11) PT(12) PT(13) PT(14) PT(15) + +#define PREDICT_8x8_DC(v) \ + for( int y = 0; y < 8; y++ ) { \ + MPIXEL_X4( src+0 ) = v; \ + MPIXEL_X4( src+4 ) = v; \ + src += FDEC_STRIDE; \ + } + +static void x264_predict_8x8_dc_128_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_DC( PIXEL_SPLAT_X4( 1 << (BIT_DEPTH-1) ) ); +} +static void x264_predict_8x8_dc_left_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_LEFT + pixel4 dc = PIXEL_SPLAT_X4( (l0+l1+l2+l3+l4+l5+l6+l7+4) >> 3 ); + PREDICT_8x8_DC( dc ); +} +static void x264_predict_8x8_dc_top_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_TOP + pixel4 dc = PIXEL_SPLAT_X4( (t0+t1+t2+t3+t4+t5+t6+t7+4) >> 3 ); + PREDICT_8x8_DC( dc ); +} +void x264_predict_8x8_dc_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_LEFT + PREDICT_8x8_LOAD_TOP + pixel4 dc = PIXEL_SPLAT_X4( (l0+l1+l2+l3+l4+l5+l6+l7+t0+t1+t2+t3+t4+t5+t6+t7+8) >> 4 ); + PREDICT_8x8_DC( dc ); +} +void x264_predict_8x8_h_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_LEFT +#define ROW(y) MPIXEL_X4( src+y*FDEC_STRIDE+0 ) =\ + MPIXEL_X4( src+y*FDEC_STRIDE+4 ) = PIXEL_SPLAT_X4( l##y ); + ROW(0); ROW(1); ROW(2); ROW(3); ROW(4); ROW(5); ROW(6); ROW(7); +#undef ROW +} +void x264_predict_8x8_v_c( pixel *src, pixel edge[36] ) +{ + pixel4 top[2] = { MPIXEL_X4( edge+16 ), + MPIXEL_X4( edge+20 ) }; + for( int y = 0; y < 8; y++ ) + { + MPIXEL_X4( src+y*FDEC_STRIDE+0 ) = top[0]; + MPIXEL_X4( src+y*FDEC_STRIDE+4 ) = top[1]; + } +} +static void x264_predict_8x8_ddl_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_TOP + PREDICT_8x8_LOAD_TOPRIGHT + SRC(0,0)= F2(t0,t1,t2); + SRC(0,1)=SRC(1,0)= F2(t1,t2,t3); + SRC(0,2)=SRC(1,1)=SRC(2,0)= F2(t2,t3,t4); + SRC(0,3)=SRC(1,2)=SRC(2,1)=SRC(3,0)= F2(t3,t4,t5); + SRC(0,4)=SRC(1,3)=SRC(2,2)=SRC(3,1)=SRC(4,0)= F2(t4,t5,t6); + SRC(0,5)=SRC(1,4)=SRC(2,3)=SRC(3,2)=SRC(4,1)=SRC(5,0)= F2(t5,t6,t7); + SRC(0,6)=SRC(1,5)=SRC(2,4)=SRC(3,3)=SRC(4,2)=SRC(5,1)=SRC(6,0)= F2(t6,t7,t8); + SRC(0,7)=SRC(1,6)=SRC(2,5)=SRC(3,4)=SRC(4,3)=SRC(5,2)=SRC(6,1)=SRC(7,0)= F2(t7,t8,t9); + SRC(1,7)=SRC(2,6)=SRC(3,5)=SRC(4,4)=SRC(5,3)=SRC(6,2)=SRC(7,1)= F2(t8,t9,t10); + SRC(2,7)=SRC(3,6)=SRC(4,5)=SRC(5,4)=SRC(6,3)=SRC(7,2)= F2(t9,t10,t11); + SRC(3,7)=SRC(4,6)=SRC(5,5)=SRC(6,4)=SRC(7,3)= F2(t10,t11,t12); + SRC(4,7)=SRC(5,6)=SRC(6,5)=SRC(7,4)= F2(t11,t12,t13); + SRC(5,7)=SRC(6,6)=SRC(7,5)= F2(t12,t13,t14); + SRC(6,7)=SRC(7,6)= F2(t13,t14,t15); + SRC(7,7)= F2(t14,t15,t15); +} +static void x264_predict_8x8_ddr_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_TOP + PREDICT_8x8_LOAD_LEFT + PREDICT_8x8_LOAD_TOPLEFT + SRC(0,7)= F2(l7,l6,l5); + SRC(0,6)=SRC(1,7)= F2(l6,l5,l4); + SRC(0,5)=SRC(1,6)=SRC(2,7)= F2(l5,l4,l3); + SRC(0,4)=SRC(1,5)=SRC(2,6)=SRC(3,7)= F2(l4,l3,l2); + SRC(0,3)=SRC(1,4)=SRC(2,5)=SRC(3,6)=SRC(4,7)= F2(l3,l2,l1); + SRC(0,2)=SRC(1,3)=SRC(2,4)=SRC(3,5)=SRC(4,6)=SRC(5,7)= F2(l2,l1,l0); + SRC(0,1)=SRC(1,2)=SRC(2,3)=SRC(3,4)=SRC(4,5)=SRC(5,6)=SRC(6,7)= F2(l1,l0,lt); + SRC(0,0)=SRC(1,1)=SRC(2,2)=SRC(3,3)=SRC(4,4)=SRC(5,5)=SRC(6,6)=SRC(7,7)= F2(l0,lt,t0); + SRC(1,0)=SRC(2,1)=SRC(3,2)=SRC(4,3)=SRC(5,4)=SRC(6,5)=SRC(7,6)= F2(lt,t0,t1); + SRC(2,0)=SRC(3,1)=SRC(4,2)=SRC(5,3)=SRC(6,4)=SRC(7,5)= F2(t0,t1,t2); + SRC(3,0)=SRC(4,1)=SRC(5,2)=SRC(6,3)=SRC(7,4)= F2(t1,t2,t3); + SRC(4,0)=SRC(5,1)=SRC(6,2)=SRC(7,3)= F2(t2,t3,t4); + SRC(5,0)=SRC(6,1)=SRC(7,2)= F2(t3,t4,t5); + SRC(6,0)=SRC(7,1)= F2(t4,t5,t6); + SRC(7,0)= F2(t5,t6,t7); + +} +static void x264_predict_8x8_vr_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_TOP + PREDICT_8x8_LOAD_LEFT + PREDICT_8x8_LOAD_TOPLEFT + SRC(0,6)= F2(l5,l4,l3); + SRC(0,7)= F2(l6,l5,l4); + SRC(0,4)=SRC(1,6)= F2(l3,l2,l1); + SRC(0,5)=SRC(1,7)= F2(l4,l3,l2); + SRC(0,2)=SRC(1,4)=SRC(2,6)= F2(l1,l0,lt); + SRC(0,3)=SRC(1,5)=SRC(2,7)= F2(l2,l1,l0); + SRC(0,1)=SRC(1,3)=SRC(2,5)=SRC(3,7)= F2(l0,lt,t0); + SRC(0,0)=SRC(1,2)=SRC(2,4)=SRC(3,6)= F1(lt,t0); + SRC(1,1)=SRC(2,3)=SRC(3,5)=SRC(4,7)= F2(lt,t0,t1); + SRC(1,0)=SRC(2,2)=SRC(3,4)=SRC(4,6)= F1(t0,t1); + SRC(2,1)=SRC(3,3)=SRC(4,5)=SRC(5,7)= F2(t0,t1,t2); + SRC(2,0)=SRC(3,2)=SRC(4,4)=SRC(5,6)= F1(t1,t2); + SRC(3,1)=SRC(4,3)=SRC(5,5)=SRC(6,7)= F2(t1,t2,t3); + SRC(3,0)=SRC(4,2)=SRC(5,4)=SRC(6,6)= F1(t2,t3); + SRC(4,1)=SRC(5,3)=SRC(6,5)=SRC(7,7)= F2(t2,t3,t4); + SRC(4,0)=SRC(5,2)=SRC(6,4)=SRC(7,6)= F1(t3,t4); + SRC(5,1)=SRC(6,3)=SRC(7,5)= F2(t3,t4,t5); + SRC(5,0)=SRC(6,2)=SRC(7,4)= F1(t4,t5); + SRC(6,1)=SRC(7,3)= F2(t4,t5,t6); + SRC(6,0)=SRC(7,2)= F1(t5,t6); + SRC(7,1)= F2(t5,t6,t7); + SRC(7,0)= F1(t6,t7); +} +static void x264_predict_8x8_hd_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_TOP + PREDICT_8x8_LOAD_LEFT + PREDICT_8x8_LOAD_TOPLEFT + int p1 = pack_pixel_1to2(F1(l6,l7), F2(l5,l6,l7)); + int p2 = pack_pixel_1to2(F1(l5,l6), F2(l4,l5,l6)); + int p3 = pack_pixel_1to2(F1(l4,l5), F2(l3,l4,l5)); + int p4 = pack_pixel_1to2(F1(l3,l4), F2(l2,l3,l4)); + int p5 = pack_pixel_1to2(F1(l2,l3), F2(l1,l2,l3)); + int p6 = pack_pixel_1to2(F1(l1,l2), F2(l0,l1,l2)); + int p7 = pack_pixel_1to2(F1(l0,l1), F2(lt,l0,l1)); + int p8 = pack_pixel_1to2(F1(lt,l0), F2(l0,lt,t0)); + int p9 = pack_pixel_1to2(F2(t1,t0,lt), F2(t2,t1,t0)); + int p10 = pack_pixel_1to2(F2(t3,t2,t1), F2(t4,t3,t2)); + int p11 = pack_pixel_1to2(F2(t5,t4,t3), F2(t6,t5,t4)); + SRC_X4(0,7)= pack_pixel_2to4(p1,p2); + SRC_X4(0,6)= pack_pixel_2to4(p2,p3); + SRC_X4(4,7)=SRC_X4(0,5)= pack_pixel_2to4(p3,p4); + SRC_X4(4,6)=SRC_X4(0,4)= pack_pixel_2to4(p4,p5); + SRC_X4(4,5)=SRC_X4(0,3)= pack_pixel_2to4(p5,p6); + SRC_X4(4,4)=SRC_X4(0,2)= pack_pixel_2to4(p6,p7); + SRC_X4(4,3)=SRC_X4(0,1)= pack_pixel_2to4(p7,p8); + SRC_X4(4,2)=SRC_X4(0,0)= pack_pixel_2to4(p8,p9); + SRC_X4(4,1)= pack_pixel_2to4(p9,p10); + SRC_X4(4,0)= pack_pixel_2to4(p10,p11); +} +static void x264_predict_8x8_vl_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_TOP + PREDICT_8x8_LOAD_TOPRIGHT + SRC(0,0)= F1(t0,t1); + SRC(0,1)= F2(t0,t1,t2); + SRC(0,2)=SRC(1,0)= F1(t1,t2); + SRC(0,3)=SRC(1,1)= F2(t1,t2,t3); + SRC(0,4)=SRC(1,2)=SRC(2,0)= F1(t2,t3); + SRC(0,5)=SRC(1,3)=SRC(2,1)= F2(t2,t3,t4); + SRC(0,6)=SRC(1,4)=SRC(2,2)=SRC(3,0)= F1(t3,t4); + SRC(0,7)=SRC(1,5)=SRC(2,3)=SRC(3,1)= F2(t3,t4,t5); + SRC(1,6)=SRC(2,4)=SRC(3,2)=SRC(4,0)= F1(t4,t5); + SRC(1,7)=SRC(2,5)=SRC(3,3)=SRC(4,1)= F2(t4,t5,t6); + SRC(2,6)=SRC(3,4)=SRC(4,2)=SRC(5,0)= F1(t5,t6); + SRC(2,7)=SRC(3,5)=SRC(4,3)=SRC(5,1)= F2(t5,t6,t7); + SRC(3,6)=SRC(4,4)=SRC(5,2)=SRC(6,0)= F1(t6,t7); + SRC(3,7)=SRC(4,5)=SRC(5,3)=SRC(6,1)= F2(t6,t7,t8); + SRC(4,6)=SRC(5,4)=SRC(6,2)=SRC(7,0)= F1(t7,t8); + SRC(4,7)=SRC(5,5)=SRC(6,3)=SRC(7,1)= F2(t7,t8,t9); + SRC(5,6)=SRC(6,4)=SRC(7,2)= F1(t8,t9); + SRC(5,7)=SRC(6,5)=SRC(7,3)= F2(t8,t9,t10); + SRC(6,6)=SRC(7,4)= F1(t9,t10); + SRC(6,7)=SRC(7,5)= F2(t9,t10,t11); + SRC(7,6)= F1(t10,t11); + SRC(7,7)= F2(t10,t11,t12); +} +static void x264_predict_8x8_hu_c( pixel *src, pixel edge[36] ) +{ + PREDICT_8x8_LOAD_LEFT + int p1 = pack_pixel_1to2(F1(l0,l1), F2(l0,l1,l2)); + int p2 = pack_pixel_1to2(F1(l1,l2), F2(l1,l2,l3)); + int p3 = pack_pixel_1to2(F1(l2,l3), F2(l2,l3,l4)); + int p4 = pack_pixel_1to2(F1(l3,l4), F2(l3,l4,l5)); + int p5 = pack_pixel_1to2(F1(l4,l5), F2(l4,l5,l6)); + int p6 = pack_pixel_1to2(F1(l5,l6), F2(l5,l6,l7)); + int p7 = pack_pixel_1to2(F1(l6,l7), F2(l6,l7,l7)); + int p8 = pack_pixel_1to2(l7,l7); + SRC_X4(0,0)= pack_pixel_2to4(p1,p2); + SRC_X4(0,1)= pack_pixel_2to4(p2,p3); + SRC_X4(4,0)=SRC_X4(0,2)= pack_pixel_2to4(p3,p4); + SRC_X4(4,1)=SRC_X4(0,3)= pack_pixel_2to4(p4,p5); + SRC_X4(4,2)=SRC_X4(0,4)= pack_pixel_2to4(p5,p6); + SRC_X4(4,3)=SRC_X4(0,5)= pack_pixel_2to4(p6,p7); + SRC_X4(4,4)=SRC_X4(0,6)= pack_pixel_2to4(p7,p8); + SRC_X4(4,5)=SRC_X4(4,6)= SRC_X4(0,7) = SRC_X4(4,7) = pack_pixel_2to4(p8,p8); +} + +/**************************************************************************** + * Exported functions: + ****************************************************************************/ +void x264_predict_16x16_init( int cpu, x264_predict_t pf[7] ) +{ + pf[I_PRED_16x16_V ] = x264_predict_16x16_v_c; + pf[I_PRED_16x16_H ] = x264_predict_16x16_h_c; + pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_c; + pf[I_PRED_16x16_P ] = x264_predict_16x16_p_c; + pf[I_PRED_16x16_DC_LEFT]= x264_predict_16x16_dc_left_c; + pf[I_PRED_16x16_DC_TOP ]= x264_predict_16x16_dc_top_c; + pf[I_PRED_16x16_DC_128 ]= x264_predict_16x16_dc_128_c; + +#if HAVE_MMX + x264_predict_16x16_init_mmx( cpu, pf ); +#endif + +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + x264_predict_16x16_init_altivec( pf ); +#endif + +#if HAVE_ARMV6 + x264_predict_16x16_init_arm( cpu, pf ); +#endif + +#if ARCH_AARCH64 + x264_predict_16x16_init_aarch64( cpu, pf ); +#endif + +#if !HIGH_BIT_DEPTH +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + { + pf[I_PRED_16x16_V ] = x264_intra_predict_vert_16x16_msa; + pf[I_PRED_16x16_H ] = x264_intra_predict_hor_16x16_msa; + pf[I_PRED_16x16_DC] = x264_intra_predict_dc_16x16_msa; + pf[I_PRED_16x16_P ] = x264_intra_predict_plane_16x16_msa; + pf[I_PRED_16x16_DC_LEFT]= x264_intra_predict_dc_left_16x16_msa; + pf[I_PRED_16x16_DC_TOP ]= x264_intra_predict_dc_top_16x16_msa; + pf[I_PRED_16x16_DC_128 ]= x264_intra_predict_dc_128_16x16_msa; + } +#endif +#endif +} + +void x264_predict_8x8c_init( int cpu, x264_predict_t pf[7] ) +{ + pf[I_PRED_CHROMA_V ] = x264_predict_8x8c_v_c; + pf[I_PRED_CHROMA_H ] = x264_predict_8x8c_h_c; + pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_c; + pf[I_PRED_CHROMA_P ] = x264_predict_8x8c_p_c; + pf[I_PRED_CHROMA_DC_LEFT]= x264_predict_8x8c_dc_left_c; + pf[I_PRED_CHROMA_DC_TOP ]= x264_predict_8x8c_dc_top_c; + pf[I_PRED_CHROMA_DC_128 ]= x264_predict_8x8c_dc_128_c; + +#if HAVE_MMX + x264_predict_8x8c_init_mmx( cpu, pf ); +#endif + +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + x264_predict_8x8c_init_altivec( pf ); +#endif + +#if HAVE_ARMV6 + x264_predict_8x8c_init_arm( cpu, pf ); +#endif + +#if ARCH_AARCH64 + x264_predict_8x8c_init_aarch64( cpu, pf ); +#endif + +#if !HIGH_BIT_DEPTH +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + { + pf[I_PRED_CHROMA_P ] = x264_intra_predict_plane_8x8_msa; + } +#endif +#endif +} + +void x264_predict_8x16c_init( int cpu, x264_predict_t pf[7] ) +{ + pf[I_PRED_CHROMA_V ] = x264_predict_8x16c_v_c; + pf[I_PRED_CHROMA_H ] = x264_predict_8x16c_h_c; + pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_c; + pf[I_PRED_CHROMA_P ] = x264_predict_8x16c_p_c; + pf[I_PRED_CHROMA_DC_LEFT]= x264_predict_8x16c_dc_left_c; + pf[I_PRED_CHROMA_DC_TOP ]= x264_predict_8x16c_dc_top_c; + pf[I_PRED_CHROMA_DC_128 ]= x264_predict_8x16c_dc_128_c; + +#if HAVE_MMX + x264_predict_8x16c_init_mmx( cpu, pf ); +#endif + +#if HAVE_ARMV6 + x264_predict_8x16c_init_arm( cpu, pf ); +#endif + +#if ARCH_AARCH64 + x264_predict_8x16c_init_aarch64( cpu, pf ); +#endif +} + +void x264_predict_8x8_init( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter ) +{ + pf[I_PRED_8x8_V] = x264_predict_8x8_v_c; + pf[I_PRED_8x8_H] = x264_predict_8x8_h_c; + pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_c; + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_c; + pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_c; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_c; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_c; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_c; + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_c; + pf[I_PRED_8x8_DC_LEFT]= x264_predict_8x8_dc_left_c; + pf[I_PRED_8x8_DC_TOP] = x264_predict_8x8_dc_top_c; + pf[I_PRED_8x8_DC_128] = x264_predict_8x8_dc_128_c; + *predict_filter = x264_predict_8x8_filter_c; + +#if HAVE_MMX + x264_predict_8x8_init_mmx( cpu, pf, predict_filter ); +#endif + +#if HAVE_ARMV6 + x264_predict_8x8_init_arm( cpu, pf, predict_filter ); +#endif + +#if ARCH_AARCH64 + x264_predict_8x8_init_aarch64( cpu, pf, predict_filter ); +#endif + +#if !HIGH_BIT_DEPTH +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + { + pf[I_PRED_8x8_DDL] = x264_intra_predict_ddl_8x8_msa; + } +#endif +#endif +} + +void x264_predict_4x4_init( int cpu, x264_predict_t pf[12] ) +{ + pf[I_PRED_4x4_V] = x264_predict_4x4_v_c; + pf[I_PRED_4x4_H] = x264_predict_4x4_h_c; + pf[I_PRED_4x4_DC] = x264_predict_4x4_dc_c; + pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_c; + pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_c; + pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_c; + pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_c; + pf[I_PRED_4x4_VL] = x264_predict_4x4_vl_c; + pf[I_PRED_4x4_HU] = x264_predict_4x4_hu_c; + pf[I_PRED_4x4_DC_LEFT]= x264_predict_4x4_dc_left_c; + pf[I_PRED_4x4_DC_TOP] = x264_predict_4x4_dc_top_c; + pf[I_PRED_4x4_DC_128] = x264_predict_4x4_dc_128_c; + +#if HAVE_MMX + x264_predict_4x4_init_mmx( cpu, pf ); +#endif + +#if HAVE_ARMV6 + x264_predict_4x4_init_arm( cpu, pf ); +#endif + +#if ARCH_AARCH64 + x264_predict_4x4_init_aarch64( cpu, pf ); +#endif +} + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/predict.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/predict.h new file mode 100644 index 00000000..9ec94763 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/predict.h @@ -0,0 +1,138 @@ +/***************************************************************************** + * predict.h: intra prediction + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_PREDICT_H +#define X264_PREDICT_H + +typedef void (*x264_predict_t)( pixel *src ); +typedef void (*x264_predict8x8_t)( pixel *src, pixel edge[36] ); +typedef void (*x264_predict_8x8_filter_t)( pixel *src, pixel edge[36], int i_neighbor, int i_filters ); + +enum intra_chroma_pred_e +{ + I_PRED_CHROMA_DC = 0, + I_PRED_CHROMA_H = 1, + I_PRED_CHROMA_V = 2, + I_PRED_CHROMA_P = 3, + + I_PRED_CHROMA_DC_LEFT = 4, + I_PRED_CHROMA_DC_TOP = 5, + I_PRED_CHROMA_DC_128 = 6 +}; +static const uint8_t x264_mb_chroma_pred_mode_fix[7] = +{ + I_PRED_CHROMA_DC, I_PRED_CHROMA_H, I_PRED_CHROMA_V, I_PRED_CHROMA_P, + I_PRED_CHROMA_DC, I_PRED_CHROMA_DC,I_PRED_CHROMA_DC +}; + +enum intra16x16_pred_e +{ + I_PRED_16x16_V = 0, + I_PRED_16x16_H = 1, + I_PRED_16x16_DC = 2, + I_PRED_16x16_P = 3, + + I_PRED_16x16_DC_LEFT = 4, + I_PRED_16x16_DC_TOP = 5, + I_PRED_16x16_DC_128 = 6, +}; +static const uint8_t x264_mb_pred_mode16x16_fix[7] = +{ + I_PRED_16x16_V, I_PRED_16x16_H, I_PRED_16x16_DC, I_PRED_16x16_P, + I_PRED_16x16_DC,I_PRED_16x16_DC,I_PRED_16x16_DC +}; + +enum intra4x4_pred_e +{ + I_PRED_4x4_V = 0, + I_PRED_4x4_H = 1, + I_PRED_4x4_DC = 2, + I_PRED_4x4_DDL= 3, + I_PRED_4x4_DDR= 4, + I_PRED_4x4_VR = 5, + I_PRED_4x4_HD = 6, + I_PRED_4x4_VL = 7, + I_PRED_4x4_HU = 8, + + I_PRED_4x4_DC_LEFT = 9, + I_PRED_4x4_DC_TOP = 10, + I_PRED_4x4_DC_128 = 11, +}; +static const int8_t x264_mb_pred_mode4x4_fix[13] = +{ + -1, + I_PRED_4x4_V, I_PRED_4x4_H, I_PRED_4x4_DC, + I_PRED_4x4_DDL, I_PRED_4x4_DDR, I_PRED_4x4_VR, + I_PRED_4x4_HD, I_PRED_4x4_VL, I_PRED_4x4_HU, + I_PRED_4x4_DC, I_PRED_4x4_DC, I_PRED_4x4_DC +}; +#define x264_mb_pred_mode4x4_fix(t) x264_mb_pred_mode4x4_fix[(t)+1] + +/* must use the same numbering as intra4x4_pred_e */ +enum intra8x8_pred_e +{ + I_PRED_8x8_V = 0, + I_PRED_8x8_H = 1, + I_PRED_8x8_DC = 2, + I_PRED_8x8_DDL= 3, + I_PRED_8x8_DDR= 4, + I_PRED_8x8_VR = 5, + I_PRED_8x8_HD = 6, + I_PRED_8x8_VL = 7, + I_PRED_8x8_HU = 8, + + I_PRED_8x8_DC_LEFT = 9, + I_PRED_8x8_DC_TOP = 10, + I_PRED_8x8_DC_128 = 11, +}; + +void x264_predict_8x8_dc_c ( pixel *src, pixel edge[36] ); +void x264_predict_8x8_h_c ( pixel *src, pixel edge[36] ); +void x264_predict_8x8_v_c ( pixel *src, pixel edge[36] ); +void x264_predict_4x4_dc_c ( pixel *src ); +void x264_predict_4x4_h_c ( pixel *src ); +void x264_predict_4x4_v_c ( pixel *src ); +void x264_predict_16x16_dc_c( pixel *src ); +void x264_predict_16x16_h_c ( pixel *src ); +void x264_predict_16x16_v_c ( pixel *src ); +void x264_predict_16x16_p_c ( pixel *src ); +void x264_predict_8x8c_dc_c ( pixel *src ); +void x264_predict_8x8c_h_c ( pixel *src ); +void x264_predict_8x8c_v_c ( pixel *src ); +void x264_predict_8x8c_p_c ( pixel *src ); +void x264_predict_8x16c_dc_c( pixel *src ); +void x264_predict_8x16c_h_c ( pixel *src ); +void x264_predict_8x16c_v_c ( pixel *src ); +void x264_predict_8x16c_p_c ( pixel *src ); + +void x264_predict_16x16_init ( int cpu, x264_predict_t pf[7] ); +void x264_predict_8x8c_init ( int cpu, x264_predict_t pf[7] ); +void x264_predict_8x16c_init ( int cpu, x264_predict_t pf[7] ); +void x264_predict_4x4_init ( int cpu, x264_predict_t pf[12] ); +void x264_predict_8x8_init ( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter ); + + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/quant.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/quant.c new file mode 100644 index 00000000..ae962226 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/quant.c @@ -0,0 +1,830 @@ +/***************************************************************************** + * quant.c: quantization and level-run + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: Loren Merritt + * Fiona Glaser + * Christian Heine + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#if HAVE_MMX +#include "x86/quant.h" +#endif +#if ARCH_PPC +# include "ppc/quant.h" +#endif +#if ARCH_ARM +# include "arm/quant.h" +#endif +#if ARCH_AARCH64 +# include "aarch64/quant.h" +#endif +#if ARCH_MIPS +# include "mips/quant.h" +#endif + +#define QUANT_ONE( coef, mf, f ) \ +{ \ + if( (coef) > 0 ) \ + (coef) = (f + (coef)) * (mf) >> 16; \ + else \ + (coef) = - ((f - (coef)) * (mf) >> 16); \ + nz |= (coef); \ +} + +static int quant_8x8( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ) +{ + int nz = 0; + for( int i = 0; i < 64; i++ ) + QUANT_ONE( dct[i], mf[i], bias[i] ); + return !!nz; +} + +static int quant_4x4( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ) +{ + int nz = 0; + for( int i = 0; i < 16; i++ ) + QUANT_ONE( dct[i], mf[i], bias[i] ); + return !!nz; +} + +static int quant_4x4x4( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ) +{ + int nza = 0; + for( int j = 0; j < 4; j++ ) + { + int nz = 0; + for( int i = 0; i < 16; i++ ) + QUANT_ONE( dct[j][i], mf[i], bias[i] ); + nza |= (!!nz)<> (-i_qbits) + +static void dequant_4x4( dctcoef dct[16], int dequant_mf[6][16], int i_qp ) +{ + const int i_mf = i_qp%6; + const int i_qbits = i_qp/6 - 4; + + if( i_qbits >= 0 ) + { + for( int i = 0; i < 16; i++ ) + DEQUANT_SHL( i ); + } + else + { + const int f = 1 << (-i_qbits-1); + for( int i = 0; i < 16; i++ ) + DEQUANT_SHR( i ); + } +} + +static void dequant_8x8( dctcoef dct[64], int dequant_mf[6][64], int i_qp ) +{ + const int i_mf = i_qp%6; + const int i_qbits = i_qp/6 - 6; + + if( i_qbits >= 0 ) + { + for( int i = 0; i < 64; i++ ) + DEQUANT_SHL( i ); + } + else + { + const int f = 1 << (-i_qbits-1); + for( int i = 0; i < 64; i++ ) + DEQUANT_SHR( i ); + } +} + +static void dequant_4x4_dc( dctcoef dct[16], int dequant_mf[6][16], int i_qp ) +{ + const int i_qbits = i_qp/6 - 6; + + if( i_qbits >= 0 ) + { + const int i_dmf = dequant_mf[i_qp%6][0] << i_qbits; + for( int i = 0; i < 16; i++ ) + dct[i] *= i_dmf; + } + else + { + const int i_dmf = dequant_mf[i_qp%6][0]; + const int f = 1 << (-i_qbits-1); + for( int i = 0; i < 16; i++ ) + dct[i] = ( dct[i] * i_dmf + f ) >> (-i_qbits); + } +} + +#define IDCT_DEQUANT_2X4_START \ + int a0 = dct[0] + dct[1]; \ + int a1 = dct[2] + dct[3]; \ + int a2 = dct[4] + dct[5]; \ + int a3 = dct[6] + dct[7]; \ + int a4 = dct[0] - dct[1]; \ + int a5 = dct[2] - dct[3]; \ + int a6 = dct[4] - dct[5]; \ + int a7 = dct[6] - dct[7]; \ + int b0 = a0 + a1; \ + int b1 = a2 + a3; \ + int b2 = a4 + a5; \ + int b3 = a6 + a7; \ + int b4 = a0 - a1; \ + int b5 = a2 - a3; \ + int b6 = a4 - a5; \ + int b7 = a6 - a7; + +static void idct_dequant_2x4_dc( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp ) +{ + IDCT_DEQUANT_2X4_START + int dmf = dequant_mf[i_qp%6][0] << i_qp/6; + dct4x4[0][0] = ((b0 + b1) * dmf + 32) >> 6; + dct4x4[1][0] = ((b2 + b3) * dmf + 32) >> 6; + dct4x4[2][0] = ((b0 - b1) * dmf + 32) >> 6; + dct4x4[3][0] = ((b2 - b3) * dmf + 32) >> 6; + dct4x4[4][0] = ((b4 - b5) * dmf + 32) >> 6; + dct4x4[5][0] = ((b6 - b7) * dmf + 32) >> 6; + dct4x4[6][0] = ((b4 + b5) * dmf + 32) >> 6; + dct4x4[7][0] = ((b6 + b7) * dmf + 32) >> 6; +} + +static void idct_dequant_2x4_dconly( dctcoef dct[8], int dequant_mf[6][16], int i_qp ) +{ + IDCT_DEQUANT_2X4_START + int dmf = dequant_mf[i_qp%6][0] << i_qp/6; + dct[0] = ((b0 + b1) * dmf + 32) >> 6; + dct[1] = ((b2 + b3) * dmf + 32) >> 6; + dct[2] = ((b0 - b1) * dmf + 32) >> 6; + dct[3] = ((b2 - b3) * dmf + 32) >> 6; + dct[4] = ((b4 - b5) * dmf + 32) >> 6; + dct[5] = ((b6 - b7) * dmf + 32) >> 6; + dct[6] = ((b4 + b5) * dmf + 32) >> 6; + dct[7] = ((b6 + b7) * dmf + 32) >> 6; +} + +static ALWAYS_INLINE void optimize_chroma_idct_dequant_2x4( dctcoef out[8], dctcoef dct[8], int dmf ) +{ + IDCT_DEQUANT_2X4_START + out[0] = ((b0 + b1) * dmf + 2080) >> 6; /* 2080 = 32 + (32<<6) */ + out[1] = ((b2 + b3) * dmf + 2080) >> 6; + out[2] = ((b0 - b1) * dmf + 2080) >> 6; + out[3] = ((b2 - b3) * dmf + 2080) >> 6; + out[4] = ((b4 - b5) * dmf + 2080) >> 6; + out[5] = ((b6 - b7) * dmf + 2080) >> 6; + out[6] = ((b4 + b5) * dmf + 2080) >> 6; + out[7] = ((b6 + b7) * dmf + 2080) >> 6; +} +#undef IDCT_DEQUANT_2X4_START + +static ALWAYS_INLINE void optimize_chroma_idct_dequant_2x2( dctcoef out[4], dctcoef dct[4], int dmf ) +{ + int d0 = dct[0] + dct[1]; + int d1 = dct[2] + dct[3]; + int d2 = dct[0] - dct[1]; + int d3 = dct[2] - dct[3]; + out[0] = ((d0 + d1) * dmf >> 5) + 32; + out[1] = ((d0 - d1) * dmf >> 5) + 32; + out[2] = ((d2 + d3) * dmf >> 5) + 32; + out[3] = ((d2 - d3) * dmf >> 5) + 32; +} + +static ALWAYS_INLINE int optimize_chroma_round( dctcoef *ref, dctcoef *dct, int dequant_mf, int chroma422 ) +{ + dctcoef out[8]; + + if( chroma422 ) + optimize_chroma_idct_dequant_2x4( out, dct, dequant_mf ); + else + optimize_chroma_idct_dequant_2x2( out, dct, dequant_mf ); + + int sum = 0; + for( int i = 0; i < (chroma422?8:4); i++ ) + sum |= ref[i] ^ out[i]; + return sum >> 6; +} + +static ALWAYS_INLINE int optimize_chroma_dc_internal( dctcoef *dct, int dequant_mf, int chroma422 ) +{ + /* dequant_mf = h->dequant4_mf[CQM_4IC + b_inter][i_qp%6][0] << i_qp/6, max 32*64 */ + dctcoef dct_orig[8]; + int coeff, nz; + + if( chroma422 ) + optimize_chroma_idct_dequant_2x4( dct_orig, dct, dequant_mf ); + else + optimize_chroma_idct_dequant_2x2( dct_orig, dct, dequant_mf ); + + /* If the DC coefficients already round to zero, terminate early. */ + int sum = 0; + for( int i = 0; i < (chroma422?8:4); i++ ) + sum |= dct_orig[i]; + if( !(sum >> 6) ) + return 0; + + /* Start with the highest frequency coefficient... is this the best option? */ + for( nz = 0, coeff = (chroma422?7:3); coeff >= 0; coeff-- ) + { + int level = dct[coeff]; + int sign = level>>31 | 1; /* dct[coeff] < 0 ? -1 : 1 */ + + while( level ) + { + dct[coeff] = level - sign; + if( optimize_chroma_round( dct_orig, dct, dequant_mf, chroma422 ) ) + { + nz = 1; + dct[coeff] = level; + break; + } + level -= sign; + } + } + + return nz; +} + +static int optimize_chroma_2x2_dc( dctcoef dct[4], int dequant_mf ) +{ + return optimize_chroma_dc_internal( dct, dequant_mf, 0 ); +} + +static int optimize_chroma_2x4_dc( dctcoef dct[8], int dequant_mf ) +{ + return optimize_chroma_dc_internal( dct, dequant_mf, 1 ); +} + +static void x264_denoise_dct( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ) +{ + for( int i = 0; i < size; i++ ) + { + int level = dct[i]; + int sign = level>>31; + level = (level+sign)^sign; + sum[i] += level; + level -= offset[i]; + dct[i] = level<0 ? 0 : (level^sign)-sign; + } +} + +/* (ref: JVT-B118) + * x264_mb_decimate_score: given dct coeffs it returns a score to see if we could empty this dct coeffs + * to 0 (low score means set it to null) + * Used in inter macroblock (luma and chroma) + * luma: for a 8x8 block: if score < 4 -> null + * for the complete mb: if score < 6 -> null + * chroma: for the complete mb: if score < 7 -> null + */ + +const uint8_t x264_decimate_table4[16] = +{ + 3,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0 +}; +const uint8_t x264_decimate_table8[64] = +{ + 3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1, + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +static int ALWAYS_INLINE x264_decimate_score_internal( dctcoef *dct, int i_max ) +{ + const uint8_t *ds_table = (i_max == 64) ? x264_decimate_table8 : x264_decimate_table4; + int i_score = 0; + int idx = i_max - 1; + + while( idx >= 0 && dct[idx] == 0 ) + idx--; + while( idx >= 0 ) + { + int i_run; + + if( (unsigned)(dct[idx--] + 1) > 2 ) + return 9; + + i_run = 0; + while( idx >= 0 && dct[idx] == 0 ) + { + idx--; + i_run++; + } + i_score += ds_table[i_run]; + } + + return i_score; +} + +static int x264_decimate_score15( dctcoef *dct ) +{ + return x264_decimate_score_internal( dct+1, 15 ); +} +static int x264_decimate_score16( dctcoef *dct ) +{ + return x264_decimate_score_internal( dct, 16 ); +} +static int x264_decimate_score64( dctcoef *dct ) +{ + return x264_decimate_score_internal( dct, 64 ); +} + +#define last(num)\ +static int x264_coeff_last##num( dctcoef *l )\ +{\ + int i_last = num-1;\ + while( i_last >= 0 && l[i_last] == 0 )\ + i_last--;\ + return i_last;\ +} + +last(4) +last(8) +last(15) +last(16) +last(64) + +#define level_run(num)\ +static int x264_coeff_level_run##num( dctcoef *dct, x264_run_level_t *runlevel )\ +{\ + int i_last = runlevel->last = x264_coeff_last##num(dct);\ + int i_total = 0;\ + int mask = 0;\ + do\ + {\ + runlevel->level[i_total++] = dct[i_last];\ + mask |= 1 << (i_last);\ + while( --i_last >= 0 && dct[i_last] == 0 );\ + } while( i_last >= 0 );\ + runlevel->mask = mask;\ + return i_total;\ +} + +level_run(4) +level_run(8) +level_run(15) +level_run(16) + +#if ARCH_X86_64 +#define INIT_TRELLIS(cpu)\ + pf->trellis_cabac_4x4 = x264_trellis_cabac_4x4_##cpu;\ + pf->trellis_cabac_8x8 = x264_trellis_cabac_8x8_##cpu;\ + pf->trellis_cabac_4x4_psy = x264_trellis_cabac_4x4_psy_##cpu;\ + pf->trellis_cabac_8x8_psy = x264_trellis_cabac_8x8_psy_##cpu;\ + pf->trellis_cabac_dc = x264_trellis_cabac_dc_##cpu;\ + pf->trellis_cabac_chroma_422_dc = x264_trellis_cabac_chroma_422_dc_##cpu; +#else +#define INIT_TRELLIS(...) +#endif + +void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) +{ + pf->quant_8x8 = quant_8x8; + pf->quant_4x4 = quant_4x4; + pf->quant_4x4x4 = quant_4x4x4; + pf->quant_4x4_dc = quant_4x4_dc; + pf->quant_2x2_dc = quant_2x2_dc; + + pf->dequant_4x4 = dequant_4x4; + pf->dequant_4x4_dc = dequant_4x4_dc; + pf->dequant_8x8 = dequant_8x8; + + pf->idct_dequant_2x4_dc = idct_dequant_2x4_dc; + pf->idct_dequant_2x4_dconly = idct_dequant_2x4_dconly; + + pf->optimize_chroma_2x2_dc = optimize_chroma_2x2_dc; + pf->optimize_chroma_2x4_dc = optimize_chroma_2x4_dc; + + pf->denoise_dct = x264_denoise_dct; + pf->decimate_score15 = x264_decimate_score15; + pf->decimate_score16 = x264_decimate_score16; + pf->decimate_score64 = x264_decimate_score64; + + pf->coeff_last4 = x264_coeff_last4; + pf->coeff_last8 = x264_coeff_last8; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15; + pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16; + pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64; + pf->coeff_level_run4 = x264_coeff_level_run4; + pf->coeff_level_run8 = x264_coeff_level_run8; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15; + pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16; + +#if HIGH_BIT_DEPTH +#if HAVE_MMX + INIT_TRELLIS( sse2 ); + if( cpu&X264_CPU_MMX2 ) + { +#if ARCH_X86 + pf->denoise_dct = x264_denoise_dct_mmx; + pf->coeff_last8 = x264_coeff_last8_mmx2; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_mmx2; + pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16_mmx2; + pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64_mmx2; + pf->coeff_level_run8 = x264_coeff_level_run8_mmx2; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_mmx2; + pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_mmx2; +#endif + pf->coeff_last4 = x264_coeff_last4_mmx2; + pf->coeff_level_run4 = x264_coeff_level_run4_mmx2; + } + if( cpu&X264_CPU_SSE2 ) + { + pf->quant_4x4 = x264_quant_4x4_sse2; + pf->quant_4x4x4 = x264_quant_4x4x4_sse2; + pf->quant_8x8 = x264_quant_8x8_sse2; + pf->quant_2x2_dc = x264_quant_2x2_dc_sse2; + pf->quant_4x4_dc = x264_quant_4x4_dc_sse2; + pf->dequant_4x4 = x264_dequant_4x4_sse2; + pf->dequant_8x8 = x264_dequant_8x8_sse2; + pf->dequant_4x4_dc = x264_dequant_4x4dc_sse2; + pf->idct_dequant_2x4_dc = x264_idct_dequant_2x4_dc_sse2; + pf->idct_dequant_2x4_dconly = x264_idct_dequant_2x4_dconly_sse2; + pf->denoise_dct = x264_denoise_dct_sse2; + pf->decimate_score15 = x264_decimate_score15_sse2; + pf->decimate_score16 = x264_decimate_score16_sse2; + pf->decimate_score64 = x264_decimate_score64_sse2; + pf->coeff_last8 = x264_coeff_last8_sse2; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2; + pf->coeff_level_run8 = x264_coeff_level_run8_sse2; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2; + } + if( cpu&X264_CPU_LZCNT ) + { + pf->coeff_last4 = x264_coeff_last4_lzcnt; + pf->coeff_last8 = x264_coeff_last8_lzcnt; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_lzcnt; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_lzcnt; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_lzcnt; + pf->coeff_level_run4 = x264_coeff_level_run4_lzcnt; + pf->coeff_level_run8 = x264_coeff_level_run8_lzcnt; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_lzcnt; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_lzcnt; + } + if( cpu&X264_CPU_SSSE3 ) + { + pf->quant_4x4 = x264_quant_4x4_ssse3; + pf->quant_4x4x4 = x264_quant_4x4x4_ssse3; + pf->quant_8x8 = x264_quant_8x8_ssse3; + pf->quant_2x2_dc = x264_quant_2x2_dc_ssse3; + pf->quant_4x4_dc = x264_quant_4x4_dc_ssse3; + pf->denoise_dct = x264_denoise_dct_ssse3; + pf->decimate_score15 = x264_decimate_score15_ssse3; + pf->decimate_score16 = x264_decimate_score16_ssse3; + pf->decimate_score64 = x264_decimate_score64_ssse3; + INIT_TRELLIS( ssse3 ); + } + if( cpu&X264_CPU_SSE4 ) + { + pf->quant_2x2_dc = x264_quant_2x2_dc_sse4; + pf->quant_4x4_dc = x264_quant_4x4_dc_sse4; + pf->quant_4x4 = x264_quant_4x4_sse4; + pf->quant_4x4x4 = x264_quant_4x4x4_sse4; + pf->quant_8x8 = x264_quant_8x8_sse4; + } + if( cpu&X264_CPU_AVX ) + { + pf->idct_dequant_2x4_dc = x264_idct_dequant_2x4_dc_avx; + pf->idct_dequant_2x4_dconly = x264_idct_dequant_2x4_dconly_avx; + pf->denoise_dct = x264_denoise_dct_avx; + } + if( cpu&X264_CPU_XOP ) + { + pf->dequant_4x4_dc = x264_dequant_4x4dc_xop; + if( h->param.i_cqm_preset != X264_CQM_FLAT ) + { + pf->dequant_4x4 = x264_dequant_4x4_xop; + pf->dequant_8x8 = x264_dequant_8x8_xop; + } + } + if( cpu&X264_CPU_AVX2 ) + { + pf->quant_4x4 = x264_quant_4x4_avx2; + pf->quant_4x4_dc = x264_quant_4x4_dc_avx2; + pf->quant_8x8 = x264_quant_8x8_avx2; + pf->quant_4x4x4 = x264_quant_4x4x4_avx2; + pf->dequant_4x4 = x264_dequant_4x4_avx2; + pf->dequant_8x8 = x264_dequant_8x8_avx2; + pf->dequant_4x4_dc = x264_dequant_4x4dc_avx2; + pf->denoise_dct = x264_denoise_dct_avx2; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2; + } + if( cpu&X264_CPU_AVX512 ) + { + pf->dequant_4x4 = x264_dequant_4x4_avx512; + pf->dequant_8x8 = x264_dequant_8x8_avx512; + pf->decimate_score15 = x264_decimate_score15_avx512; + pf->decimate_score16 = x264_decimate_score16_avx512; + pf->decimate_score64 = x264_decimate_score64_avx512; + pf->coeff_last4 = x264_coeff_last4_avx512; + pf->coeff_last8 = x264_coeff_last8_avx512; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_avx512; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_avx512; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx512; + } +#endif // HAVE_MMX +#else // !HIGH_BIT_DEPTH +#if HAVE_MMX + INIT_TRELLIS( sse2 ); + if( cpu&X264_CPU_MMX ) + { +#if ARCH_X86 + pf->dequant_4x4 = x264_dequant_4x4_mmx; + pf->dequant_4x4_dc = x264_dequant_4x4dc_mmx2; + pf->dequant_8x8 = x264_dequant_8x8_mmx; + if( h->param.i_cqm_preset == X264_CQM_FLAT ) + { + pf->dequant_4x4 = x264_dequant_4x4_flat16_mmx; + pf->dequant_8x8 = x264_dequant_8x8_flat16_mmx; + } + pf->denoise_dct = x264_denoise_dct_mmx; +#endif + } + + if( cpu&X264_CPU_MMX2 ) + { + pf->quant_2x2_dc = x264_quant_2x2_dc_mmx2; +#if ARCH_X86 + pf->quant_4x4 = x264_quant_4x4_mmx2; + pf->quant_8x8 = x264_quant_8x8_mmx2; + pf->quant_4x4_dc = x264_quant_4x4_dc_mmx2; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_mmx2; + pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16_mmx2; + pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64_mmx2; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_mmx2; + pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_mmx2; +#endif + pf->coeff_last4 = x264_coeff_last4_mmx2; + pf->coeff_last8 = x264_coeff_last8_mmx2; + pf->coeff_level_run4 = x264_coeff_level_run4_mmx2; + pf->coeff_level_run8 = x264_coeff_level_run8_mmx2; + } + + if( cpu&X264_CPU_SSE2 ) + { + pf->quant_4x4_dc = x264_quant_4x4_dc_sse2; + pf->quant_4x4 = x264_quant_4x4_sse2; + pf->quant_4x4x4 = x264_quant_4x4x4_sse2; + pf->quant_8x8 = x264_quant_8x8_sse2; + pf->dequant_4x4 = x264_dequant_4x4_sse2; + pf->dequant_4x4_dc = x264_dequant_4x4dc_sse2; + pf->dequant_8x8 = x264_dequant_8x8_sse2; + if( h->param.i_cqm_preset == X264_CQM_FLAT ) + { + pf->dequant_4x4 = x264_dequant_4x4_flat16_sse2; + pf->dequant_8x8 = x264_dequant_8x8_flat16_sse2; + } + pf->idct_dequant_2x4_dc = x264_idct_dequant_2x4_dc_sse2; + pf->idct_dequant_2x4_dconly = x264_idct_dequant_2x4_dconly_sse2; + pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_sse2; + pf->denoise_dct = x264_denoise_dct_sse2; + pf->decimate_score15 = x264_decimate_score15_sse2; + pf->decimate_score16 = x264_decimate_score16_sse2; + pf->decimate_score64 = x264_decimate_score64_sse2; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2; + } + + if( cpu&X264_CPU_LZCNT ) + { + pf->coeff_last4 = x264_coeff_last4_lzcnt; + pf->coeff_last8 = x264_coeff_last8_lzcnt; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_lzcnt; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_lzcnt; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_lzcnt; + pf->coeff_level_run4 = x264_coeff_level_run4_lzcnt; + pf->coeff_level_run8 = x264_coeff_level_run8_lzcnt; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_lzcnt; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_lzcnt; + } + + if( cpu&X264_CPU_SSSE3 ) + { + pf->quant_2x2_dc = x264_quant_2x2_dc_ssse3; + pf->quant_4x4_dc = x264_quant_4x4_dc_ssse3; + pf->quant_4x4 = x264_quant_4x4_ssse3; + pf->quant_4x4x4 = x264_quant_4x4x4_ssse3; + pf->quant_8x8 = x264_quant_8x8_ssse3; + pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_ssse3; + pf->denoise_dct = x264_denoise_dct_ssse3; + pf->decimate_score15 = x264_decimate_score15_ssse3; + pf->decimate_score16 = x264_decimate_score16_ssse3; + pf->decimate_score64 = x264_decimate_score64_ssse3; + INIT_TRELLIS( ssse3 ); +#if ARCH_X86 || !defined( __MACH__ ) + pf->coeff_level_run4 = x264_coeff_level_run4_ssse3; + pf->coeff_level_run8 = x264_coeff_level_run8_ssse3; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_ssse3; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_ssse3; + if( cpu&X264_CPU_LZCNT ) + { + pf->coeff_level_run4 = x264_coeff_level_run4_ssse3_lzcnt; + pf->coeff_level_run8 = x264_coeff_level_run8_ssse3_lzcnt; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_ssse3_lzcnt; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_ssse3_lzcnt; + } +#endif + } + + if( cpu&X264_CPU_SSE4 ) + { + pf->quant_4x4_dc = x264_quant_4x4_dc_sse4; + pf->quant_4x4 = x264_quant_4x4_sse4; + pf->quant_8x8 = x264_quant_8x8_sse4; + pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_sse4; + } + + if( cpu&X264_CPU_AVX ) + { + pf->dequant_4x4_dc = x264_dequant_4x4dc_avx; + if( h->param.i_cqm_preset != X264_CQM_FLAT ) + { + pf->dequant_4x4 = x264_dequant_4x4_avx; + pf->dequant_8x8 = x264_dequant_8x8_avx; + } + pf->idct_dequant_2x4_dc = x264_idct_dequant_2x4_dc_avx; + pf->idct_dequant_2x4_dconly = x264_idct_dequant_2x4_dconly_avx; + pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_avx; + pf->denoise_dct = x264_denoise_dct_avx; + } + + if( cpu&X264_CPU_XOP ) + { + if( h->param.i_cqm_preset != X264_CQM_FLAT ) + { + pf->dequant_4x4 = x264_dequant_4x4_xop; + pf->dequant_8x8 = x264_dequant_8x8_xop; + } + } + + if( cpu&X264_CPU_AVX2 ) + { + pf->quant_4x4 = x264_quant_4x4_avx2; + pf->quant_4x4_dc = x264_quant_4x4_dc_avx2; + pf->quant_8x8 = x264_quant_8x8_avx2; + pf->quant_4x4x4 = x264_quant_4x4x4_avx2; + pf->dequant_4x4 = x264_dequant_4x4_avx2; + pf->dequant_8x8 = x264_dequant_8x8_avx2; + pf->dequant_4x4_dc = x264_dequant_4x4dc_avx2; + if( h->param.i_cqm_preset == X264_CQM_FLAT ) + { + pf->dequant_4x4 = x264_dequant_4x4_flat16_avx2; + pf->dequant_8x8 = x264_dequant_8x8_flat16_avx2; + } + pf->decimate_score64 = x264_decimate_score64_avx2; + pf->denoise_dct = x264_denoise_dct_avx2; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2; +#if ARCH_X86 || !defined( __MACH__ ) + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_avx2; + pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_avx2; +#endif + } + if( cpu&X264_CPU_AVX512 ) + { + if( h->param.i_cqm_preset == X264_CQM_FLAT ) + pf->dequant_8x8 = x264_dequant_8x8_flat16_avx512; + else + { + pf->dequant_4x4 = x264_dequant_4x4_avx512; + pf->dequant_8x8 = x264_dequant_8x8_avx512; + } + pf->decimate_score15 = x264_decimate_score15_avx512; + pf->decimate_score16 = x264_decimate_score16_avx512; + pf->decimate_score64 = x264_decimate_score64_avx512; + pf->coeff_last8 = x264_coeff_last8_avx512; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_avx512; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_avx512; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx512; + } +#endif // HAVE_MMX + +#if HAVE_ALTIVEC + if( cpu&X264_CPU_ALTIVEC ) + { + pf->quant_2x2_dc = x264_quant_2x2_dc_altivec; + pf->quant_4x4_dc = x264_quant_4x4_dc_altivec; + pf->quant_4x4 = x264_quant_4x4_altivec; + pf->quant_8x8 = x264_quant_8x8_altivec; + + pf->dequant_4x4 = x264_dequant_4x4_altivec; + pf->dequant_8x8 = x264_dequant_8x8_altivec; + } +#endif + +#if HAVE_ARMV6 + if( cpu&X264_CPU_ARMV6 ) + { + pf->coeff_last4 = x264_coeff_last4_arm; + pf->coeff_last8 = x264_coeff_last8_arm; + } +#endif +#if HAVE_ARMV6 || ARCH_AARCH64 + if( cpu&X264_CPU_NEON ) + { + pf->quant_2x2_dc = x264_quant_2x2_dc_neon; + pf->quant_4x4 = x264_quant_4x4_neon; + pf->quant_4x4_dc = x264_quant_4x4_dc_neon; + pf->quant_4x4x4 = x264_quant_4x4x4_neon; + pf->quant_8x8 = x264_quant_8x8_neon; + pf->dequant_4x4 = x264_dequant_4x4_neon; + pf->dequant_4x4_dc = x264_dequant_4x4_dc_neon; + pf->dequant_8x8 = x264_dequant_8x8_neon; + pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_neon; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_neon; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_neon; + pf->denoise_dct = x264_denoise_dct_neon; + pf->decimate_score15 = x264_decimate_score15_neon; + pf->decimate_score16 = x264_decimate_score16_neon; + pf->decimate_score64 = x264_decimate_score64_neon; + } +#endif +#if ARCH_AARCH64 + if( cpu&X264_CPU_ARMV8 ) + { + pf->coeff_last4 = x264_coeff_last4_aarch64; + pf->coeff_last8 = x264_coeff_last8_aarch64; + pf->coeff_level_run4 = x264_coeff_level_run4_aarch64; + } + if( cpu&X264_CPU_NEON ) + { + pf->coeff_level_run8 = x264_coeff_level_run8_neon; + pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_neon; + pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_neon; + } +#endif + +#if HAVE_MSA + if( cpu&X264_CPU_MSA ) + { + pf->quant_4x4 = x264_quant_4x4_msa; + pf->quant_4x4_dc = x264_quant_4x4_dc_msa; + pf->quant_4x4x4 = x264_quant_4x4x4_msa; + pf->quant_8x8 = x264_quant_8x8_msa; + pf->dequant_4x4 = x264_dequant_4x4_msa; + pf->dequant_4x4_dc = x264_dequant_4x4_dc_msa; + pf->dequant_8x8 = x264_dequant_8x8_msa; + pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_msa; + pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_msa; + } +#endif +#endif // HIGH_BIT_DEPTH + pf->coeff_last[DCT_LUMA_DC] = pf->coeff_last[DCT_CHROMAU_DC] = pf->coeff_last[DCT_CHROMAV_DC] = + pf->coeff_last[DCT_CHROMAU_4x4] = pf->coeff_last[DCT_CHROMAV_4x4] = pf->coeff_last[DCT_LUMA_4x4]; + pf->coeff_last[DCT_CHROMA_AC] = pf->coeff_last[DCT_CHROMAU_AC] = + pf->coeff_last[DCT_CHROMAV_AC] = pf->coeff_last[DCT_LUMA_AC]; + pf->coeff_last[DCT_CHROMAU_8x8] = pf->coeff_last[DCT_CHROMAV_8x8] = pf->coeff_last[DCT_LUMA_8x8]; + + pf->coeff_level_run[DCT_LUMA_DC] = pf->coeff_level_run[DCT_CHROMAU_DC] = pf->coeff_level_run[DCT_CHROMAV_DC] = + pf->coeff_level_run[DCT_CHROMAU_4x4] = pf->coeff_level_run[DCT_CHROMAV_4x4] = pf->coeff_level_run[DCT_LUMA_4x4]; + pf->coeff_level_run[DCT_CHROMA_AC] = pf->coeff_level_run[DCT_CHROMAU_AC] = + pf->coeff_level_run[DCT_CHROMAV_AC] = pf->coeff_level_run[DCT_LUMA_AC]; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/quant.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/quant.h new file mode 100644 index 00000000..0bd0c21c --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/quant.h @@ -0,0 +1,74 @@ +/***************************************************************************** + * quant.h: quantization and level-run + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_QUANT_H +#define X264_QUANT_H + +typedef struct +{ + int (*quant_8x8) ( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); + int (*quant_4x4) ( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); + int (*quant_4x4x4)( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); + int (*quant_4x4_dc)( dctcoef dct[16], int mf, int bias ); + int (*quant_2x2_dc)( dctcoef dct[4], int mf, int bias ); + + void (*dequant_8x8)( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); + void (*dequant_4x4)( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); + void (*dequant_4x4_dc)( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); + + void (*idct_dequant_2x4_dc)( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp ); + void (*idct_dequant_2x4_dconly)( dctcoef dct[8], int dequant_mf[6][16], int i_qp ); + + int (*optimize_chroma_2x2_dc)( dctcoef dct[4], int dequant_mf ); + int (*optimize_chroma_2x4_dc)( dctcoef dct[8], int dequant_mf ); + + void (*denoise_dct)( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); + + int (*decimate_score15)( dctcoef *dct ); + int (*decimate_score16)( dctcoef *dct ); + int (*decimate_score64)( dctcoef *dct ); + int (*coeff_last[14])( dctcoef *dct ); + int (*coeff_last4)( dctcoef *dct ); + int (*coeff_last8)( dctcoef *dct ); + int (*coeff_level_run[13])( dctcoef *dct, x264_run_level_t *runlevel ); + int (*coeff_level_run4)( dctcoef *dct, x264_run_level_t *runlevel ); + int (*coeff_level_run8)( dctcoef *dct, x264_run_level_t *runlevel ); + +#define TRELLIS_PARAMS const int *unquant_mf, const uint8_t *zigzag, int lambda2,\ + int last_nnz, dctcoef *coefs, dctcoef *quant_coefs, dctcoef *dct,\ + uint8_t *cabac_state_sig, uint8_t *cabac_state_last,\ + uint64_t level_state0, uint16_t level_state1 + int (*trellis_cabac_4x4)( TRELLIS_PARAMS, int b_ac ); + int (*trellis_cabac_8x8)( TRELLIS_PARAMS, int b_interlaced ); + int (*trellis_cabac_4x4_psy)( TRELLIS_PARAMS, int b_ac, dctcoef *fenc_dct, int psy_trellis ); + int (*trellis_cabac_8x8_psy)( TRELLIS_PARAMS, int b_interlaced, dctcoef *fenc_dct, int psy_trellis ); + int (*trellis_cabac_dc)( TRELLIS_PARAMS, int num_coefs ); + int (*trellis_cabac_chroma_422_dc)( TRELLIS_PARAMS ); +} x264_quant_function_t; + +void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/rectangle.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/rectangle.c new file mode 100644 index 00000000..4057b683 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/rectangle.c @@ -0,0 +1,58 @@ +/***************************************************************************** + * rectangle.c: rectangle filling + ***************************************************************************** + * Copyright (C) 2010-2017 x264 project + * + * Authors: Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#define CACHE_FUNC(name,size,width,height)\ +static void x264_macroblock_cache_##name##_##width##_##height( void *target, uint32_t val )\ +{\ + x264_macroblock_cache_rect( target, width*size, height, size, val );\ +} + +#define CACHE_FUNCS(name,size)\ +CACHE_FUNC(name,size,4,4)\ +CACHE_FUNC(name,size,2,4)\ +CACHE_FUNC(name,size,4,2)\ +CACHE_FUNC(name,size,2,2)\ +CACHE_FUNC(name,size,2,1)\ +CACHE_FUNC(name,size,1,2)\ +CACHE_FUNC(name,size,1,1)\ +void (*x264_cache_##name##_func_table[10])(void *, uint32_t) =\ +{\ + x264_macroblock_cache_##name##_1_1,\ + x264_macroblock_cache_##name##_2_1,\ + x264_macroblock_cache_##name##_1_2,\ + x264_macroblock_cache_##name##_2_2,\ + NULL,\ + x264_macroblock_cache_##name##_4_2,\ + NULL,\ + x264_macroblock_cache_##name##_2_4,\ + NULL,\ + x264_macroblock_cache_##name##_4_4\ +};\ + +CACHE_FUNCS(mv, 4) +CACHE_FUNCS(mvd, 2) +CACHE_FUNCS(ref, 1) diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/rectangle.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/rectangle.h new file mode 100644 index 00000000..2bd20281 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/rectangle.h @@ -0,0 +1,157 @@ +/***************************************************************************** + * rectangle.h: rectangle filling + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Fiona Glaser + * Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +/* This function should only be called with constant w / h / s arguments! */ +static ALWAYS_INLINE void x264_macroblock_cache_rect( void *dst, int w, int h, int s, uint32_t v ) +{ + uint8_t *d = dst; + uint16_t v2 = s == 2 ? v : v * 0x101; + uint32_t v4 = s == 4 ? v : s == 2 ? v * 0x10001 : v * 0x1010101; + uint64_t v8 = v4 + ((uint64_t)v4 << 32); + s *= 8; + + if( w == 2 ) + { + M16( d+s*0 ) = v2; + if( h == 1 ) return; + M16( d+s*1 ) = v2; + if( h == 2 ) return; + M16( d+s*2 ) = v2; + M16( d+s*3 ) = v2; + } + else if( w == 4 ) + { + M32( d+s*0 ) = v4; + if( h == 1 ) return; + M32( d+s*1 ) = v4; + if( h == 2 ) return; + M32( d+s*2 ) = v4; + M32( d+s*3 ) = v4; + } + else if( w == 8 ) + { + if( WORD_SIZE == 8 ) + { + M64( d+s*0 ) = v8; + if( h == 1 ) return; + M64( d+s*1 ) = v8; + if( h == 2 ) return; + M64( d+s*2 ) = v8; + M64( d+s*3 ) = v8; + } + else + { + M32( d+s*0+0 ) = v4; + M32( d+s*0+4 ) = v4; + if( h == 1 ) return; + M32( d+s*1+0 ) = v4; + M32( d+s*1+4 ) = v4; + if( h == 2 ) return; + M32( d+s*2+0 ) = v4; + M32( d+s*2+4 ) = v4; + M32( d+s*3+0 ) = v4; + M32( d+s*3+4 ) = v4; + } + } + else if( w == 16 ) + { + /* height 1, width 16 doesn't occur */ + assert( h != 1 ); +#if HAVE_VECTOREXT && defined(__SSE__) + v4si v16 = {v,v,v,v}; + + M128( d+s*0+0 ) = (__m128)v16; + M128( d+s*1+0 ) = (__m128)v16; + if( h == 2 ) return; + M128( d+s*2+0 ) = (__m128)v16; + M128( d+s*3+0 ) = (__m128)v16; +#else + if( WORD_SIZE == 8 ) + { + do + { + M64( d+s*0+0 ) = v8; + M64( d+s*0+8 ) = v8; + M64( d+s*1+0 ) = v8; + M64( d+s*1+8 ) = v8; + h -= 2; + d += s*2; + } while( h ); + } + else + { + do + { + M32( d+ 0 ) = v4; + M32( d+ 4 ) = v4; + M32( d+ 8 ) = v4; + M32( d+12 ) = v4; + d += s; + } while( --h ); + } +#endif + } + else + assert(0); +} + +extern void (*x264_cache_mv_func_table[10])(void *, uint32_t);\ +extern void (*x264_cache_mvd_func_table[10])(void *, uint32_t);\ +extern void (*x264_cache_ref_func_table[10])(void *, uint32_t);\ + +#define x264_macroblock_cache_mv_ptr( a, x, y, w, h, l, mv ) x264_macroblock_cache_mv( a, x, y, w, h, l, M32( mv ) ) +static ALWAYS_INLINE void x264_macroblock_cache_mv( x264_t *h, int x, int y, int width, int height, int i_list, uint32_t mv ) +{ + void *mv_cache = &h->mb.cache.mv[i_list][X264_SCAN8_0+x+8*y]; + if( x264_nonconstant_p( width ) || x264_nonconstant_p( height ) ) + x264_cache_mv_func_table[width + (height<<1)-3]( mv_cache, mv ); + else + x264_macroblock_cache_rect( mv_cache, width*4, height, 4, mv ); +} +static ALWAYS_INLINE void x264_macroblock_cache_mvd( x264_t *h, int x, int y, int width, int height, int i_list, uint16_t mvd ) +{ + void *mvd_cache = &h->mb.cache.mvd[i_list][X264_SCAN8_0+x+8*y]; + if( x264_nonconstant_p( width ) || x264_nonconstant_p( height ) ) + x264_cache_mvd_func_table[width + (height<<1)-3]( mvd_cache, mvd ); + else + x264_macroblock_cache_rect( mvd_cache, width*2, height, 2, mvd ); +} +static ALWAYS_INLINE void x264_macroblock_cache_ref( x264_t *h, int x, int y, int width, int height, int i_list, uint8_t ref ) +{ + void *ref_cache = &h->mb.cache.ref[i_list][X264_SCAN8_0+x+8*y]; + if( x264_nonconstant_p( width ) || x264_nonconstant_p( height ) ) + x264_cache_ref_func_table[width + (height<<1)-3]( ref_cache, ref ); + else + x264_macroblock_cache_rect( ref_cache, width, height, 1, ref ); +} +static ALWAYS_INLINE void x264_macroblock_cache_skip( x264_t *h, int x, int y, int width, int height, int b_skip ) +{ + x264_macroblock_cache_rect( &h->mb.cache.skip[X264_SCAN8_0+x+8*y], width, height, 1, b_skip ); +} +static ALWAYS_INLINE void x264_macroblock_cache_intra8x8_pred( x264_t *h, int x, int y, int i_mode ) +{ + x264_macroblock_cache_rect( &h->mb.cache.intra4x4_pred_mode[X264_SCAN8_0+x+8*y], 2, 2, 1, i_mode ); +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/set.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/set.c new file mode 100644 index 00000000..b9d94fd8 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/set.c @@ -0,0 +1,379 @@ +/***************************************************************************** + * set.c: quantization init + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +#define SHIFT(x,s) ((s)<=0 ? (x)<<-(s) : ((x)+(1<<((s)-1)))>>(s)) +#define DIV(n,d) (((n) + ((d)>>1)) / (d)) + +static const uint8_t dequant4_scale[6][3] = +{ + { 10, 13, 16 }, + { 11, 14, 18 }, + { 13, 16, 20 }, + { 14, 18, 23 }, + { 16, 20, 25 }, + { 18, 23, 29 } +}; +static const uint16_t quant4_scale[6][3] = +{ + { 13107, 8066, 5243 }, + { 11916, 7490, 4660 }, + { 10082, 6554, 4194 }, + { 9362, 5825, 3647 }, + { 8192, 5243, 3355 }, + { 7282, 4559, 2893 }, +}; + +static const uint8_t quant8_scan[16] = +{ + 0,3,4,3, 3,1,5,1, 4,5,2,5, 3,1,5,1 +}; +static const uint8_t dequant8_scale[6][6] = +{ + { 20, 18, 32, 19, 25, 24 }, + { 22, 19, 35, 21, 28, 26 }, + { 26, 23, 42, 24, 33, 31 }, + { 28, 25, 45, 26, 35, 33 }, + { 32, 28, 51, 30, 40, 38 }, + { 36, 32, 58, 34, 46, 43 }, +}; +static const uint16_t quant8_scale[6][6] = +{ + { 13107, 11428, 20972, 12222, 16777, 15481 }, + { 11916, 10826, 19174, 11058, 14980, 14290 }, + { 10082, 8943, 15978, 9675, 12710, 11985 }, + { 9362, 8228, 14913, 8931, 11984, 11259 }, + { 8192, 7346, 13159, 7740, 10486, 9777 }, + { 7282, 6428, 11570, 6830, 9118, 8640 } +}; + +int x264_cqm_init( x264_t *h ) +{ + int def_quant4[6][16]; + int def_quant8[6][64]; + int def_dequant4[6][16]; + int def_dequant8[6][64]; + int quant4_mf[4][6][16]; + int quant8_mf[4][6][64]; + int deadzone[4] = { 32 - h->param.analyse.i_luma_deadzone[1], + 32 - h->param.analyse.i_luma_deadzone[0], + 32 - 11, 32 - 21 }; + int max_qp_err = -1; + int max_chroma_qp_err = -1; + int min_qp_err = QP_MAX+1; + int num_8x8_lists = h->sps->i_chroma_format_idc == CHROMA_444 ? 4 + : h->param.analyse.b_transform_8x8 ? 2 : 0; /* Checkasm may segfault if optimized out by --chroma-format */ + +#define CQM_ALLOC( w, count )\ + for( int i = 0; i < count; i++ )\ + {\ + int size = w*w;\ + int start = w == 8 ? 4 : 0;\ + int j;\ + for( j = 0; j < i; j++ )\ + if( !memcmp( h->pps->scaling_list[i+start], h->pps->scaling_list[j+start], size*sizeof(uint8_t) ) )\ + break;\ + if( j < i )\ + {\ + h-> quant##w##_mf[i] = h-> quant##w##_mf[j];\ + h->dequant##w##_mf[i] = h->dequant##w##_mf[j];\ + h->unquant##w##_mf[i] = h->unquant##w##_mf[j];\ + }\ + else\ + {\ + CHECKED_MALLOC( h-> quant##w##_mf[i], (QP_MAX_SPEC+1)*size*sizeof(udctcoef) );\ + CHECKED_MALLOC( h->dequant##w##_mf[i], 6*size*sizeof(int) );\ + CHECKED_MALLOC( h->unquant##w##_mf[i], (QP_MAX_SPEC+1)*size*sizeof(int) );\ + }\ + for( j = 0; j < i; j++ )\ + if( deadzone[j] == deadzone[i] &&\ + !memcmp( h->pps->scaling_list[i+start], h->pps->scaling_list[j+start], size*sizeof(uint8_t) ) )\ + break;\ + if( j < i )\ + {\ + h->quant##w##_bias[i] = h->quant##w##_bias[j];\ + h->quant##w##_bias0[i] = h->quant##w##_bias0[j];\ + }\ + else\ + {\ + CHECKED_MALLOC( h->quant##w##_bias[i], (QP_MAX_SPEC+1)*size*sizeof(udctcoef) );\ + CHECKED_MALLOC( h->quant##w##_bias0[i], (QP_MAX_SPEC+1)*size*sizeof(udctcoef) );\ + }\ + } + + CQM_ALLOC( 4, 4 ) + CQM_ALLOC( 8, num_8x8_lists ) + + for( int q = 0; q < 6; q++ ) + { + for( int i = 0; i < 16; i++ ) + { + int j = (i&1) + ((i>>2)&1); + def_dequant4[q][i] = dequant4_scale[q][j]; + def_quant4[q][i] = quant4_scale[q][j]; + } + for( int i = 0; i < 64; i++ ) + { + int j = quant8_scan[((i>>1)&12) | (i&3)]; + def_dequant8[q][i] = dequant8_scale[q][j]; + def_quant8[q][i] = quant8_scale[q][j]; + } + } + + for( int q = 0; q < 6; q++ ) + { + for( int i_list = 0; i_list < 4; i_list++ ) + for( int i = 0; i < 16; i++ ) + { + h->dequant4_mf[i_list][q][i] = def_dequant4[q][i] * h->pps->scaling_list[i_list][i]; + quant4_mf[i_list][q][i] = DIV(def_quant4[q][i] * 16, h->pps->scaling_list[i_list][i]); + } + for( int i_list = 0; i_list < num_8x8_lists; i_list++ ) + for( int i = 0; i < 64; i++ ) + { + h->dequant8_mf[i_list][q][i] = def_dequant8[q][i] * h->pps->scaling_list[4+i_list][i]; + quant8_mf[i_list][q][i] = DIV(def_quant8[q][i] * 16, h->pps->scaling_list[4+i_list][i]); + } + } + for( int q = 0; q <= QP_MAX_SPEC; q++ ) + { + int j; + for( int i_list = 0; i_list < 4; i_list++ ) + for( int i = 0; i < 16; i++ ) + { + h->unquant4_mf[i_list][q][i] = (1ULL << (q/6 + 15 + 8)) / quant4_mf[i_list][q%6][i]; + h->quant4_mf[i_list][q][i] = j = SHIFT(quant4_mf[i_list][q%6][i], q/6 - 1); + if( !j ) + { + min_qp_err = X264_MIN( min_qp_err, q ); + continue; + } + // round to nearest, unless that would cause the deadzone to be negative + h->quant4_bias[i_list][q][i] = X264_MIN( DIV(deadzone[i_list]<<10, j), (1<<15)/j ); + h->quant4_bias0[i_list][q][i] = (1<<15)/j; + if( j > 0xffff && q > max_qp_err && (i_list == CQM_4IY || i_list == CQM_4PY) ) + max_qp_err = q; + if( j > 0xffff && q > max_chroma_qp_err && (i_list == CQM_4IC || i_list == CQM_4PC) ) + max_chroma_qp_err = q; + } + if( h->param.analyse.b_transform_8x8 ) + for( int i_list = 0; i_list < num_8x8_lists; i_list++ ) + for( int i = 0; i < 64; i++ ) + { + h->unquant8_mf[i_list][q][i] = (1ULL << (q/6 + 16 + 8)) / quant8_mf[i_list][q%6][i]; + j = SHIFT(quant8_mf[i_list][q%6][i], q/6); + h->quant8_mf[i_list][q][i] = (uint16_t)j; + + if( !j ) + { + min_qp_err = X264_MIN( min_qp_err, q ); + continue; + } + h->quant8_bias[i_list][q][i] = X264_MIN( DIV(deadzone[i_list]<<10, j), (1<<15)/j ); + h->quant8_bias0[i_list][q][i] = (1<<15)/j; + if( j > 0xffff && q > max_qp_err && (i_list == CQM_8IY || i_list == CQM_8PY) ) + max_qp_err = q; + if( j > 0xffff && q > max_chroma_qp_err && (i_list == CQM_8IC || i_list == CQM_8PC) ) + max_chroma_qp_err = q; + } + } + + /* Emergency mode denoising. */ + x264_emms(); + CHECKED_MALLOC( h->nr_offset_emergency, sizeof(*h->nr_offset_emergency)*(QP_MAX-QP_MAX_SPEC) ); + for( int q = 0; q < QP_MAX - QP_MAX_SPEC; q++ ) + for( int cat = 0; cat < 3 + CHROMA444; cat++ ) + { + int dct8x8 = cat&1; + if( !h->param.analyse.b_transform_8x8 && dct8x8 ) + continue; + + int size = dct8x8 ? 64 : 16; + udctcoef *nr_offset = h->nr_offset_emergency[q][cat]; + /* Denoise chroma first (due to h264's chroma QP offset), then luma, then DC. */ + int dc_threshold = (QP_MAX-QP_MAX_SPEC)*2/3; + int luma_threshold = (QP_MAX-QP_MAX_SPEC)*2/3; + int chroma_threshold = 0; + + for( int i = 0; i < size; i++ ) + { + int max = (1 << (7 + BIT_DEPTH)) - 1; + /* True "emergency mode": remove all DCT coefficients */ + if( q == QP_MAX - QP_MAX_SPEC - 1 ) + { + nr_offset[i] = max; + continue; + } + + int thresh = i == 0 ? dc_threshold : cat >= 2 ? chroma_threshold : luma_threshold; + if( q < thresh ) + { + nr_offset[i] = 0; + continue; + } + double pos = (double)(q-thresh+1) / (QP_MAX - QP_MAX_SPEC - thresh); + + /* XXX: this math is largely tuned for /dev/random input. */ + double start = dct8x8 ? h->unquant8_mf[CQM_8PY][QP_MAX_SPEC][i] + : h->unquant4_mf[CQM_4PY][QP_MAX_SPEC][i]; + /* Formula chosen as an exponential scale to vaguely mimic the effects + * of a higher quantizer. */ + double bias = (pow( 2, pos*(QP_MAX - QP_MAX_SPEC)/10. )*0.003-0.003) * start; + nr_offset[i] = X264_MIN( bias + 0.5, max ); + } + } + + if( !h->mb.b_lossless ) + { + while( h->chroma_qp_table[SPEC_QP(h->param.rc.i_qp_min)] <= max_chroma_qp_err ) + h->param.rc.i_qp_min++; + if( min_qp_err <= h->param.rc.i_qp_max ) + h->param.rc.i_qp_max = min_qp_err-1; + if( max_qp_err >= h->param.rc.i_qp_min ) + h->param.rc.i_qp_min = max_qp_err+1; + /* If long level-codes aren't allowed, we need to allow QP high enough to avoid them. */ + if( !h->param.b_cabac && h->sps->i_profile_idc < PROFILE_HIGH ) + while( h->chroma_qp_table[SPEC_QP(h->param.rc.i_qp_max)] <= 12 || h->param.rc.i_qp_max <= 12 ) + h->param.rc.i_qp_max++; + if( h->param.rc.i_qp_min > h->param.rc.i_qp_max ) + { + x264_log( h, X264_LOG_ERROR, "Impossible QP constraints for CQM (min=%d, max=%d)\n", h->param.rc.i_qp_min, h->param.rc.i_qp_max ); + return -1; + } + } + return 0; +fail: + x264_cqm_delete( h ); + return -1; +} + +#define CQM_DELETE( n, max )\ + for( int i = 0; i < (max); i++ )\ + {\ + int j;\ + for( j = 0; j < i; j++ )\ + if( h->quant##n##_mf[i] == h->quant##n##_mf[j] )\ + break;\ + if( j == i )\ + {\ + x264_free( h-> quant##n##_mf[i] );\ + x264_free( h->dequant##n##_mf[i] );\ + x264_free( h->unquant##n##_mf[i] );\ + }\ + for( j = 0; j < i; j++ )\ + if( h->quant##n##_bias[i] == h->quant##n##_bias[j] )\ + break;\ + if( j == i )\ + {\ + x264_free( h->quant##n##_bias[i] );\ + x264_free( h->quant##n##_bias0[i] );\ + }\ + } + +void x264_cqm_delete( x264_t *h ) +{ + CQM_DELETE( 4, 4 ); + CQM_DELETE( 8, CHROMA444 ? 4 : 2 ); + x264_free( h->nr_offset_emergency ); +} + +static int x264_cqm_parse_jmlist( x264_t *h, const char *buf, const char *name, + uint8_t *cqm, const uint8_t *jvt, int length ) +{ + int i; + + char *p = strstr( buf, name ); + if( !p ) + { + memset( cqm, 16, length ); + return 0; + } + + p += strlen( name ); + if( *p == 'U' || *p == 'V' ) + p++; + + char *nextvar = strstr( p, "INT" ); + + for( i = 0; i < length && (p = strpbrk( p, " \t\n," )) && (p = strpbrk( p, "0123456789" )); i++ ) + { + int coef = -1; + sscanf( p, "%d", &coef ); + if( i == 0 && coef == 0 ) + { + memcpy( cqm, jvt, length ); + return 0; + } + if( coef < 1 || coef > 255 ) + { + x264_log( h, X264_LOG_ERROR, "bad coefficient in list '%s'\n", name ); + return -1; + } + cqm[i] = coef; + } + + if( (nextvar && p > nextvar) || i != length ) + { + x264_log( h, X264_LOG_ERROR, "not enough coefficients in list '%s'\n", name ); + return -1; + } + + return 0; +} + +int x264_cqm_parse_file( x264_t *h, const char *filename ) +{ + char *p; + int b_error = 0; + + h->param.i_cqm_preset = X264_CQM_CUSTOM; + + char *buf = x264_slurp_file( filename ); + if( !buf ) + { + x264_log( h, X264_LOG_ERROR, "can't open file '%s'\n", filename ); + return -1; + } + + while( (p = strchr( buf, '#' )) != NULL ) + memset( p, ' ', strcspn( p, "\n" ) ); + + b_error |= x264_cqm_parse_jmlist( h, buf, "INTRA4X4_LUMA", h->param.cqm_4iy, x264_cqm_jvt4i, 16 ); + b_error |= x264_cqm_parse_jmlist( h, buf, "INTER4X4_LUMA", h->param.cqm_4py, x264_cqm_jvt4p, 16 ); + b_error |= x264_cqm_parse_jmlist( h, buf, "INTRA4X4_CHROMA", h->param.cqm_4ic, x264_cqm_jvt4i, 16 ); + b_error |= x264_cqm_parse_jmlist( h, buf, "INTER4X4_CHROMA", h->param.cqm_4pc, x264_cqm_jvt4p, 16 ); + b_error |= x264_cqm_parse_jmlist( h, buf, "INTRA8X8_LUMA", h->param.cqm_8iy, x264_cqm_jvt8i, 64 ); + b_error |= x264_cqm_parse_jmlist( h, buf, "INTER8X8_LUMA", h->param.cqm_8py, x264_cqm_jvt8p, 64 ); + if( CHROMA444 ) + { + b_error |= x264_cqm_parse_jmlist( h, buf, "INTRA8X8_CHROMA", h->param.cqm_8ic, x264_cqm_jvt8i, 64 ); + b_error |= x264_cqm_parse_jmlist( h, buf, "INTER8X8_CHROMA", h->param.cqm_8pc, x264_cqm_jvt8p, 64 ); + } + + x264_free( buf ); + return b_error; +} + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/set.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/set.h new file mode 100644 index 00000000..5760f33c --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/set.h @@ -0,0 +1,347 @@ +/***************************************************************************** + * set.h: quantization init + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_SET_H +#define X264_SET_H + +enum profile_e +{ + PROFILE_BASELINE = 66, + PROFILE_MAIN = 77, + PROFILE_HIGH = 100, + PROFILE_HIGH10 = 110, + PROFILE_HIGH422 = 122, + PROFILE_HIGH444_PREDICTIVE = 244, +}; + +enum chroma_format_e +{ + CHROMA_400 = 0, + CHROMA_420 = 1, + CHROMA_422 = 2, + CHROMA_444 = 3, +}; + +enum cqm4_e +{ + CQM_4IY = 0, + CQM_4PY = 1, + CQM_4IC = 2, + CQM_4PC = 3 +}; +enum cqm8_e +{ + CQM_8IY = 0, + CQM_8PY = 1, + CQM_8IC = 2, + CQM_8PC = 3, +}; + +typedef struct +{ + int i_id; + + int i_profile_idc; + int i_level_idc; + + int b_constraint_set0; + int b_constraint_set1; + int b_constraint_set2; + int b_constraint_set3; + + int i_log2_max_frame_num; + + int i_poc_type; + /* poc 0 */ + int i_log2_max_poc_lsb; + + int i_num_ref_frames; + int b_gaps_in_frame_num_value_allowed; + int i_mb_width; + int i_mb_height; + int b_frame_mbs_only; + int b_mb_adaptive_frame_field; + int b_direct8x8_inference; + + int b_crop; + struct + { + int i_left; + int i_right; + int i_top; + int i_bottom; + } crop; + + int b_vui; + struct + { + int b_aspect_ratio_info_present; + int i_sar_width; + int i_sar_height; + + int b_overscan_info_present; + int b_overscan_info; + + int b_signal_type_present; + int i_vidformat; + int b_fullrange; + int b_color_description_present; + int i_colorprim; + int i_transfer; + int i_colmatrix; + + int b_chroma_loc_info_present; + int i_chroma_loc_top; + int i_chroma_loc_bottom; + + int b_timing_info_present; + uint32_t i_num_units_in_tick; + uint32_t i_time_scale; + int b_fixed_frame_rate; + + int b_nal_hrd_parameters_present; + int b_vcl_hrd_parameters_present; + + struct + { + int i_cpb_cnt; + int i_bit_rate_scale; + int i_cpb_size_scale; + int i_bit_rate_value; + int i_cpb_size_value; + int i_bit_rate_unscaled; + int i_cpb_size_unscaled; + int b_cbr_hrd; + + int i_initial_cpb_removal_delay_length; + int i_cpb_removal_delay_length; + int i_dpb_output_delay_length; + int i_time_offset_length; + } hrd; + + int b_pic_struct_present; + int b_bitstream_restriction; + int b_motion_vectors_over_pic_boundaries; + int i_max_bytes_per_pic_denom; + int i_max_bits_per_mb_denom; + int i_log2_max_mv_length_horizontal; + int i_log2_max_mv_length_vertical; + int i_num_reorder_frames; + int i_max_dec_frame_buffering; + + /* FIXME to complete */ + } vui; + + int b_qpprime_y_zero_transform_bypass; + int i_chroma_format_idc; + +} x264_sps_t; + +typedef struct +{ + int i_id; + int i_sps_id; + + int b_cabac; + + int b_pic_order; + int i_num_slice_groups; + + int i_num_ref_idx_l0_default_active; + int i_num_ref_idx_l1_default_active; + + int b_weighted_pred; + int b_weighted_bipred; + + int i_pic_init_qp; + int i_pic_init_qs; + + int i_chroma_qp_index_offset; + + int b_deblocking_filter_control; + int b_constrained_intra_pred; + int b_redundant_pic_cnt; + + int b_transform_8x8_mode; + + int i_cqm_preset; + const uint8_t *scaling_list[8]; /* could be 12, but we don't allow separate Cb/Cr lists */ + +} x264_pps_t; + +/* default quant matrices */ +static const uint8_t x264_cqm_jvt4i[16] = +{ + 6,13,20,28, + 13,20,28,32, + 20,28,32,37, + 28,32,37,42 +}; +static const uint8_t x264_cqm_jvt4p[16] = +{ + 10,14,20,24, + 14,20,24,27, + 20,24,27,30, + 24,27,30,34 +}; +static const uint8_t x264_cqm_jvt8i[64] = +{ + 6,10,13,16,18,23,25,27, + 10,11,16,18,23,25,27,29, + 13,16,18,23,25,27,29,31, + 16,18,23,25,27,29,31,33, + 18,23,25,27,29,31,33,36, + 23,25,27,29,31,33,36,38, + 25,27,29,31,33,36,38,40, + 27,29,31,33,36,38,40,42 +}; +static const uint8_t x264_cqm_jvt8p[64] = +{ + 9,13,15,17,19,21,22,24, + 13,13,17,19,21,22,24,25, + 15,17,19,21,22,24,25,27, + 17,19,21,22,24,25,27,28, + 19,21,22,24,25,27,28,30, + 21,22,24,25,27,28,30,32, + 22,24,25,27,28,30,32,33, + 24,25,27,28,30,32,33,35 +}; +static const uint8_t x264_cqm_flat16[64] = +{ + 16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16 +}; +static const uint8_t * const x264_cqm_jvt[8] = +{ + x264_cqm_jvt4i, x264_cqm_jvt4p, + x264_cqm_jvt4i, x264_cqm_jvt4p, + x264_cqm_jvt8i, x264_cqm_jvt8p, + x264_cqm_jvt8i, x264_cqm_jvt8p +}; + +// 1080i25_avci50, 1080p25_avci50 +static const uint8_t x264_cqm_avci50_4ic[16] = +{ + 16,22,28,40, + 22,28,40,44, + 28,40,44,48, + 40,44,48,60 +}; + +// 1080i25_avci50, +static const uint8_t x264_cqm_avci50_1080i_8iy[64] = +{ + 16,18,19,21,27,33,81,87, + 18,19,21,24,30,33,81,87, + 19,21,24,27,30,78,84,90, + 21,24,27,30,33,78,84,90, + 24,27,30,33,78,81,84,90, + 24,27,30,33,78,81,84,93, + 27,30,33,78,78,81,87,93, + 30,33,33,78,81,84,87,96 +}; + +// 1080p25_avci50, 720p25_avci50, 720p50_avci50 +static const uint8_t x264_cqm_avci50_p_8iy[64] = +{ + 16,18,19,21,24,27,30,33, + 18,19,21,24,27,30,33,78, + 19,21,24,27,30,33,78,81, + 21,24,27,30,33,78,81,84, + 24,27,30,33,78,81,84,87, + 27,30,33,78,81,84,87,90, + 30,33,78,81,84,87,90,93, + 33,78,81,84,87,90,93,96 +}; + +// 1080i25_avci100, 1080p25_avci100 +static const uint8_t x264_cqm_avci100_1080_4ic[16] = +{ + 16,20,26,32, + 20,26,32,38, + 26,32,38,44, + 32,38,44,50 +}; + +// 720p25_avci100, 720p50_avci100 +static const uint8_t x264_cqm_avci100_720p_4ic[16] = +{ + 16,21,27,34, + 21,27,34,41, + 27,34,41,46, + 34,41,46,54 +}; + +// 1080i25_avci100, +static const uint8_t x264_cqm_avci100_1080i_8iy[64] = +{ + 16,19,20,23,24,26,32,42, + 18,19,22,24,26,32,36,42, + 18,20,23,24,26,32,36,63, + 19,20,23,26,32,36,42,63, + 20,22,24,26,32,36,59,63, + 22,23,24,26,32,36,59,68, + 22,23,24,26,32,42,59,68, + 22,23,24,26,36,42,59,72 +}; + +// 1080p25_avci100, +static const uint8_t x264_cqm_avci100_1080p_8iy[64] = +{ + 16,18,19,20,22,23,24,26, + 18,19,20,22,23,24,26,32, + 19,20,22,23,24,26,32,36, + 20,22,23,24,26,32,36,42, + 22,23,24,26,32,36,42,59, + 23,24,26,32,36,42,59,63, + 24,26,32,36,42,59,63,68, + 26,32,36,42,59,63,68,72 +}; + +// 720p25_avci100, 720p50_avci100 +static const uint8_t x264_cqm_avci100_720p_8iy[64] = +{ + 16,18,19,21,22,24,26,32, + 18,19,19,21,22,24,26,32, + 19,19,21,22,22,24,26,32, + 21,21,22,22,23,24,26,34, + 22,22,22,23,24,25,26,34, + 24,24,24,24,25,26,34,36, + 26,26,26,26,26,34,36,38, + 32,32,32,34,34,36,38,42 +}; + +int x264_cqm_init( x264_t *h ); +void x264_cqm_delete( x264_t *h ); +int x264_cqm_parse_file( x264_t *h, const char *filename ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/threadpool.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/threadpool.c new file mode 100644 index 00000000..72eb86d0 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/threadpool.c @@ -0,0 +1,164 @@ +/***************************************************************************** + * threadpool.c: thread pooling + ***************************************************************************** + * Copyright (C) 2010-2017 x264 project + * + * Authors: Steven Walters + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +typedef struct +{ + void *(*func)(void *); + void *arg; + void *ret; +} x264_threadpool_job_t; + +struct x264_threadpool_t +{ + int exit; + int threads; + x264_pthread_t *thread_handle; + void (*init_func)(void *); + void *init_arg; + + /* requires a synchronized list structure and associated methods, + so use what is already implemented for frames */ + x264_sync_frame_list_t uninit; /* list of jobs that are awaiting use */ + x264_sync_frame_list_t run; /* list of jobs that are queued for processing by the pool */ + x264_sync_frame_list_t done; /* list of jobs that have finished processing */ +}; + +static void *x264_threadpool_thread( x264_threadpool_t *pool ) +{ + if( pool->init_func ) + pool->init_func( pool->init_arg ); + + while( !pool->exit ) + { + x264_threadpool_job_t *job = NULL; + x264_pthread_mutex_lock( &pool->run.mutex ); + while( !pool->exit && !pool->run.i_size ) + x264_pthread_cond_wait( &pool->run.cv_fill, &pool->run.mutex ); + if( pool->run.i_size ) + { + job = (void*)x264_frame_shift( pool->run.list ); + pool->run.i_size--; + } + x264_pthread_mutex_unlock( &pool->run.mutex ); + if( !job ) + continue; + job->ret = (void*)x264_stack_align( job->func, job->arg ); /* execute the function */ + x264_sync_frame_list_push( &pool->done, (void*)job ); + } + return NULL; +} + +int x264_threadpool_init( x264_threadpool_t **p_pool, int threads, + void (*init_func)(void *), void *init_arg ) +{ + if( threads <= 0 ) + return -1; + + x264_threadpool_t *pool; + CHECKED_MALLOCZERO( pool, sizeof(x264_threadpool_t) ); + *p_pool = pool; + + pool->init_func = init_func; + pool->init_arg = init_arg; + pool->threads = threads; + + CHECKED_MALLOC( pool->thread_handle, pool->threads * sizeof(x264_pthread_t) ); + + if( x264_sync_frame_list_init( &pool->uninit, pool->threads ) || + x264_sync_frame_list_init( &pool->run, pool->threads ) || + x264_sync_frame_list_init( &pool->done, pool->threads ) ) + goto fail; + + for( int i = 0; i < pool->threads; i++ ) + { + x264_threadpool_job_t *job; + CHECKED_MALLOC( job, sizeof(x264_threadpool_job_t) ); + x264_sync_frame_list_push( &pool->uninit, (void*)job ); + } + for( int i = 0; i < pool->threads; i++ ) + if( x264_pthread_create( pool->thread_handle+i, NULL, (void*)x264_threadpool_thread, pool ) ) + goto fail; + + return 0; +fail: + return -1; +} + +void x264_threadpool_run( x264_threadpool_t *pool, void *(*func)(void *), void *arg ) +{ + x264_threadpool_job_t *job = (void*)x264_sync_frame_list_pop( &pool->uninit ); + job->func = func; + job->arg = arg; + x264_sync_frame_list_push( &pool->run, (void*)job ); +} + +void *x264_threadpool_wait( x264_threadpool_t *pool, void *arg ) +{ + x264_pthread_mutex_lock( &pool->done.mutex ); + while( 1 ) + { + for( int i = 0; i < pool->done.i_size; i++ ) + if( ((x264_threadpool_job_t*)pool->done.list[i])->arg == arg ) + { + x264_threadpool_job_t *job = (void*)x264_frame_shift( pool->done.list+i ); + pool->done.i_size--; + x264_pthread_mutex_unlock( &pool->done.mutex ); + + void *ret = job->ret; + x264_sync_frame_list_push( &pool->uninit, (void*)job ); + return ret; + } + + x264_pthread_cond_wait( &pool->done.cv_fill, &pool->done.mutex ); + } +} + +static void x264_threadpool_list_delete( x264_sync_frame_list_t *slist ) +{ + for( int i = 0; slist->list[i]; i++ ) + { + x264_free( slist->list[i] ); + slist->list[i] = NULL; + } + x264_sync_frame_list_delete( slist ); +} + +void x264_threadpool_delete( x264_threadpool_t *pool ) +{ + x264_pthread_mutex_lock( &pool->run.mutex ); + pool->exit = 1; + x264_pthread_cond_broadcast( &pool->run.cv_fill ); + x264_pthread_mutex_unlock( &pool->run.mutex ); + for( int i = 0; i < pool->threads; i++ ) + x264_pthread_join( pool->thread_handle[i], NULL ); + + x264_threadpool_list_delete( &pool->uninit ); + x264_threadpool_list_delete( &pool->run ); + x264_threadpool_list_delete( &pool->done ); + x264_free( pool->thread_handle ); + x264_free( pool ); +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/threadpool.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/threadpool.h new file mode 100644 index 00000000..639cad42 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/threadpool.h @@ -0,0 +1,44 @@ +/***************************************************************************** + * threadpool.h: thread pooling + ***************************************************************************** + * Copyright (C) 2010-2017 x264 project + * + * Authors: Steven Walters + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_THREADPOOL_H +#define X264_THREADPOOL_H + +typedef struct x264_threadpool_t x264_threadpool_t; + +#if HAVE_THREAD +int x264_threadpool_init( x264_threadpool_t **p_pool, int threads, + void (*init_func)(void *), void *init_arg ); +void x264_threadpool_run( x264_threadpool_t *pool, void *(*func)(void *), void *arg ); +void *x264_threadpool_wait( x264_threadpool_t *pool, void *arg ); +void x264_threadpool_delete( x264_threadpool_t *pool ); +#else +#define x264_threadpool_init(p,t,f,a) -1 +#define x264_threadpool_run(p,f,a) +#define x264_threadpool_wait(p,a) NULL +#define x264_threadpool_delete(p) +#endif + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/vlc.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/vlc.c new file mode 100644 index 00000000..a55d4b90 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/vlc.c @@ -0,0 +1,869 @@ +/***************************************************************************** + * vlc.c : vlc tables + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Fiona Glaser + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common.h" + +/* [nC] */ +const vlc_t x264_coeff0_token[6] = +{ + { 0x1, 1 }, /* str=1 */ + { 0x3, 2 }, /* str=11 */ + { 0xf, 4 }, /* str=1111 */ + { 0x3, 6 }, /* str=000011 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 1 }, /* str=1 */ +}; + +/* [nC][i_total_coeff-1][i_trailing] */ +const vlc_t x264_coeff_token[6][16][4] = +{ + { /* table 0 */ + { /* i_total 1 */ + { 0x5, 6 }, /* str=000101 */ + { 0x1, 2 }, /* str=01 */ + }, + { /* i_total 2 */ + { 0x7, 8 }, /* str=00000111 */ + { 0x4, 6 }, /* str=000100 */ + { 0x1, 3 }, /* str=001 */ + }, + { /* i_total 3 */ + { 0x7, 9 }, /* str=000000111 */ + { 0x6, 8 }, /* str=00000110 */ + { 0x5, 7 }, /* str=0000101 */ + { 0x3, 5 }, /* str=00011 */ + }, + { /* i_total 4 */ + { 0x7, 10 }, /* str=0000000111 */ + { 0x6, 9 }, /* str=000000110 */ + { 0x5, 8 }, /* str=00000101 */ + { 0x3, 6 }, /* str=000011 */ + }, + { /* i_total 5 */ + { 0x7, 11 }, /* str=00000000111 */ + { 0x6, 10 }, /* str=0000000110 */ + { 0x5, 9 }, /* str=000000101 */ + { 0x4, 7 }, /* str=0000100 */ + }, + { /* i_total 6 */ + { 0xf, 13 }, /* str=0000000001111 */ + { 0x6, 11 }, /* str=00000000110 */ + { 0x5, 10 }, /* str=0000000101 */ + { 0x4, 8 }, /* str=00000100 */ + }, + { /* i_total 7 */ + { 0xb, 13 }, /* str=0000000001011 */ + { 0xe, 13 }, /* str=0000000001110 */ + { 0x5, 11 }, /* str=00000000101 */ + { 0x4, 9 }, /* str=000000100 */ + }, + { /* i_total 8 */ + { 0x8, 13 }, /* str=0000000001000 */ + { 0xa, 13 }, /* str=0000000001010 */ + { 0xd, 13 }, /* str=0000000001101 */ + { 0x4, 10 }, /* str=0000000100 */ + }, + { /* i_total 9 */ + { 0xf, 14 }, /* str=00000000001111 */ + { 0xe, 14 }, /* str=00000000001110 */ + { 0x9, 13 }, /* str=0000000001001 */ + { 0x4, 11 }, /* str=00000000100 */ + }, + { /* i_total 10 */ + { 0xb, 14 }, /* str=00000000001011 */ + { 0xa, 14 }, /* str=00000000001010 */ + { 0xd, 14 }, /* str=00000000001101 */ + { 0xc, 13 }, /* str=0000000001100 */ + }, + { /* i_total 14 */ + { 0xf, 15 }, /* str=000000000001111 */ + { 0xe, 15 }, /* str=000000000001110 */ + { 0x9, 14 }, /* str=00000000001001 */ + { 0xc, 14 }, /* str=00000000001100 */ + }, + { /* i_total 12 */ + { 0xb, 15 }, /* str=000000000001011 */ + { 0xa, 15 }, /* str=000000000001010 */ + { 0xd, 15 }, /* str=000000000001101 */ + { 0x8, 14 }, /* str=00000000001000 */ + }, + { /* i_total 13 */ + { 0xf, 16 }, /* str=0000000000001111 */ + { 0x1, 15 }, /* str=000000000000001 */ + { 0x9, 15 }, /* str=000000000001001 */ + { 0xc, 15 }, /* str=000000000001100 */ + }, + { /* i_total 14 */ + { 0xb, 16 }, /* str=0000000000001011 */ + { 0xe, 16 }, /* str=0000000000001110 */ + { 0xd, 16 }, /* str=0000000000001101 */ + { 0x8, 15 }, /* str=000000000001000 */ + }, + { /* i_total 15 */ + { 0x7, 16 }, /* str=0000000000000111 */ + { 0xa, 16 }, /* str=0000000000001010 */ + { 0x9, 16 }, /* str=0000000000001001 */ + { 0xc, 16 }, /* str=0000000000001100 */ + }, + { /* i_total 16 */ + { 0x4, 16 }, /* str=0000000000000100 */ + { 0x6, 16 }, /* str=0000000000000110 */ + { 0x5, 16 }, /* str=0000000000000101 */ + { 0x8, 16 }, /* str=0000000000001000 */ + }, + }, + { /* table 1 */ + { /* i_total 1 */ + { 0xb, 6 }, /* str=001011 */ + { 0x2, 2 }, /* str=10 */ + }, + { /* i_total 2 */ + { 0x7, 6 }, /* str=000111 */ + { 0x7, 5 }, /* str=00111 */ + { 0x3, 3 }, /* str=011 */ + }, + { /* i_total 3 */ + { 0x7, 7 }, /* str=0000111 */ + { 0xa, 6 }, /* str=001010 */ + { 0x9, 6 }, /* str=001001 */ + { 0x5, 4 }, /* str=0101 */ + }, + { /* i_total 4 */ + { 0x7, 8 }, /* str=00000111 */ + { 0x6, 6 }, /* str=000110 */ + { 0x5, 6 }, /* str=000101 */ + { 0x4, 4 }, /* str=0100 */ + }, + { /* i_total 5 */ + { 0x4, 8 }, /* str=00000100 */ + { 0x6, 7 }, /* str=0000110 */ + { 0x5, 7 }, /* str=0000101 */ + { 0x6, 5 }, /* str=00110 */ + }, + { /* i_total 6 */ + { 0x7, 9 }, /* str=000000111 */ + { 0x6, 8 }, /* str=00000110 */ + { 0x5, 8 }, /* str=00000101 */ + { 0x8, 6 }, /* str=001000 */ + }, + { /* i_total 7 */ + { 0xf, 11 }, /* str=00000001111 */ + { 0x6, 9 }, /* str=000000110 */ + { 0x5, 9 }, /* str=000000101 */ + { 0x4, 6 }, /* str=000100 */ + }, + { /* i_total 8 */ + { 0xb, 11 }, /* str=00000001011 */ + { 0xe, 11 }, /* str=00000001110 */ + { 0xd, 11 }, /* str=00000001101 */ + { 0x4, 7 }, /* str=0000100 */ + }, + { /* i_total 9 */ + { 0xf, 12 }, /* str=000000001111 */ + { 0xa, 11 }, /* str=00000001010 */ + { 0x9, 11 }, /* str=00000001001 */ + { 0x4, 9 }, /* str=000000100 */ + }, + { /* i_total 10 */ + { 0xb, 12 }, /* str=000000001011 */ + { 0xe, 12 }, /* str=000000001110 */ + { 0xd, 12 }, /* str=000000001101 */ + { 0xc, 11 }, /* str=00000001100 */ + }, + { /* i_total 11 */ + { 0x8, 12 }, /* str=000000001000 */ + { 0xa, 12 }, /* str=000000001010 */ + { 0x9, 12 }, /* str=000000001001 */ + { 0x8, 11 }, /* str=00000001000 */ + }, + { /* i_total 12 */ + { 0xf, 13 }, /* str=0000000001111 */ + { 0xe, 13 }, /* str=0000000001110 */ + { 0xd, 13 }, /* str=0000000001101 */ + { 0xc, 12 }, /* str=000000001100 */ + }, + { /* i_total 13 */ + { 0xb, 13 }, /* str=0000000001011 */ + { 0xa, 13 }, /* str=0000000001010 */ + { 0x9, 13 }, /* str=0000000001001 */ + { 0xc, 13 }, /* str=0000000001100 */ + }, + { /* i_total 14 */ + { 0x7, 13 }, /* str=0000000000111 */ + { 0xb, 14 }, /* str=00000000001011 */ + { 0x6, 13 }, /* str=0000000000110 */ + { 0x8, 13 }, /* str=0000000001000 */ + }, + { /* i_total 15 */ + { 0x9, 14 }, /* str=00000000001001 */ + { 0x8, 14 }, /* str=00000000001000 */ + { 0xa, 14 }, /* str=00000000001010 */ + { 0x1, 13 }, /* str=0000000000001 */ + }, + { /* i_total 16 */ + { 0x7, 14 }, /* str=00000000000111 */ + { 0x6, 14 }, /* str=00000000000110 */ + { 0x5, 14 }, /* str=00000000000101 */ + { 0x4, 14 }, /* str=00000000000100 */ + }, + }, + { /* table 2 */ + { /* i_total 1 */ + { 0xf, 6 }, /* str=001111 */ + { 0xe, 4 }, /* str=1110 */ + }, + { /* i_total 2 */ + { 0xb, 6 }, /* str=001011 */ + { 0xf, 5 }, /* str=01111 */ + { 0xd, 4 }, /* str=1101 */ + }, + { /* i_total 3 */ + { 0x8, 6 }, /* str=001000 */ + { 0xc, 5 }, /* str=01100 */ + { 0xe, 5 }, /* str=01110 */ + { 0xc, 4 }, /* str=1100 */ + }, + { /* i_total 4 */ + { 0xf, 7 }, /* str=0001111 */ + { 0xa, 5 }, /* str=01010 */ + { 0xb, 5 }, /* str=01011 */ + { 0xb, 4 }, /* str=1011 */ + }, + { /* i_total 5 */ + { 0xb, 7 }, /* str=0001011 */ + { 0x8, 5 }, /* str=01000 */ + { 0x9, 5 }, /* str=01001 */ + { 0xa, 4 }, /* str=1010 */ + }, + { /* i_total 6 */ + { 0x9, 7 }, /* str=0001001 */ + { 0xe, 6 }, /* str=001110 */ + { 0xd, 6 }, /* str=001101 */ + { 0x9, 4 }, /* str=1001 */ + }, + { /* i_total 7 */ + { 0x8, 7 }, /* str=0001000 */ + { 0xa, 6 }, /* str=001010 */ + { 0x9, 6 }, /* str=001001 */ + { 0x8, 4 }, /* str=1000 */ + }, + { /* i_total 8 */ + { 0xf, 8 }, /* str=00001111 */ + { 0xe, 7 }, /* str=0001110 */ + { 0xd, 7 }, /* str=0001101 */ + { 0xd, 5 }, /* str=01101 */ + }, + { /* i_total 9 */ + { 0xb, 8 }, /* str=00001011 */ + { 0xe, 8 }, /* str=00001110 */ + { 0xa, 7 }, /* str=0001010 */ + { 0xc, 6 }, /* str=001100 */ + }, + { /* i_total 10 */ + { 0xf, 9 }, /* str=000001111 */ + { 0xa, 8 }, /* str=00001010 */ + { 0xd, 8 }, /* str=00001101 */ + { 0xc, 7 }, /* str=0001100 */ + }, + { /* i_total 11 */ + { 0xb, 9 }, /* str=000001011 */ + { 0xe, 9 }, /* str=000001110 */ + { 0x9, 8 }, /* str=00001001 */ + { 0xc, 8 }, /* str=00001100 */ + }, + { /* i_total 12 */ + { 0x8, 9 }, /* str=000001000 */ + { 0xa, 9 }, /* str=000001010 */ + { 0xd, 9 }, /* str=000001101 */ + { 0x8, 8 }, /* str=00001000 */ + }, + { /* i_total 13 */ + { 0xd, 10 }, /* str=0000001101 */ + { 0x7, 9 }, /* str=000000111 */ + { 0x9, 9 }, /* str=000001001 */ + { 0xc, 9 }, /* str=000001100 */ + }, + { /* i_total 14 */ + { 0x9, 10 }, /* str=0000001001 */ + { 0xc, 10 }, /* str=0000001100 */ + { 0xb, 10 }, /* str=0000001011 */ + { 0xa, 10 }, /* str=0000001010 */ + }, + { /* i_total 15 */ + { 0x5, 10 }, /* str=0000000101 */ + { 0x8, 10 }, /* str=0000001000 */ + { 0x7, 10 }, /* str=0000000111 */ + { 0x6, 10 }, /* str=0000000110 */ + }, + { /* i_total 16 */ + { 0x1, 10 }, /* str=0000000001 */ + { 0x4, 10 }, /* str=0000000100 */ + { 0x3, 10 }, /* str=0000000011 */ + { 0x2, 10 }, /* str=0000000010 */ + }, + }, + { /* table 3 */ + { /* i_total 1 */ + { 0x0, 6 }, /* str=000000 */ + { 0x1, 6 }, /* str=000001 */ + }, + { /* i_total 2 */ + { 0x4, 6 }, /* str=000100 */ + { 0x5, 6 }, /* str=000101 */ + { 0x6, 6 }, /* str=000110 */ + }, + { /* i_total 3 */ + { 0x8, 6 }, /* str=001000 */ + { 0x9, 6 }, /* str=001001 */ + { 0xa, 6 }, /* str=001010 */ + { 0xb, 6 }, /* str=001011 */ + }, + { /* i_total 4 */ + { 0xc, 6 }, /* str=001100 */ + { 0xd, 6 }, /* str=001101 */ + { 0xe, 6 }, /* str=001110 */ + { 0xf, 6 }, /* str=001111 */ + }, + { /* i_total 5 */ + { 0x10, 6 }, /* str=010000 */ + { 0x11, 6 }, /* str=010001 */ + { 0x12, 6 }, /* str=010010 */ + { 0x13, 6 }, /* str=010011 */ + }, + { /* i_total 6 */ + { 0x14, 6 }, /* str=010100 */ + { 0x15, 6 }, /* str=010101 */ + { 0x16, 6 }, /* str=010110 */ + { 0x17, 6 }, /* str=010111 */ + }, + { /* i_total 7 */ + { 0x18, 6 }, /* str=011000 */ + { 0x19, 6 }, /* str=011001 */ + { 0x1a, 6 }, /* str=011010 */ + { 0x1b, 6 }, /* str=011011 */ + }, + { /* i_total 8 */ + { 0x1c, 6 }, /* str=011100 */ + { 0x1d, 6 }, /* str=011101 */ + { 0x1e, 6 }, /* str=011110 */ + { 0x1f, 6 }, /* str=011111 */ + }, + { /* i_total 9 */ + { 0x20, 6 }, /* str=100000 */ + { 0x21, 6 }, /* str=100001 */ + { 0x22, 6 }, /* str=100010 */ + { 0x23, 6 }, /* str=100011 */ + }, + { /* i_total 10 */ + { 0x24, 6 }, /* str=100100 */ + { 0x25, 6 }, /* str=100101 */ + { 0x26, 6 }, /* str=100110 */ + { 0x27, 6 }, /* str=100111 */ + }, + { /* i_total 11 */ + { 0x28, 6 }, /* str=101000 */ + { 0x29, 6 }, /* str=101001 */ + { 0x2a, 6 }, /* str=101010 */ + { 0x2b, 6 }, /* str=101011 */ + }, + { /* i_total 12 */ + { 0x2c, 6 }, /* str=101100 */ + { 0x2d, 6 }, /* str=101101 */ + { 0x2e, 6 }, /* str=101110 */ + { 0x2f, 6 }, /* str=101111 */ + }, + { /* i_total 13 */ + { 0x30, 6 }, /* str=110000 */ + { 0x31, 6 }, /* str=110001 */ + { 0x32, 6 }, /* str=110010 */ + { 0x33, 6 }, /* str=110011 */ + }, + { /* i_total 14 */ + { 0x34, 6 }, /* str=110100 */ + { 0x35, 6 }, /* str=110101 */ + { 0x36, 6 }, /* str=110110 */ + { 0x37, 6 }, /* str=110111 */ + }, + { /* i_total 15 */ + { 0x38, 6 }, /* str=111000 */ + { 0x39, 6 }, /* str=111001 */ + { 0x3a, 6 }, /* str=111010 */ + { 0x3b, 6 }, /* str=111011 */ + }, + { /* i_total 16 */ + { 0x3c, 6 }, /* str=111100 */ + { 0x3d, 6 }, /* str=111101 */ + { 0x3e, 6 }, /* str=111110 */ + { 0x3f, 6 }, /* str=111111 */ + }, + }, + { /* table 4 */ + { /* i_total 1 */ + { 0x7, 6 }, /* str=000111 */ + { 0x1, 1 }, /* str=1 */ + }, + { /* i_total 2 */ + { 0x4, 6 }, /* str=000100 */ + { 0x6, 6 }, /* str=000110 */ + { 0x1, 3 }, /* str=001 */ + }, + { /* i_total 3 */ + { 0x3, 6 }, /* str=000011 */ + { 0x3, 7 }, /* str=0000011 */ + { 0x2, 7 }, /* str=0000010 */ + { 0x5, 6 }, /* str=000101 */ + }, + { /* i_total 4 */ + { 0x2, 6 }, /* str=000010 */ + { 0x3, 8 }, /* str=00000011 */ + { 0x2, 8 }, /* str=00000010 */ + { 0x0, 7 }, /* str=0000000 */ + }, + }, + { /* table 5 */ + { /* i_total 1 */ + { 0xf, 7 }, /* str=0001111 */ + { 0x1, 2 }, /* str=01 */ + }, + { /* i_total 2 */ + { 0xe, 7 }, /* str=0001110 */ + { 0xd, 7 }, /* str=0001101 */ + { 0x1, 3 }, /* str=001 */ + }, + { /* i_total 3 */ + { 0x7, 9 }, /* str=000000111 */ + { 0xc, 7 }, /* str=0001100 */ + { 0xb, 7 }, /* str=0001011 */ + { 0x1, 5 }, /* str=00001 */ + }, + { /* i_total 4 */ + { 0x6, 9 }, /* str=000000110 */ + { 0x5, 9 }, /* str=000000101 */ + { 0xa, 7 }, /* str=0001010 */ + { 0x1, 6 }, /* str=000001 */ + }, + { /* i_total 5 */ + { 0x7, 10 }, /* str=0000000111 */ + { 0x6, 10 }, /* str=0000000110 */ + { 0x4, 9 }, /* str=000000100 */ + { 0x9, 7 }, /* str=0001001 */ + }, + { /* i_total 6 */ + { 0x7, 11 }, /* str=00000000111 */ + { 0x6, 11 }, /* str=00000000110 */ + { 0x5, 10 }, /* str=0000000101 */ + { 0x8, 7 }, /* str=0001000 */ + }, + { /* i_total 7 */ + { 0x7, 12 }, /* str=000000000111 */ + { 0x6, 12 }, /* str=000000000110 */ + { 0x5, 11 }, /* str=00000000101 */ + { 0x4, 10 }, /* str=0000000100 */ + }, + { /* i_total 8 */ + { 0x7, 13 }, /* str=0000000000111 */ + { 0x5, 12 }, /* str=000000000101 */ + { 0x4, 12 }, /* str=000000000100 */ + { 0x4, 11 }, /* str=00000000100 */ + }, + }, +}; + +/* [i_total_coeff-1][i_total_zeros] */ +const vlc_t x264_total_zeros[15][16] = +{ + { /* i_total 1 */ + { 0x1, 1 }, /* str=1 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 3 }, /* str=010 */ + { 0x3, 4 }, /* str=0011 */ + { 0x2, 4 }, /* str=0010 */ + { 0x3, 5 }, /* str=00011 */ + { 0x2, 5 }, /* str=00010 */ + { 0x3, 6 }, /* str=000011 */ + { 0x2, 6 }, /* str=000010 */ + { 0x3, 7 }, /* str=0000011 */ + { 0x2, 7 }, /* str=0000010 */ + { 0x3, 8 }, /* str=00000011 */ + { 0x2, 8 }, /* str=00000010 */ + { 0x3, 9 }, /* str=000000011 */ + { 0x2, 9 }, /* str=000000010 */ + { 0x1, 9 }, /* str=000000001 */ + }, + { /* i_total 2 */ + { 0x7, 3 }, /* str=111 */ + { 0x6, 3 }, /* str=110 */ + { 0x5, 3 }, /* str=101 */ + { 0x4, 3 }, /* str=100 */ + { 0x3, 3 }, /* str=011 */ + { 0x5, 4 }, /* str=0101 */ + { 0x4, 4 }, /* str=0100 */ + { 0x3, 4 }, /* str=0011 */ + { 0x2, 4 }, /* str=0010 */ + { 0x3, 5 }, /* str=00011 */ + { 0x2, 5 }, /* str=00010 */ + { 0x3, 6 }, /* str=000011 */ + { 0x2, 6 }, /* str=000010 */ + { 0x1, 6 }, /* str=000001 */ + { 0x0, 6 }, /* str=000000 */ + }, + { /* i_total 3 */ + { 0x5, 4 }, /* str=0101 */ + { 0x7, 3 }, /* str=111 */ + { 0x6, 3 }, /* str=110 */ + { 0x5, 3 }, /* str=101 */ + { 0x4, 4 }, /* str=0100 */ + { 0x3, 4 }, /* str=0011 */ + { 0x4, 3 }, /* str=100 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 4 }, /* str=0010 */ + { 0x3, 5 }, /* str=00011 */ + { 0x2, 5 }, /* str=00010 */ + { 0x1, 6 }, /* str=000001 */ + { 0x1, 5 }, /* str=00001 */ + { 0x0, 6 }, /* str=000000 */ + }, + { /* i_total 4 */ + { 0x3, 5 }, /* str=00011 */ + { 0x7, 3 }, /* str=111 */ + { 0x5, 4 }, /* str=0101 */ + { 0x4, 4 }, /* str=0100 */ + { 0x6, 3 }, /* str=110 */ + { 0x5, 3 }, /* str=101 */ + { 0x4, 3 }, /* str=100 */ + { 0x3, 4 }, /* str=0011 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 4 }, /* str=0010 */ + { 0x2, 5 }, /* str=00010 */ + { 0x1, 5 }, /* str=00001 */ + { 0x0, 5 }, /* str=00000 */ + }, + { /* i_total 5 */ + { 0x5, 4 }, /* str=0101 */ + { 0x4, 4 }, /* str=0100 */ + { 0x3, 4 }, /* str=0011 */ + { 0x7, 3 }, /* str=111 */ + { 0x6, 3 }, /* str=110 */ + { 0x5, 3 }, /* str=101 */ + { 0x4, 3 }, /* str=100 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 4 }, /* str=0010 */ + { 0x1, 5 }, /* str=00001 */ + { 0x1, 4 }, /* str=0001 */ + { 0x0, 5 }, /* str=00000 */ + }, + { /* i_total 6 */ + { 0x1, 6 }, /* str=000001 */ + { 0x1, 5 }, /* str=00001 */ + { 0x7, 3 }, /* str=111 */ + { 0x6, 3 }, /* str=110 */ + { 0x5, 3 }, /* str=101 */ + { 0x4, 3 }, /* str=100 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 3 }, /* str=010 */ + { 0x1, 4 }, /* str=0001 */ + { 0x1, 3 }, /* str=001 */ + { 0x0, 6 }, /* str=000000 */ + }, + { /* i_total 7 */ + { 0x1, 6 }, /* str=000001 */ + { 0x1, 5 }, /* str=00001 */ + { 0x5, 3 }, /* str=101 */ + { 0x4, 3 }, /* str=100 */ + { 0x3, 3 }, /* str=011 */ + { 0x3, 2 }, /* str=11 */ + { 0x2, 3 }, /* str=010 */ + { 0x1, 4 }, /* str=0001 */ + { 0x1, 3 }, /* str=001 */ + { 0x0, 6 }, /* str=000000 */ + }, + { /* i_total 8 */ + { 0x1, 6 }, /* str=000001 */ + { 0x1, 4 }, /* str=0001 */ + { 0x1, 5 }, /* str=00001 */ + { 0x3, 3 }, /* str=011 */ + { 0x3, 2 }, /* str=11 */ + { 0x2, 2 }, /* str=10 */ + { 0x2, 3 }, /* str=010 */ + { 0x1, 3 }, /* str=001 */ + { 0x0, 6 }, /* str=000000 */ + }, + { /* i_total 9 */ + { 0x1, 6 }, /* str=000001 */ + { 0x0, 6 }, /* str=000000 */ + { 0x1, 4 }, /* str=0001 */ + { 0x3, 2 }, /* str=11 */ + { 0x2, 2 }, /* str=10 */ + { 0x1, 3 }, /* str=001 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 5 }, /* str=00001 */ + }, + { /* i_total 10 */ + { 0x1, 5 }, /* str=00001 */ + { 0x0, 5 }, /* str=00000 */ + { 0x1, 3 }, /* str=001 */ + { 0x3, 2 }, /* str=11 */ + { 0x2, 2 }, /* str=10 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 4 }, /* str=0001 */ + }, + { /* i_total 11 */ + { 0x0, 4 }, /* str=0000 */ + { 0x1, 4 }, /* str=0001 */ + { 0x1, 3 }, /* str=001 */ + { 0x2, 3 }, /* str=010 */ + { 0x1, 1 }, /* str=1 */ + { 0x3, 3 }, /* str=011 */ + }, + { /* i_total 12 */ + { 0x0, 4 }, /* str=0000 */ + { 0x1, 4 }, /* str=0001 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 1 }, /* str=1 */ + { 0x1, 3 }, /* str=001 */ + }, + { /* i_total 13 */ + { 0x0, 3 }, /* str=000 */ + { 0x1, 3 }, /* str=001 */ + { 0x1, 1 }, /* str=1 */ + { 0x1, 2 }, /* str=01 */ + }, + { /* i_total 14 */ + { 0x0, 2 }, /* str=00 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 1 }, /* str=1 */ + }, + { /* i_total 15 */ + { 0x0, 1 }, /* str=0 */ + { 0x1, 1 }, /* str=1 */ + }, +}; + +/* [i_total_coeff-1][i_total_zeros] */ +const vlc_t x264_total_zeros_2x2_dc[3][4] = +{ + { /* i_total 1 */ + { 0x1, 1 }, /* str=1 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 3 }, /* str=001 */ + { 0x0, 3 } /* str=000 */ + }, + { /* i_total 2 */ + { 0x1, 1 }, /* str=1 */ + { 0x1, 2 }, /* str=01 */ + { 0x0, 2 }, /* str=00 */ + }, + { /* i_total 3 */ + { 0x1, 1 }, /* str=1 */ + { 0x0, 1 }, /* str=0 */ + }, +}; + +/* [i_total_coeff-1][i_total_zeros] */ +const vlc_t x264_total_zeros_2x4_dc[7][8] = +{ + { /* i_total 1 */ + { 0x1, 1 }, /* str=1 */ + { 0x2, 3 }, /* str=010 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 4 }, /* str=0010 */ + { 0x3, 4 }, /* str=0011 */ + { 0x1, 4 }, /* str=0001 */ + { 0x1, 5 }, /* str=00001 */ + { 0x0, 5 }, /* str=00000 */ + }, + { /* i_total 2 */ + { 0x0, 3 }, /* str=000 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 3 }, /* str=001 */ + { 0x4, 3 }, /* str=100 */ + { 0x5, 3 }, /* str=101 */ + { 0x6, 3 }, /* str=110 */ + { 0x7, 3 }, /* str=111 */ + }, + { /* i_total 3 */ + { 0x0, 3 }, /* str=000 */ + { 0x1, 3 }, /* str=001 */ + { 0x1, 2 }, /* str=01 */ + { 0x2, 2 }, /* str=10 */ + { 0x6, 3 }, /* str=110 */ + { 0x7, 3 }, /* str=111 */ + }, + { /* i_total 4 */ + { 0x6, 3 }, /* str=110 */ + { 0x0, 2 }, /* str=00 */ + { 0x1, 2 }, /* str=01 */ + { 0x2, 2 }, /* str=10 */ + { 0x7, 3 }, /* str=111 */ + }, + { /* i_total 5 */ + { 0x0, 2 }, /* str=00 */ + { 0x1, 2 }, /* str=01 */ + { 0x2, 2 }, /* str=10 */ + { 0x3, 2 }, /* str=11 */ + }, + { /* i_total 6 */ + { 0x0, 2 }, /* str=00 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 1 }, /* str=1 */ + }, + { /* i_total 7 */ + { 0x0, 1 }, /* str=0 */ + { 0x1, 1 }, /* str=1 */ + } +}; + +/* [MIN( i_zero_left-1, 6 )][run_before] */ +static const vlc_t run_before[7][16] = +{ + { /* i_zero_left 1 */ + { 0x1, 1 }, /* str=1 */ + { 0x0, 1 }, /* str=0 */ + }, + { /* i_zero_left 2 */ + { 0x1, 1 }, /* str=1 */ + { 0x1, 2 }, /* str=01 */ + { 0x0, 2 }, /* str=00 */ + }, + { /* i_zero_left 3 */ + { 0x3, 2 }, /* str=11 */ + { 0x2, 2 }, /* str=10 */ + { 0x1, 2 }, /* str=01 */ + { 0x0, 2 }, /* str=00 */ + }, + { /* i_zero_left 4 */ + { 0x3, 2 }, /* str=11 */ + { 0x2, 2 }, /* str=10 */ + { 0x1, 2 }, /* str=01 */ + { 0x1, 3 }, /* str=001 */ + { 0x0, 3 }, /* str=000 */ + }, + { /* i_zero_left 5 */ + { 0x3, 2 }, /* str=11 */ + { 0x2, 2 }, /* str=10 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 3 }, /* str=010 */ + { 0x1, 3 }, /* str=001 */ + { 0x0, 3 }, /* str=000 */ + }, + { /* i_zero_left 6 */ + { 0x3, 2 }, /* str=11 */ + { 0x0, 3 }, /* str=000 */ + { 0x1, 3 }, /* str=001 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 3 }, /* str=010 */ + { 0x5, 3 }, /* str=101 */ + { 0x4, 3 }, /* str=100 */ + }, + { /* i_zero_left >6 */ + { 0x7, 3 }, /* str=111 */ + { 0x6, 3 }, /* str=110 */ + { 0x5, 3 }, /* str=101 */ + { 0x4, 3 }, /* str=100 */ + { 0x3, 3 }, /* str=011 */ + { 0x2, 3 }, /* str=010 */ + { 0x1, 3 }, /* str=001 */ + { 0x1, 4 }, /* str=0001 */ + { 0x1, 5 }, /* str=00001 */ + { 0x1, 6 }, /* str=000001 */ + { 0x1, 7 }, /* str=0000001 */ + { 0x1, 8 }, /* str=00000001 */ + { 0x1, 9 }, /* str=000000001 */ + { 0x1, 10 }, /* str=0000000001 */ + { 0x1, 11 }, /* str=00000000001 */ + }, +}; + +vlc_large_t x264_level_token[7][LEVEL_TABLE_SIZE]; +uint32_t x264_run_before[1<<16]; + +void x264_cavlc_init( x264_t *h ) +{ + for( int i_suffix = 0; i_suffix < 7; i_suffix++ ) + for( int16_t level = -LEVEL_TABLE_SIZE/2; level < LEVEL_TABLE_SIZE/2; level++ ) + { + int mask = level >> 15; + int abs_level = (level^mask)-mask; + int i_level_code = abs_level*2-mask-2; + int i_next = i_suffix; + vlc_large_t *vlc = &x264_level_token[i_suffix][level+LEVEL_TABLE_SIZE/2]; + + if( ( i_level_code >> i_suffix ) < 14 ) + { + vlc->i_size = (i_level_code >> i_suffix) + 1 + i_suffix; + vlc->i_bits = (1<i_size = 19; + vlc->i_bits = (1<<4) + (i_level_code - 14); + } + else if( i_suffix > 0 && ( i_level_code >> i_suffix ) == 14 ) + { + vlc->i_size = 15 + i_suffix; + vlc->i_bits = (1<i_size = 28; + vlc->i_bits = (1<<12) + i_level_code; + } + if( i_next == 0 ) + i_next++; + if( abs_level > (3 << (i_next-1)) && i_next < 6 ) + i_next++; + vlc->i_next = i_next; + } + + for( int i = 1; i < (1<<16); i++ ) + { + x264_run_level_t runlevel; + ALIGNED_ARRAY_16( dctcoef, dct, [16] ); + int size = 0; + int bits = 0; + for( int j = 0; j < 16; j++ ) + dct[j] = i&(1<quantf.coeff_level_run[DCT_LUMA_4x4]( dct, &runlevel ); + int zeros = runlevel.last + 1 - total; + uint32_t mask = i << (x264_clz( i ) + 1); + for( int j = 0; j < total-1 && zeros > 0; j++ ) + { + int idx = X264_MIN(zeros, 7) - 1; + int run = x264_clz( mask ); + int len = run_before[idx][run].i_size; + size += len; + bits <<= len; + bits |= run_before[idx][run].i_bits; + zeros -= run; + mask <<= run + 1; + } + x264_run_before[i] = (bits << 5) + size; + } +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/win32thread.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/win32thread.c new file mode 100644 index 00000000..94e9d898 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/win32thread.c @@ -0,0 +1,357 @@ +/***************************************************************************** + * win32thread.c: windows threading + ***************************************************************************** + * Copyright (C) 2010-2017 x264 project + * + * Authors: Steven Walters + * Pegasys Inc. + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +/* Microsoft's way of supporting systems with >64 logical cpus can be found at + * http://www.microsoft.com/whdc/system/Sysinternals/MoreThan64proc.mspx */ + +/* Based on the agreed standing that x264 does not need to utilize >64 logical cpus, + * this API does not detect nor utilize more than 64 cpus for systems that have them. */ + +#include "common.h" + +#if HAVE_WINRT +/* _beginthreadex() is technically the correct option, but it's only available for Desktop applications. + * Using CreateThread() as an alternative works on Windows Store and Windows Phone 8.1+ as long as we're + * using a dynamically linked MSVCRT which happens to be a requirement for WinRT applications anyway */ +#define _beginthreadex CreateThread +#define InitializeCriticalSectionAndSpinCount(a, b) InitializeCriticalSectionEx(a, b, CRITICAL_SECTION_NO_DEBUG_INFO) +#define WaitForSingleObject(a, b) WaitForSingleObjectEx(a, b, FALSE) +#else +#include +#endif + +/* number of times to spin a thread about to block on a locked mutex before retrying and sleeping if still locked */ +#define X264_SPIN_COUNT 0 + +/* global mutex for replacing MUTEX_INITIALIZER instances */ +static x264_pthread_mutex_t static_mutex; + +/* _beginthreadex requires that the start routine is __stdcall */ +static unsigned __stdcall x264_win32thread_worker( void *arg ) +{ + x264_pthread_t *h = arg; + *h->p_ret = h->func( h->arg ); + return 0; +} + +int x264_pthread_create( x264_pthread_t *thread, const x264_pthread_attr_t *attr, + void *(*start_routine)( void* ), void *arg ) +{ + thread->func = start_routine; + thread->arg = arg; + thread->p_ret = &thread->ret; + thread->ret = NULL; + thread->handle = (void*)_beginthreadex( NULL, 0, x264_win32thread_worker, thread, 0, NULL ); + return !thread->handle; +} + +int x264_pthread_join( x264_pthread_t thread, void **value_ptr ) +{ + DWORD ret = WaitForSingleObject( thread.handle, INFINITE ); + if( ret != WAIT_OBJECT_0 ) + return -1; + if( value_ptr ) + *value_ptr = *thread.p_ret; + CloseHandle( thread.handle ); + return 0; +} + +int x264_pthread_mutex_init( x264_pthread_mutex_t *mutex, const x264_pthread_mutexattr_t *attr ) +{ + return !InitializeCriticalSectionAndSpinCount( mutex, X264_SPIN_COUNT ); +} + +int x264_pthread_mutex_destroy( x264_pthread_mutex_t *mutex ) +{ + DeleteCriticalSection( mutex ); + return 0; +} + +int x264_pthread_mutex_lock( x264_pthread_mutex_t *mutex ) +{ + static const x264_pthread_mutex_t init = X264_PTHREAD_MUTEX_INITIALIZER; + if( !memcmp( mutex, &init, sizeof(x264_pthread_mutex_t) ) ) + *mutex = static_mutex; + EnterCriticalSection( mutex ); + return 0; +} + +int x264_pthread_mutex_unlock( x264_pthread_mutex_t *mutex ) +{ + LeaveCriticalSection( mutex ); + return 0; +} + +void x264_win32_threading_destroy( void ) +{ + x264_pthread_mutex_destroy( &static_mutex ); + memset( &static_mutex, 0, sizeof(static_mutex) ); +} + +#if HAVE_WINRT +int x264_pthread_cond_init( x264_pthread_cond_t *cond, const x264_pthread_condattr_t *attr ) +{ + InitializeConditionVariable( cond ); + return 0; +} + +int x264_pthread_cond_destroy( x264_pthread_cond_t *cond ) +{ + return 0; +} + +int x264_pthread_cond_broadcast( x264_pthread_cond_t *cond ) +{ + WakeAllConditionVariable( cond ); + return 0; +} + +int x264_pthread_cond_signal( x264_pthread_cond_t *cond ) +{ + WakeConditionVariable( cond ); + return 0; +} + +int x264_pthread_cond_wait( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mutex ) +{ + return !SleepConditionVariableCS( cond, mutex, INFINITE ); +} + +int x264_win32_threading_init( void ) +{ + return x264_pthread_mutex_init( &static_mutex, NULL ); +} + +int x264_pthread_num_processors_np( void ) +{ + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + return si.dwNumberOfProcessors; +} + +#else + +static struct +{ + /* function pointers to conditional variable API on windows 6.0+ kernels */ + void (WINAPI *cond_broadcast)( x264_pthread_cond_t *cond ); + void (WINAPI *cond_init)( x264_pthread_cond_t *cond ); + void (WINAPI *cond_signal)( x264_pthread_cond_t *cond ); + BOOL (WINAPI *cond_wait)( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mutex, DWORD milliseconds ); +} thread_control; + +/* for pre-Windows 6.0 platforms we need to define and use our own condition variable and api */ +typedef struct +{ + x264_pthread_mutex_t mtx_broadcast; + x264_pthread_mutex_t mtx_waiter_count; + volatile int waiter_count; + HANDLE semaphore; + HANDLE waiters_done; + volatile int is_broadcast; +} x264_win32_cond_t; + +int x264_pthread_cond_init( x264_pthread_cond_t *cond, const x264_pthread_condattr_t *attr ) +{ + if( thread_control.cond_init ) + { + thread_control.cond_init( cond ); + return 0; + } + + /* non native condition variables */ + x264_win32_cond_t *win32_cond = calloc( 1, sizeof(x264_win32_cond_t) ); + if( !win32_cond ) + return -1; + cond->Ptr = win32_cond; + win32_cond->semaphore = CreateSemaphoreW( NULL, 0, 0x7fffffff, NULL ); + if( !win32_cond->semaphore ) + return -1; + + if( x264_pthread_mutex_init( &win32_cond->mtx_waiter_count, NULL ) ) + return -1; + if( x264_pthread_mutex_init( &win32_cond->mtx_broadcast, NULL ) ) + return -1; + + win32_cond->waiters_done = CreateEventW( NULL, FALSE, FALSE, NULL ); + if( !win32_cond->waiters_done ) + return -1; + + return 0; +} + +int x264_pthread_cond_destroy( x264_pthread_cond_t *cond ) +{ + /* native condition variables do not destroy */ + if( thread_control.cond_init ) + return 0; + + /* non native condition variables */ + x264_win32_cond_t *win32_cond = cond->Ptr; + CloseHandle( win32_cond->semaphore ); + CloseHandle( win32_cond->waiters_done ); + x264_pthread_mutex_destroy( &win32_cond->mtx_broadcast ); + x264_pthread_mutex_destroy( &win32_cond->mtx_waiter_count ); + free( win32_cond ); + + return 0; +} + +int x264_pthread_cond_broadcast( x264_pthread_cond_t *cond ) +{ + if( thread_control.cond_broadcast ) + { + thread_control.cond_broadcast( cond ); + return 0; + } + + /* non native condition variables */ + x264_win32_cond_t *win32_cond = cond->Ptr; + x264_pthread_mutex_lock( &win32_cond->mtx_broadcast ); + x264_pthread_mutex_lock( &win32_cond->mtx_waiter_count ); + int have_waiter = 0; + + if( win32_cond->waiter_count ) + { + win32_cond->is_broadcast = 1; + have_waiter = 1; + } + + if( have_waiter ) + { + ReleaseSemaphore( win32_cond->semaphore, win32_cond->waiter_count, NULL ); + x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count ); + WaitForSingleObject( win32_cond->waiters_done, INFINITE ); + win32_cond->is_broadcast = 0; + } + else + x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count ); + return x264_pthread_mutex_unlock( &win32_cond->mtx_broadcast ); +} + +int x264_pthread_cond_signal( x264_pthread_cond_t *cond ) +{ + if( thread_control.cond_signal ) + { + thread_control.cond_signal( cond ); + return 0; + } + + /* non-native condition variables */ + x264_win32_cond_t *win32_cond = cond->Ptr; + + x264_pthread_mutex_lock( &win32_cond->mtx_broadcast ); + x264_pthread_mutex_lock( &win32_cond->mtx_waiter_count ); + int have_waiter = win32_cond->waiter_count; + x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count ); + + if( have_waiter ) + { + ReleaseSemaphore( win32_cond->semaphore, 1, NULL ); + WaitForSingleObject( win32_cond->waiters_done, INFINITE ); + } + + return x264_pthread_mutex_unlock( &win32_cond->mtx_broadcast ); +} + +int x264_pthread_cond_wait( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mutex ) +{ + if( thread_control.cond_wait ) + return !thread_control.cond_wait( cond, mutex, INFINITE ); + + /* non native condition variables */ + x264_win32_cond_t *win32_cond = cond->Ptr; + + x264_pthread_mutex_lock( &win32_cond->mtx_broadcast ); + x264_pthread_mutex_lock( &win32_cond->mtx_waiter_count ); + win32_cond->waiter_count++; + x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count ); + x264_pthread_mutex_unlock( &win32_cond->mtx_broadcast ); + + // unlock the external mutex + x264_pthread_mutex_unlock( mutex ); + WaitForSingleObject( win32_cond->semaphore, INFINITE ); + + x264_pthread_mutex_lock( &win32_cond->mtx_waiter_count ); + win32_cond->waiter_count--; + int last_waiter = !win32_cond->waiter_count || !win32_cond->is_broadcast; + x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count ); + + if( last_waiter ) + SetEvent( win32_cond->waiters_done ); + + // lock the external mutex + return x264_pthread_mutex_lock( mutex ); +} + +int x264_win32_threading_init( void ) +{ + /* find function pointers to API functions, if they exist */ + HANDLE kernel_dll = GetModuleHandleW( L"kernel32.dll" ); + thread_control.cond_init = (void*)GetProcAddress( kernel_dll, "InitializeConditionVariable" ); + if( thread_control.cond_init ) + { + /* we're on a windows 6.0+ kernel, acquire the rest of the functions */ + thread_control.cond_broadcast = (void*)GetProcAddress( kernel_dll, "WakeAllConditionVariable" ); + thread_control.cond_signal = (void*)GetProcAddress( kernel_dll, "WakeConditionVariable" ); + thread_control.cond_wait = (void*)GetProcAddress( kernel_dll, "SleepConditionVariableCS" ); + } + return x264_pthread_mutex_init( &static_mutex, NULL ); +} + +int x264_pthread_num_processors_np( void ) +{ + DWORD_PTR system_cpus, process_cpus = 0; + int cpus = 0; + + /* GetProcessAffinityMask returns affinities of 0 when the process has threads in multiple processor groups. + * On platforms that support processor grouping, use GetThreadGroupAffinity to get the current thread's affinity instead. */ +#if ARCH_X86_64 + /* find function pointers to API functions specific to x86_64 platforms, if they exist */ + HANDLE kernel_dll = GetModuleHandleW( L"kernel32.dll" ); + BOOL (*get_thread_affinity)( HANDLE thread, void *group_affinity ) = (void*)GetProcAddress( kernel_dll, "GetThreadGroupAffinity" ); + if( get_thread_affinity ) + { + /* running on a platform that supports >64 logical cpus */ + struct /* GROUP_AFFINITY */ + { + ULONG_PTR mask; // KAFFINITY = ULONG_PTR + USHORT group; + USHORT reserved[3]; + } thread_affinity; + if( get_thread_affinity( GetCurrentThread(), &thread_affinity ) ) + process_cpus = thread_affinity.mask; + } +#endif + if( !process_cpus ) + GetProcessAffinityMask( GetCurrentProcess(), &process_cpus, &system_cpus ); + for( DWORD_PTR bit = 1; bit; bit <<= 1 ) + cpus += !!(process_cpus & bit); + + return cpus ? cpus : 1; +} +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/win32thread.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/win32thread.h new file mode 100644 index 00000000..44a7241b --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/win32thread.h @@ -0,0 +1,81 @@ +/***************************************************************************** + * win32thread.h: windows threading + ***************************************************************************** + * Copyright (C) 2010-2017 x264 project + * + * Authors: Steven Walters + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_WIN32THREAD_H +#define X264_WIN32THREAD_H + +#include +/* the following macro is used within x264 */ +#undef ERROR + +typedef struct +{ + void *handle; + void *(*func)( void* arg ); + void *arg; + void **p_ret; + void *ret; +} x264_pthread_t; +#define x264_pthread_attr_t int + +/* the conditional variable api for windows 6.0+ uses critical sections and not mutexes */ +typedef CRITICAL_SECTION x264_pthread_mutex_t; +#define X264_PTHREAD_MUTEX_INITIALIZER {0} +#define x264_pthread_mutexattr_t int + +#if HAVE_WINRT +typedef CONDITION_VARIABLE x264_pthread_cond_t; +#else +typedef struct +{ + void *Ptr; +} x264_pthread_cond_t; +#endif +#define x264_pthread_condattr_t int + +int x264_pthread_create( x264_pthread_t *thread, const x264_pthread_attr_t *attr, + void *(*start_routine)( void* ), void *arg ); +int x264_pthread_join( x264_pthread_t thread, void **value_ptr ); + +int x264_pthread_mutex_init( x264_pthread_mutex_t *mutex, const x264_pthread_mutexattr_t *attr ); +int x264_pthread_mutex_destroy( x264_pthread_mutex_t *mutex ); +int x264_pthread_mutex_lock( x264_pthread_mutex_t *mutex ); +int x264_pthread_mutex_unlock( x264_pthread_mutex_t *mutex ); + +int x264_pthread_cond_init( x264_pthread_cond_t *cond, const x264_pthread_condattr_t *attr ); +int x264_pthread_cond_destroy( x264_pthread_cond_t *cond ); +int x264_pthread_cond_broadcast( x264_pthread_cond_t *cond ); +int x264_pthread_cond_wait( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mutex ); +int x264_pthread_cond_signal( x264_pthread_cond_t *cond ); + +#define x264_pthread_attr_init(a) 0 +#define x264_pthread_attr_destroy(a) 0 + +int x264_win32_threading_init( void ); +void x264_win32_threading_destroy( void ); + +int x264_pthread_num_processors_np( void ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/dct.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/dct.h new file mode 100644 index 00000000..20a65c53 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/dct.h @@ -0,0 +1,144 @@ +/***************************************************************************** + * dct.h: x86 transform and zigzag + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_I386_DCT_H +#define X264_I386_DCT_H + +void x264_sub4x4_dct_mmx ( dctcoef dct [16], pixel *pix1, pixel *pix2 ); +void x264_sub8x8_dct_mmx ( dctcoef dct[ 4][16], pixel *pix1, pixel *pix2 ); +void x264_sub16x16_dct_mmx ( dctcoef dct[16][16], pixel *pix1, pixel *pix2 ); +void x264_sub8x8_dct_sse2 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct_sse2 ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub4x4_dct_ssse3 ( int16_t dct [16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub4x4_dct_avx512 ( int16_t dct [16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_ssse3 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct_ssse3( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_avx ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct_avx ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_xop ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct_xop ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_avx2 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_avx512 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct_avx2 ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct_avx512( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_dc_mmx2 ( int16_t dct [ 4], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct_dc_sse2 ( dctcoef dct [ 4], pixel *pix1, pixel *pix2 ); +void x264_sub8x8_dct_dc_avx512 ( int16_t dct [ 4], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x16_dct_dc_sse2 ( dctcoef dct [ 8], pixel *pix1, pixel *pix2 ); +void x264_sub8x16_dct_dc_ssse3 ( int16_t dct [ 8], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x16_dct_dc_avx ( dctcoef dct [ 8], pixel *pix1, pixel *pix2 ); +void x264_sub8x16_dct_dc_avx512( int16_t dct [ 8], uint8_t *pix1, uint8_t *pix2 ); + +void x264_add4x4_idct_mmx ( uint8_t *p_dst, int16_t dct [16] ); +void x264_add4x4_idct_sse2 ( uint16_t *p_dst, int32_t dct [16] ); +void x264_add4x4_idct_sse4 ( uint8_t *p_dst, int16_t dct [16] ); +void x264_add4x4_idct_avx ( pixel *p_dst, dctcoef dct [16] ); +void x264_add8x8_idct_mmx ( uint8_t *p_dst, int16_t dct[ 4][16] ); +void x264_add8x8_idct_dc_mmx2 ( uint8_t *p_dst, int16_t dct [ 4] ); +void x264_add16x16_idct_mmx ( uint8_t *p_dst, int16_t dct[16][16] ); +void x264_add16x16_idct_dc_mmx2 ( uint8_t *p_dst, int16_t dct [16] ); +void x264_add8x8_idct_sse2 ( pixel *p_dst, dctcoef dct[ 4][16] ); +void x264_add8x8_idct_avx ( pixel *p_dst, dctcoef dct[ 4][16] ); +void x264_add8x8_idct_avx2 ( pixel *p_dst, dctcoef dct[ 4][16] ); +void x264_add8x8_idct_avx512 ( uint8_t *p_dst, int16_t dct[ 4][16] ); +void x264_add16x16_idct_sse2 ( pixel *p_dst, dctcoef dct[16][16] ); +void x264_add16x16_idct_avx ( pixel *p_dst, dctcoef dct[16][16] ); +void x264_add16x16_idct_avx2 ( pixel *p_dst, dctcoef dct[16][16] ); +void x264_add8x8_idct_dc_sse2 ( pixel *p_dst, dctcoef dct [ 4] ); +void x264_add16x16_idct_dc_sse2 ( pixel *p_dst, dctcoef dct [16] ); +void x264_add8x8_idct_dc_ssse3 ( uint8_t *p_dst, int16_t dct [ 4] ); +void x264_add16x16_idct_dc_ssse3( uint8_t *p_dst, int16_t dct [16] ); +void x264_add8x8_idct_dc_avx ( pixel *p_dst, dctcoef dct [ 4] ); +void x264_add16x16_idct_dc_avx ( pixel *p_dst, dctcoef dct [16] ); +void x264_add16x16_idct_dc_avx2 ( uint8_t *p_dst, int16_t dct [16] ); + +void x264_dct4x4dc_mmx2 ( int16_t d[16] ); +void x264_dct4x4dc_sse2 ( int32_t d[16] ); +void x264_dct4x4dc_avx ( int32_t d[16] ); +void x264_idct4x4dc_mmx ( int16_t d[16] ); +void x264_idct4x4dc_sse2 ( int32_t d[16] ); +void x264_idct4x4dc_avx ( int32_t d[16] ); + +void x264_dct2x4dc_mmx2( dctcoef dct[8], dctcoef dct4x4[8][16] ); +void x264_dct2x4dc_sse2( dctcoef dct[8], dctcoef dct4x4[8][16] ); +void x264_dct2x4dc_avx ( dctcoef dct[8], dctcoef dct4x4[8][16] ); + +void x264_sub8x8_dct8_mmx ( int16_t dct [64], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct8_mmx ( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct8_sse2 ( dctcoef dct [64], pixel *pix1, pixel *pix2 ); +void x264_sub16x16_dct8_sse2 ( dctcoef dct[4][64], pixel *pix1, pixel *pix2 ); +void x264_sub8x8_dct8_ssse3 ( int16_t dct [64], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub16x16_dct8_ssse3( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix2 ); +void x264_sub8x8_dct8_sse4 ( int32_t dct [64], uint16_t *pix1, uint16_t *pix2 ); +void x264_sub16x16_dct8_sse4 ( int32_t dct[4][64], uint16_t *pix1, uint16_t *pix2 ); +void x264_sub8x8_dct8_avx ( dctcoef dct [64], pixel *pix1, pixel *pix2 ); +void x264_sub16x16_dct8_avx ( dctcoef dct[4][64], pixel *pix1, pixel *pix2 ); +void x264_sub16x16_dct8_avx2 ( dctcoef dct[4][64], pixel *pix1, pixel *pix2 ); + + +void x264_add8x8_idct8_mmx ( uint8_t *dst, int16_t dct [64] ); +void x264_add16x16_idct8_mmx ( uint8_t *dst, int16_t dct[4][64] ); +void x264_add8x8_idct8_sse2 ( pixel *dst, dctcoef dct [64] ); +void x264_add16x16_idct8_sse2( pixel *dst, dctcoef dct[4][64] ); +void x264_add8x8_idct8_avx ( pixel *dst, dctcoef dct [64] ); +void x264_add16x16_idct8_avx ( pixel *dst, dctcoef dct[4][64] ); + +void x264_zigzag_scan_8x8_frame_mmx2 ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_frame_sse2 ( dctcoef level[64], dctcoef dct[64] ); +void x264_zigzag_scan_8x8_frame_ssse3 ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_frame_avx ( dctcoef level[64], dctcoef dct[64] ); +void x264_zigzag_scan_8x8_frame_xop ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_frame_avx512( dctcoef level[64], dctcoef dct[64] ); +void x264_zigzag_scan_4x4_frame_mmx ( int16_t level[16], int16_t dct[16] ); +void x264_zigzag_scan_4x4_frame_sse2 ( int32_t level[16], int32_t dct[16] ); +void x264_zigzag_scan_4x4_frame_ssse3 ( int16_t level[16], int16_t dct[16] ); +void x264_zigzag_scan_4x4_frame_avx ( dctcoef level[16], dctcoef dct[16] ); +void x264_zigzag_scan_4x4_frame_xop ( dctcoef level[16], dctcoef dct[16] ); +void x264_zigzag_scan_4x4_frame_avx512( dctcoef level[16], dctcoef dct[16] ); +void x264_zigzag_scan_4x4_field_sse ( int16_t level[16], int16_t dct[16] ); +void x264_zigzag_scan_4x4_field_sse2 ( int32_t level[16], int32_t dct[16] ); +void x264_zigzag_scan_4x4_field_avx512( dctcoef level[16], dctcoef dct[16] ); +void x264_zigzag_scan_8x8_field_mmx2 ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_field_sse4 ( int32_t level[64], int32_t dct[64] ); +void x264_zigzag_scan_8x8_field_avx ( int32_t level[64], int32_t dct[64] ); +void x264_zigzag_scan_8x8_field_xop ( int16_t level[64], int16_t dct[64] ); +void x264_zigzag_scan_8x8_field_avx512( dctcoef level[64], dctcoef dct[64] ); +int x264_zigzag_sub_4x4_frame_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst ); +int x264_zigzag_sub_4x4_frame_ssse3 ( int16_t level[16], const uint8_t *src, uint8_t *dst ); +int x264_zigzag_sub_4x4ac_frame_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc ); +int x264_zigzag_sub_4x4ac_frame_ssse3( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc ); +int x264_zigzag_sub_4x4_field_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst ); +int x264_zigzag_sub_4x4_field_ssse3 ( int16_t level[16], const uint8_t *src, uint8_t *dst ); +int x264_zigzag_sub_4x4ac_field_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc ); +int x264_zigzag_sub_4x4ac_field_ssse3( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc ); +void x264_zigzag_interleave_8x8_cavlc_mmx ( int16_t *dst, int16_t *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_sse2 ( dctcoef *dst, dctcoef *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_avx ( dctcoef *dst, dctcoef *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_avx2 ( int16_t *dst, int16_t *src, uint8_t *nnz ); +void x264_zigzag_interleave_8x8_cavlc_avx512( dctcoef *dst, dctcoef *src, uint8_t *nnz ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/mc-c.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/mc-c.c new file mode 100644 index 00000000..c06691c9 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/mc-c.c @@ -0,0 +1,911 @@ +/***************************************************************************** + * mc-c.c: x86 motion compensation + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "mc.h" + +#define DECL_SUF( func, args )\ + void func##_mmx2 args;\ + void func##_sse2 args;\ + void func##_ssse3 args;\ + void func##_avx2 args;\ + void func##_avx512 args; + +DECL_SUF( x264_pixel_avg_16x16, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) +DECL_SUF( x264_pixel_avg_16x8, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) +DECL_SUF( x264_pixel_avg_8x16, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) +DECL_SUF( x264_pixel_avg_8x8, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) +DECL_SUF( x264_pixel_avg_8x4, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) +DECL_SUF( x264_pixel_avg_4x16, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) +DECL_SUF( x264_pixel_avg_4x8, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) +DECL_SUF( x264_pixel_avg_4x4, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) +DECL_SUF( x264_pixel_avg_4x2, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int )) + +#define MC_WEIGHT(w,type) \ + void x264_mc_weight_w##w##_##type( pixel *, intptr_t, pixel *, intptr_t, const x264_weight_t *, int ); + +#define MC_WEIGHT_OFFSET(w,type) \ + void x264_mc_offsetadd_w##w##_##type( pixel *, intptr_t, pixel *, intptr_t, const x264_weight_t *, int ); \ + void x264_mc_offsetsub_w##w##_##type( pixel *, intptr_t, pixel *, intptr_t, const x264_weight_t *, int ); \ + MC_WEIGHT(w,type) + +MC_WEIGHT_OFFSET( 4, mmx2 ) +MC_WEIGHT_OFFSET( 8, mmx2 ) +MC_WEIGHT_OFFSET( 12, mmx2 ) +MC_WEIGHT_OFFSET( 16, mmx2 ) +MC_WEIGHT_OFFSET( 20, mmx2 ) +MC_WEIGHT_OFFSET( 12, sse2 ) +MC_WEIGHT_OFFSET( 16, sse2 ) +MC_WEIGHT_OFFSET( 20, sse2 ) +#if HIGH_BIT_DEPTH +MC_WEIGHT_OFFSET( 8, sse2 ) +#endif +MC_WEIGHT( 8, sse2 ) +MC_WEIGHT( 4, ssse3 ) +MC_WEIGHT( 8, ssse3 ) +MC_WEIGHT( 12, ssse3 ) +MC_WEIGHT( 16, ssse3 ) +MC_WEIGHT( 20, ssse3 ) +MC_WEIGHT( 8, avx2 ) +MC_WEIGHT( 16, avx2 ) +MC_WEIGHT( 20, avx2 ) +#undef MC_OFFSET +#undef MC_WEIGHT + +void x264_mc_copy_w4_mmx ( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w8_mmx ( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w8_sse ( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w16_mmx( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w16_sse( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w16_aligned_sse( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w16_avx( uint16_t *, intptr_t, uint16_t *, intptr_t, int ); +void x264_mc_copy_w16_aligned_avx( uint16_t *, intptr_t, uint16_t *, intptr_t, int ); +void x264_prefetch_fenc_420_mmx2( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_prefetch_fenc_422_mmx2( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_prefetch_ref_mmx2( pixel *, intptr_t, int ); +void x264_plane_copy_core_sse( pixel *, intptr_t, pixel *, intptr_t, int w, int h ); +void x264_plane_copy_core_avx( pixel *, intptr_t, pixel *, intptr_t, int w, int h ); +void x264_plane_copy_swap_core_ssse3( pixel *, intptr_t, pixel *, intptr_t, int w, int h ); +void x264_plane_copy_swap_core_avx2 ( pixel *, intptr_t, pixel *, intptr_t, int w, int h ); +void x264_plane_copy_interleave_core_mmx2( pixel *dst, intptr_t i_dst, + pixel *srcu, intptr_t i_srcu, + pixel *srcv, intptr_t i_srcv, int w, int h ); +void x264_plane_copy_interleave_core_sse2( pixel *dst, intptr_t i_dst, + pixel *srcu, intptr_t i_srcu, + pixel *srcv, intptr_t i_srcv, int w, int h ); +void x264_plane_copy_interleave_core_avx( pixel *dst, intptr_t i_dst, + pixel *srcu, intptr_t i_srcu, + pixel *srcv, intptr_t i_srcv, int w, int h ); +void x264_plane_copy_deinterleave_sse2( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, + pixel *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_ssse3( uint8_t *dsta, intptr_t i_dsta, + uint8_t *dstb, intptr_t i_dstb, + uint8_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_avx( uint16_t *dsta, intptr_t i_dsta, + uint16_t *dstb, intptr_t i_dstb, + uint16_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_avx2( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, + pixel *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_rgb_sse2 ( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, + pixel *dstc, intptr_t i_dstc, + pixel *src, intptr_t i_src, int pw, int w, int h ); +void x264_plane_copy_deinterleave_rgb_ssse3( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, + pixel *dstc, intptr_t i_dstc, + pixel *src, intptr_t i_src, int pw, int w, int h ); +void x264_plane_copy_deinterleave_rgb_avx2 ( pixel *dsta, intptr_t i_dsta, + pixel *dstb, intptr_t i_dstb, + pixel *dstc, intptr_t i_dstc, + pixel *src, intptr_t i_src, int pw, int w, int h ); +void x264_plane_copy_deinterleave_v210_ssse3 ( uint16_t *dstu, intptr_t i_dstu, + uint16_t *dstv, intptr_t i_dstv, + uint32_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_v210_avx ( uint16_t *dstu, intptr_t i_dstu, + uint16_t *dstv, intptr_t i_dstv, + uint32_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_v210_avx2 ( uint16_t *dstu, intptr_t i_dstu, + uint16_t *dstv, intptr_t i_dstv, + uint32_t *src, intptr_t i_src, int w, int h ); +void x264_plane_copy_deinterleave_v210_avx512( uint16_t *dstu, intptr_t i_dstu, + uint16_t *dstv, intptr_t i_dstv, + uint32_t *src, intptr_t i_src, int w, int h ); +void x264_store_interleave_chroma_mmx2( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); +void x264_store_interleave_chroma_sse2( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); +void x264_store_interleave_chroma_avx ( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height ); +void x264_load_deinterleave_chroma_fenc_sse2( pixel *dst, pixel *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fenc_ssse3( uint8_t *dst, uint8_t *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fenc_avx( uint16_t *dst, uint16_t *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fenc_avx2( pixel *dst, pixel *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fdec_sse2( pixel *dst, pixel *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fdec_ssse3( uint8_t *dst, uint8_t *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fdec_avx( uint16_t *dst, uint16_t *src, intptr_t i_src, int height ); +void x264_load_deinterleave_chroma_fdec_avx2( uint16_t *dst, uint16_t *src, intptr_t i_src, int height ); +void *x264_memcpy_aligned_sse ( void *dst, const void *src, size_t n ); +void *x264_memcpy_aligned_avx ( void *dst, const void *src, size_t n ); +void *x264_memcpy_aligned_avx512( void *dst, const void *src, size_t n ); +void x264_memzero_aligned_sse ( void *dst, size_t n ); +void x264_memzero_aligned_avx ( void *dst, size_t n ); +void x264_memzero_aligned_avx512( void *dst, size_t n ); +void x264_integral_init4h_sse4( uint16_t *sum, uint8_t *pix, intptr_t stride ); +void x264_integral_init4h_avx2( uint16_t *sum, uint8_t *pix, intptr_t stride ); +void x264_integral_init8h_sse4( uint16_t *sum, uint8_t *pix, intptr_t stride ); +void x264_integral_init8h_avx ( uint16_t *sum, uint8_t *pix, intptr_t stride ); +void x264_integral_init8h_avx2( uint16_t *sum, uint8_t *pix, intptr_t stride ); +void x264_integral_init4v_mmx ( uint16_t *sum8, uint16_t *sum4, intptr_t stride ); +void x264_integral_init4v_sse2 ( uint16_t *sum8, uint16_t *sum4, intptr_t stride ); +void x264_integral_init4v_ssse3( uint16_t *sum8, uint16_t *sum4, intptr_t stride ); +void x264_integral_init4v_avx2( uint16_t *sum8, uint16_t *sum4, intptr_t stride ); +void x264_integral_init8v_mmx ( uint16_t *sum8, intptr_t stride ); +void x264_integral_init8v_sse2( uint16_t *sum8, intptr_t stride ); +void x264_integral_init8v_avx2( uint16_t *sum8, intptr_t stride ); +void x264_mbtree_propagate_cost_sse2 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_avx ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_fma4 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_avx2 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_avx512( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_fix8_pack_ssse3( uint16_t *dst, float *src, int count ); +void x264_mbtree_fix8_pack_avx2 ( uint16_t *dst, float *src, int count ); +void x264_mbtree_fix8_unpack_ssse3( float *dst, uint16_t *src, int count ); +void x264_mbtree_fix8_unpack_avx2 ( float *dst, uint16_t *src, int count ); + +#define MC_CHROMA(cpu)\ +void x264_mc_chroma_##cpu( pixel *dstu, pixel *dstv, intptr_t i_dst, pixel *src, intptr_t i_src,\ + int dx, int dy, int i_width, int i_height ); +MC_CHROMA(mmx2) +MC_CHROMA(sse2) +MC_CHROMA(ssse3) +MC_CHROMA(cache64_ssse3) +MC_CHROMA(avx) +MC_CHROMA(avx2) + +#define LOWRES(cpu)\ +void x264_frame_init_lowres_core_##cpu( pixel *src0, pixel *dst0, pixel *dsth, pixel *dstv, pixel *dstc,\ + intptr_t src_stride, intptr_t dst_stride, int width, int height ); +LOWRES(mmx2) +LOWRES(cache32_mmx2) +LOWRES(sse2) +LOWRES(ssse3) +LOWRES(avx) +LOWRES(xop) +LOWRES(avx2) + +#define PIXEL_AVG_W(width,cpu)\ +void x264_pixel_avg2_w##width##_##cpu( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t ); +/* This declares some functions that don't exist, but that isn't a problem. */ +#define PIXEL_AVG_WALL(cpu)\ +PIXEL_AVG_W(4,cpu); PIXEL_AVG_W(8,cpu); PIXEL_AVG_W(10,cpu); PIXEL_AVG_W(12,cpu); PIXEL_AVG_W(16,cpu); PIXEL_AVG_W(18,cpu); PIXEL_AVG_W(20,cpu); + +PIXEL_AVG_WALL(mmx2) +PIXEL_AVG_WALL(cache32_mmx2) +PIXEL_AVG_WALL(cache64_mmx2) +PIXEL_AVG_WALL(cache64_sse2) +PIXEL_AVG_WALL(sse2) +PIXEL_AVG_WALL(cache64_ssse3) +PIXEL_AVG_WALL(avx2) + +#define PIXEL_AVG_WTAB(instr, name1, name2, name3, name4, name5)\ +static void (* const x264_pixel_avg_wtab_##instr[6])( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t ) =\ +{\ + NULL,\ + x264_pixel_avg2_w4_##name1,\ + x264_pixel_avg2_w8_##name2,\ + x264_pixel_avg2_w12_##name3,\ + x264_pixel_avg2_w16_##name4,\ + x264_pixel_avg2_w20_##name5,\ +}; + +#if HIGH_BIT_DEPTH +/* we can replace w12/w20 with w10/w18 as only 9/17 pixels in fact are important */ +#define x264_pixel_avg2_w12_mmx2 x264_pixel_avg2_w10_mmx2 +#define x264_pixel_avg2_w20_mmx2 x264_pixel_avg2_w18_mmx2 +#define x264_pixel_avg2_w12_sse2 x264_pixel_avg2_w10_sse2 +#define x264_pixel_avg2_w20_sse2 x264_pixel_avg2_w18_sse2 +#define x264_pixel_avg2_w12_avx2 x264_pixel_avg2_w16_avx2 +#define x264_pixel_avg2_w20_avx2 x264_pixel_avg2_w18_avx2 +#else +/* w16 sse2 is faster than w12 mmx as long as the cacheline issue is resolved */ +#define x264_pixel_avg2_w12_cache64_ssse3 x264_pixel_avg2_w16_cache64_ssse3 +#define x264_pixel_avg2_w12_cache64_sse2 x264_pixel_avg2_w16_cache64_sse2 +#define x264_pixel_avg2_w12_sse3 x264_pixel_avg2_w16_sse3 +#define x264_pixel_avg2_w12_sse2 x264_pixel_avg2_w16_sse2 +#endif // HIGH_BIT_DEPTH + +PIXEL_AVG_WTAB(mmx2, mmx2, mmx2, mmx2, mmx2, mmx2) +#if HIGH_BIT_DEPTH +PIXEL_AVG_WTAB(sse2, mmx2, sse2, sse2, sse2, sse2) +PIXEL_AVG_WTAB(avx2, mmx2, sse2, avx2, avx2, avx2) +#else // !HIGH_BIT_DEPTH +#if ARCH_X86 +PIXEL_AVG_WTAB(cache32_mmx2, mmx2, cache32_mmx2, cache32_mmx2, cache32_mmx2, cache32_mmx2) +PIXEL_AVG_WTAB(cache64_mmx2, mmx2, cache64_mmx2, cache64_mmx2, cache64_mmx2, cache64_mmx2) +#endif +PIXEL_AVG_WTAB(sse2, mmx2, mmx2, sse2, sse2, sse2) +PIXEL_AVG_WTAB(cache64_sse2, mmx2, cache64_mmx2, cache64_sse2, cache64_sse2, cache64_sse2) +PIXEL_AVG_WTAB(cache64_ssse3, mmx2, cache64_mmx2, cache64_ssse3, cache64_ssse3, cache64_sse2) +PIXEL_AVG_WTAB(cache64_ssse3_atom, mmx2, mmx2, cache64_ssse3, cache64_ssse3, sse2) +PIXEL_AVG_WTAB(avx2, mmx2, mmx2, sse2, sse2, avx2) +#endif // HIGH_BIT_DEPTH + +#define MC_COPY_WTAB(instr, name1, name2, name3)\ +static void (* const x264_mc_copy_wtab_##instr[5])( pixel *, intptr_t, pixel *, intptr_t, int ) =\ +{\ + NULL,\ + x264_mc_copy_w4_##name1,\ + x264_mc_copy_w8_##name2,\ + NULL,\ + x264_mc_copy_w16_##name3,\ +}; + +MC_COPY_WTAB(mmx,mmx,mmx,mmx) +#if HIGH_BIT_DEPTH +MC_COPY_WTAB(sse,mmx,sse,sse) +MC_COPY_WTAB(avx,mmx,sse,avx) +#else +MC_COPY_WTAB(sse,mmx,mmx,sse) +#endif + +#define MC_WEIGHT_WTAB(function, instr, name1, name2, w12version)\ + static void (* x264_mc_##function##_wtab_##instr[6])( pixel *, intptr_t, pixel *, intptr_t, const x264_weight_t *, int ) =\ +{\ + x264_mc_##function##_w4_##name1,\ + x264_mc_##function##_w4_##name1,\ + x264_mc_##function##_w8_##name2,\ + x264_mc_##function##_w##w12version##_##instr,\ + x264_mc_##function##_w16_##instr,\ + x264_mc_##function##_w20_##instr,\ +}; + +#if HIGH_BIT_DEPTH +MC_WEIGHT_WTAB(weight,mmx2,mmx2,mmx2,12) +MC_WEIGHT_WTAB(offsetadd,mmx2,mmx2,mmx2,12) +MC_WEIGHT_WTAB(offsetsub,mmx2,mmx2,mmx2,12) +MC_WEIGHT_WTAB(weight,sse2,mmx2,sse2,12) +MC_WEIGHT_WTAB(offsetadd,sse2,mmx2,sse2,16) +MC_WEIGHT_WTAB(offsetsub,sse2,mmx2,sse2,16) + +static void x264_weight_cache_mmx2( x264_t *h, x264_weight_t *w ) +{ + if( w->i_scale == 1<i_denom ) + { + if( w->i_offset < 0 ) + w->weightfn = h->mc.offsetsub; + else + w->weightfn = h->mc.offsetadd; + for( int i = 0; i < 8; i++ ) + w->cachea[i] = abs(w->i_offset<<(BIT_DEPTH-8)); + return; + } + w->weightfn = h->mc.weight; + int den1 = 1<i_denom; + int den2 = w->i_scale<<1; + int den3 = 1+(w->i_offset<<(BIT_DEPTH-8+1)); + for( int i = 0; i < 8; i++ ) + { + w->cachea[i] = den1; + w->cacheb[i] = i&1 ? den3 : den2; + } +} +#else +MC_WEIGHT_WTAB(weight,mmx2,mmx2,mmx2,12) +MC_WEIGHT_WTAB(offsetadd,mmx2,mmx2,mmx2,12) +MC_WEIGHT_WTAB(offsetsub,mmx2,mmx2,mmx2,12) +MC_WEIGHT_WTAB(weight,sse2,mmx2,sse2,16) +MC_WEIGHT_WTAB(offsetadd,sse2,mmx2,mmx2,16) +MC_WEIGHT_WTAB(offsetsub,sse2,mmx2,mmx2,16) +MC_WEIGHT_WTAB(weight,ssse3,ssse3,ssse3,16) +MC_WEIGHT_WTAB(weight,avx2,ssse3,avx2,16) + +static void x264_weight_cache_mmx2( x264_t *h, x264_weight_t *w ) +{ + int i; + int16_t den1; + + if( w->i_scale == 1<i_denom ) + { + if( w->i_offset < 0 ) + w->weightfn = h->mc.offsetsub; + else + w->weightfn = h->mc.offsetadd; + memset( w->cachea, abs(w->i_offset), sizeof(w->cachea) ); + return; + } + w->weightfn = h->mc.weight; + den1 = 1 << (w->i_denom - 1) | w->i_offset << w->i_denom; + for( i = 0; i < 8; i++ ) + { + w->cachea[i] = w->i_scale; + w->cacheb[i] = den1; + } +} + +static void x264_weight_cache_ssse3( x264_t *h, x264_weight_t *w ) +{ + int i, den1; + if( w->i_scale == 1<i_denom ) + { + if( w->i_offset < 0 ) + w->weightfn = h->mc.offsetsub; + else + w->weightfn = h->mc.offsetadd; + + memset( w->cachea, abs( w->i_offset ), sizeof(w->cachea) ); + return; + } + w->weightfn = h->mc.weight; + den1 = w->i_scale << (8 - w->i_denom); + for( i = 0; i < 8; i++ ) + { + w->cachea[i] = den1; + w->cacheb[i] = w->i_offset; + } +} +#endif // !HIGH_BIT_DEPTH + +#define MC_LUMA(name,instr1,instr2)\ +static void mc_luma_##name( pixel *dst, intptr_t i_dst_stride,\ + pixel *src[4], intptr_t i_src_stride,\ + int mvx, int mvy,\ + int i_width, int i_height, const x264_weight_t *weight )\ +{\ + int qpel_idx = ((mvy&3)<<2) + (mvx&3);\ + int offset = (mvy>>2)*i_src_stride + (mvx>>2);\ + pixel *src1 = src[x264_hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;\ + if( qpel_idx & 5 ) /* qpel interpolation needed */\ + {\ + pixel *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);\ + x264_pixel_avg_wtab_##instr1[i_width>>2](\ + dst, i_dst_stride, src1, i_src_stride,\ + src2, i_height );\ + if( weight->weightfn )\ + weight->weightfn[i_width>>2]( dst, i_dst_stride, dst, i_dst_stride, weight, i_height );\ + }\ + else if( weight->weightfn )\ + weight->weightfn[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, weight, i_height );\ + else\ + x264_mc_copy_wtab_##instr2[i_width>>2](dst, i_dst_stride, src1, i_src_stride, i_height );\ +} + +MC_LUMA(mmx2,mmx2,mmx) +MC_LUMA(sse2,sse2,sse) +#if HIGH_BIT_DEPTH +MC_LUMA(avx2,avx2,avx) +#else +#if ARCH_X86 +MC_LUMA(cache32_mmx2,cache32_mmx2,mmx) +MC_LUMA(cache64_mmx2,cache64_mmx2,mmx) +#endif +MC_LUMA(cache64_sse2,cache64_sse2,sse) +MC_LUMA(cache64_ssse3,cache64_ssse3,sse) +MC_LUMA(cache64_ssse3_atom,cache64_ssse3_atom,sse) +#endif // !HIGH_BIT_DEPTH + +#define GET_REF(name)\ +static pixel *get_ref_##name( pixel *dst, intptr_t *i_dst_stride,\ + pixel *src[4], intptr_t i_src_stride,\ + int mvx, int mvy,\ + int i_width, int i_height, const x264_weight_t *weight )\ +{\ + int qpel_idx = ((mvy&3)<<2) + (mvx&3);\ + int offset = (mvy>>2)*i_src_stride + (mvx>>2);\ + pixel *src1 = src[x264_hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;\ + if( qpel_idx & 5 ) /* qpel interpolation needed */\ + {\ + pixel *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);\ + x264_pixel_avg_wtab_##name[i_width>>2](\ + dst, *i_dst_stride, src1, i_src_stride,\ + src2, i_height );\ + if( weight->weightfn )\ + weight->weightfn[i_width>>2]( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_height );\ + return dst;\ + }\ + else if( weight->weightfn )\ + {\ + weight->weightfn[i_width>>2]( dst, *i_dst_stride, src1, i_src_stride, weight, i_height );\ + return dst;\ + }\ + else\ + {\ + *i_dst_stride = i_src_stride;\ + return src1;\ + }\ +} + +GET_REF(mmx2) +GET_REF(sse2) +GET_REF(avx2) +#if !HIGH_BIT_DEPTH +#if ARCH_X86 +GET_REF(cache32_mmx2) +GET_REF(cache64_mmx2) +#endif +GET_REF(cache64_sse2) +GET_REF(cache64_ssse3) +GET_REF(cache64_ssse3_atom) +#endif // !HIGH_BIT_DEPTH + +#define HPEL(align, cpu, cpuv, cpuc, cpuh)\ +void x264_hpel_filter_v_##cpuv( pixel *dst, pixel *src, int16_t *buf, intptr_t stride, intptr_t width);\ +void x264_hpel_filter_c_##cpuc( pixel *dst, int16_t *buf, intptr_t width );\ +void x264_hpel_filter_h_##cpuh( pixel *dst, pixel *src, intptr_t width );\ +static void x264_hpel_filter_##cpu( pixel *dsth, pixel *dstv, pixel *dstc, pixel *src,\ + intptr_t stride, int width, int height, int16_t *buf )\ +{\ + intptr_t realign = (intptr_t)src & (align-1);\ + src -= realign;\ + dstv -= realign;\ + dstc -= realign;\ + dsth -= realign;\ + width += realign;\ + while( height-- )\ + {\ + x264_hpel_filter_v_##cpuv( dstv, src, buf+16, stride, width );\ + x264_hpel_filter_c_##cpuc( dstc, buf+16, width );\ + x264_hpel_filter_h_##cpuh( dsth, src, width );\ + dsth += stride;\ + dstv += stride;\ + dstc += stride;\ + src += stride;\ + }\ + x264_sfence();\ +} + +HPEL(8, mmx2, mmx2, mmx2, mmx2) +#if HIGH_BIT_DEPTH +HPEL(16, sse2, sse2, sse2, sse2) +#else // !HIGH_BIT_DEPTH +HPEL(16, sse2_amd, mmx2, mmx2, sse2) +#if ARCH_X86_64 +void x264_hpel_filter_sse2 ( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, intptr_t stride, int width, int height, int16_t *buf ); +void x264_hpel_filter_ssse3( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, intptr_t stride, int width, int height, int16_t *buf ); +void x264_hpel_filter_avx ( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, intptr_t stride, int width, int height, int16_t *buf ); +void x264_hpel_filter_avx2 ( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, intptr_t stride, int width, int height, int16_t *buf ); +#else +HPEL(16, sse2, sse2, sse2, sse2) +HPEL(16, ssse3, ssse3, ssse3, ssse3) +HPEL(16, avx, avx, avx, avx) +HPEL(32, avx2, avx2, avx2, avx2) +#endif +#endif // HIGH_BIT_DEPTH + +PLANE_COPY(16, sse) +PLANE_COPY(32, avx) + +PLANE_COPY_SWAP(16, ssse3) +PLANE_COPY_SWAP(32, avx2) + +#if HIGH_BIT_DEPTH +PLANE_COPY_YUYV(64, sse2) +PLANE_COPY_YUYV(64, avx) +#else +PLANE_COPY_YUYV(32, sse2) +PLANE_COPY_YUYV(32, ssse3) +#endif +PLANE_COPY_YUYV(64, avx2) + +PLANE_INTERLEAVE(mmx2) +PLANE_INTERLEAVE(sse2) +#if HIGH_BIT_DEPTH +PLANE_INTERLEAVE(avx) +#endif + +#if HAVE_X86_INLINE_ASM +#undef MC_CLIP_ADD +#define MC_CLIP_ADD(s,x)\ +do\ +{\ + int temp;\ + asm("movd %0, %%xmm0 \n"\ + "movd %2, %%xmm1 \n"\ + "paddsw %%xmm1, %%xmm0 \n"\ + "movd %%xmm0, %1 \n"\ + :"+m"(s), "=&r"(temp)\ + :"m"(x)\ + );\ + s = temp;\ +} while( 0 ) + +#undef MC_CLIP_ADD2 +#define MC_CLIP_ADD2(s,x)\ +do\ +{\ + asm("movd %0, %%xmm0 \n"\ + "movd %1, %%xmm1 \n"\ + "paddsw %%xmm1, %%xmm0 \n"\ + "movd %%xmm0, %0 \n"\ + :"+m"(M32(s))\ + :"m"(M32(x))\ + );\ +} while( 0 ) +#endif + +PROPAGATE_LIST(ssse3) +PROPAGATE_LIST(avx) +PROPAGATE_LIST(avx2) + +#if ARCH_X86_64 +void x264_mbtree_propagate_list_internal_avx512( size_t len, uint16_t *ref_costs, int16_t (*mvs)[2], int16_t *propagate_amount, + uint16_t *lowres_costs, int bipred_weight, int mb_y, + int width, int height, int stride, int list_mask ); + +static void x264_mbtree_propagate_list_avx512( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2], + int16_t *propagate_amount, uint16_t *lowres_costs, + int bipred_weight, int mb_y, int len, int list ) +{ + x264_mbtree_propagate_list_internal_avx512( len, ref_costs, mvs, propagate_amount, lowres_costs, bipred_weight << 9, + mb_y << 16, h->mb.i_mb_width, h->mb.i_mb_height, h->mb.i_mb_stride, + (1 << LOWRES_COST_SHIFT) << list ); +} +#endif + +void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) +{ + if( !(cpu&X264_CPU_MMX) ) + return; + + pf->copy_16x16_unaligned = x264_mc_copy_w16_mmx; + pf->copy[PIXEL_16x16] = x264_mc_copy_w16_mmx; + pf->copy[PIXEL_8x8] = x264_mc_copy_w8_mmx; + pf->copy[PIXEL_4x4] = x264_mc_copy_w4_mmx; + pf->integral_init4v = x264_integral_init4v_mmx; + pf->integral_init8v = x264_integral_init8v_mmx; + + if( !(cpu&X264_CPU_MMX2) ) + return; + + pf->prefetch_fenc_420 = x264_prefetch_fenc_420_mmx2; + pf->prefetch_fenc_422 = x264_prefetch_fenc_422_mmx2; + pf->prefetch_ref = x264_prefetch_ref_mmx2; + + pf->plane_copy_interleave = x264_plane_copy_interleave_mmx2; + pf->store_interleave_chroma = x264_store_interleave_chroma_mmx2; + + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_mmx2; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_mmx2; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_mmx2; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_mmx2; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_mmx2; + pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_mmx2; + pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_mmx2; + pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_mmx2; + pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_mmx2; + + pf->mc_luma = mc_luma_mmx2; + pf->get_ref = get_ref_mmx2; + pf->mc_chroma = x264_mc_chroma_mmx2; + pf->hpel_filter = x264_hpel_filter_mmx2; + pf->weight = x264_mc_weight_wtab_mmx2; + pf->weight_cache = x264_weight_cache_mmx2; + pf->offsetadd = x264_mc_offsetadd_wtab_mmx2; + pf->offsetsub = x264_mc_offsetsub_wtab_mmx2; + + pf->frame_init_lowres_core = x264_frame_init_lowres_core_mmx2; + + if( cpu&X264_CPU_SSE ) + { + pf->memcpy_aligned = x264_memcpy_aligned_sse; + pf->memzero_aligned = x264_memzero_aligned_sse; + pf->plane_copy = x264_plane_copy_sse; + } + +#if HIGH_BIT_DEPTH +#if ARCH_X86 // all x86_64 cpus with cacheline split issues use sse2 instead + if( cpu&(X264_CPU_CACHELINE_32|X264_CPU_CACHELINE_64) ) + pf->frame_init_lowres_core = x264_frame_init_lowres_core_cache32_mmx2; +#endif + + if( !(cpu&X264_CPU_SSE2) ) + return; + + pf->frame_init_lowres_core = x264_frame_init_lowres_core_sse2; + + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_sse2; + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_sse2; + + pf->plane_copy_interleave = x264_plane_copy_interleave_sse2; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_sse2; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_sse2; + + if( cpu&X264_CPU_SSE2_IS_FAST ) + { + pf->get_ref = get_ref_sse2; + pf->mc_luma = mc_luma_sse2; + pf->hpel_filter = x264_hpel_filter_sse2; + } + + pf->integral_init4v = x264_integral_init4v_sse2; + pf->integral_init8v = x264_integral_init8v_sse2; + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_sse2; + pf->store_interleave_chroma = x264_store_interleave_chroma_sse2; + pf->offsetadd = x264_mc_offsetadd_wtab_sse2; + pf->offsetsub = x264_mc_offsetsub_wtab_sse2; + + if( cpu&X264_CPU_SSE2_IS_SLOW ) + return; + + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_sse2; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_sse2; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_sse2; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_sse2; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_sse2; + pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_sse2; + pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_sse2; + pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_sse2; + pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_sse2; + + pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse; + pf->weight = x264_mc_weight_wtab_sse2; + + if( !(cpu&X264_CPU_STACK_MOD4) ) + pf->mc_chroma = x264_mc_chroma_sse2; + + if( !(cpu&X264_CPU_SSSE3) ) + return; + + pf->frame_init_lowres_core = x264_frame_init_lowres_core_ssse3; + pf->plane_copy_swap = x264_plane_copy_swap_ssse3; + pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_ssse3; + pf->mbtree_propagate_list = x264_mbtree_propagate_list_ssse3; + pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_ssse3; + pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_ssse3; + + if( !(cpu&(X264_CPU_SLOW_SHUFFLE|X264_CPU_SLOW_ATOM|X264_CPU_SLOW_PALIGNR)) ) + pf->integral_init4v = x264_integral_init4v_ssse3; + + if( !(cpu&X264_CPU_AVX) ) + return; + + pf->frame_init_lowres_core = x264_frame_init_lowres_core_avx; + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_avx; + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_avx; + pf->plane_copy_interleave = x264_plane_copy_interleave_avx; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_avx; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_avx; + pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx; + pf->store_interleave_chroma = x264_store_interleave_chroma_avx; + pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_avx; + + if( !(cpu&X264_CPU_STACK_MOD4) ) + pf->mc_chroma = x264_mc_chroma_avx; + + if( cpu&X264_CPU_XOP ) + pf->frame_init_lowres_core = x264_frame_init_lowres_core_xop; + + if( cpu&X264_CPU_AVX2 ) + { + pf->mc_luma = mc_luma_avx2; + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_avx2; + pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx2; + } + + if( cpu&X264_CPU_AVX512 ) + { + pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx512; + } +#else // !HIGH_BIT_DEPTH + +#if ARCH_X86 // all x86_64 cpus with cacheline split issues use sse2 instead + if( cpu&X264_CPU_CACHELINE_32 ) + { + pf->mc_luma = mc_luma_cache32_mmx2; + pf->get_ref = get_ref_cache32_mmx2; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_cache32_mmx2; + } + else if( cpu&X264_CPU_CACHELINE_64 ) + { + pf->mc_luma = mc_luma_cache64_mmx2; + pf->get_ref = get_ref_cache64_mmx2; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_cache32_mmx2; + } +#endif + + if( !(cpu&X264_CPU_SSE2) ) + return; + + pf->integral_init4v = x264_integral_init4v_sse2; + pf->integral_init8v = x264_integral_init8v_sse2; + pf->hpel_filter = x264_hpel_filter_sse2_amd; + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_sse2; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_sse2; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_sse2; + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_sse2; + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_sse2; + pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_sse2; + + if( !(cpu&X264_CPU_SSE2_IS_SLOW) ) + { + pf->weight = x264_mc_weight_wtab_sse2; + if( !(cpu&X264_CPU_SLOW_ATOM) ) + { + pf->offsetadd = x264_mc_offsetadd_wtab_sse2; + pf->offsetsub = x264_mc_offsetsub_wtab_sse2; + } + + pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse; + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_sse2; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_sse2; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_sse2; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_sse2; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_sse2; + pf->hpel_filter = x264_hpel_filter_sse2; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_sse2; + if( !(cpu&X264_CPU_STACK_MOD4) ) + pf->mc_chroma = x264_mc_chroma_sse2; + + if( cpu&X264_CPU_SSE2_IS_FAST ) + { + pf->store_interleave_chroma = x264_store_interleave_chroma_sse2; // FIXME sse2fast? sse2medium? + pf->plane_copy_interleave = x264_plane_copy_interleave_sse2; + pf->mc_luma = mc_luma_sse2; + pf->get_ref = get_ref_sse2; + if( cpu&X264_CPU_CACHELINE_64 ) + { + pf->mc_luma = mc_luma_cache64_sse2; + pf->get_ref = get_ref_cache64_sse2; + } + } + } + + if( !(cpu&X264_CPU_SSSE3) ) + return; + + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_ssse3; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_ssse3; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_ssse3; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_ssse3; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_ssse3; + pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_ssse3; + pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_ssse3; + pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_ssse3; + pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_ssse3; + pf->plane_copy_swap = x264_plane_copy_swap_ssse3; + pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_ssse3; + pf->mbtree_propagate_list = x264_mbtree_propagate_list_ssse3; + pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_ssse3; + pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_ssse3; + + if( !(cpu&X264_CPU_SLOW_PSHUFB) ) + { + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_ssse3; + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_ssse3; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_ssse3; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_ssse3; + } + + if( !(cpu&X264_CPU_SLOW_PALIGNR) ) + { +#if ARCH_X86_64 + if( !(cpu&X264_CPU_SLOW_ATOM) ) /* The 64-bit version is slower, but the 32-bit version is faster? */ +#endif + pf->hpel_filter = x264_hpel_filter_ssse3; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_ssse3; + } + if( !(cpu&X264_CPU_STACK_MOD4) ) + pf->mc_chroma = x264_mc_chroma_ssse3; + + if( cpu&X264_CPU_CACHELINE_64 ) + { + if( !(cpu&X264_CPU_STACK_MOD4) ) + pf->mc_chroma = x264_mc_chroma_cache64_ssse3; + pf->mc_luma = mc_luma_cache64_ssse3; + pf->get_ref = get_ref_cache64_ssse3; + if( cpu&X264_CPU_SLOW_ATOM ) + { + pf->mc_luma = mc_luma_cache64_ssse3_atom; + pf->get_ref = get_ref_cache64_ssse3_atom; + } + } + + pf->weight_cache = x264_weight_cache_ssse3; + pf->weight = x264_mc_weight_wtab_ssse3; + + if( !(cpu&(X264_CPU_SLOW_SHUFFLE|X264_CPU_SLOW_ATOM|X264_CPU_SLOW_PALIGNR)) ) + pf->integral_init4v = x264_integral_init4v_ssse3; + + if( !(cpu&X264_CPU_SSE4) ) + return; + + pf->integral_init4h = x264_integral_init4h_sse4; + pf->integral_init8h = x264_integral_init8h_sse4; + + if( !(cpu&X264_CPU_AVX) ) + return; + + pf->frame_init_lowres_core = x264_frame_init_lowres_core_avx; + pf->integral_init8h = x264_integral_init8h_avx; + pf->hpel_filter = x264_hpel_filter_avx; + + if( !(cpu&X264_CPU_STACK_MOD4) ) + pf->mc_chroma = x264_mc_chroma_avx; + + if( cpu&X264_CPU_XOP ) + pf->frame_init_lowres_core = x264_frame_init_lowres_core_xop; + + if( cpu&X264_CPU_AVX2 ) + { + pf->hpel_filter = x264_hpel_filter_avx2; + pf->mc_chroma = x264_mc_chroma_avx2; + pf->weight = x264_mc_weight_wtab_avx2; + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_avx2; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_avx2; + pf->integral_init8v = x264_integral_init8v_avx2; + pf->integral_init4v = x264_integral_init4v_avx2; + pf->integral_init8h = x264_integral_init8h_avx2; + pf->integral_init4h = x264_integral_init4h_avx2; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_avx2; + pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_avx2; + } + + if( cpu&X264_CPU_AVX512 ) + { + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_avx512; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_avx512; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_avx512; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_avx512; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_avx512; + } +#endif // HIGH_BIT_DEPTH + + if( !(cpu&X264_CPU_AVX) ) + return; + pf->memcpy_aligned = x264_memcpy_aligned_avx; + pf->memzero_aligned = x264_memzero_aligned_avx; + pf->plane_copy = x264_plane_copy_avx; + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx; + pf->mbtree_propagate_list = x264_mbtree_propagate_list_avx; + + if( cpu&X264_CPU_FMA4 ) + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_fma4; + + if( !(cpu&X264_CPU_AVX2) ) + return; + pf->plane_copy_swap = x264_plane_copy_swap_avx2; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_avx2; + pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_avx2; + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_avx2; + pf->get_ref = get_ref_avx2; + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx2; + pf->mbtree_propagate_list = x264_mbtree_propagate_list_avx2; + pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_avx2; + pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_avx2; + + if( !(cpu&X264_CPU_AVX512) ) + return; + pf->memcpy_aligned = x264_memcpy_aligned_avx512; + pf->memzero_aligned = x264_memzero_aligned_avx512; + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx512; +#if ARCH_X86_64 + pf->mbtree_propagate_list = x264_mbtree_propagate_list_avx512; +#endif +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/mc.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/mc.h new file mode 100644 index 00000000..394fb7bb --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/mc.h @@ -0,0 +1,32 @@ +/***************************************************************************** + * mc.h: x86 motion compensation + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_I386_MC_H +#define X264_I386_MC_H + +void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/pixel.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/pixel.h new file mode 100644 index 00000000..56cfc5cb --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/pixel.h @@ -0,0 +1,220 @@ +/***************************************************************************** + * pixel.h: x86 pixel metrics + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_I386_PIXEL_H +#define X264_I386_PIXEL_H + +#define DECL_PIXELS( ret, name, suffix, args ) \ + ret x264_pixel_##name##_16x16_##suffix args;\ + ret x264_pixel_##name##_16x8_##suffix args;\ + ret x264_pixel_##name##_8x16_##suffix args;\ + ret x264_pixel_##name##_8x8_##suffix args;\ + ret x264_pixel_##name##_8x4_##suffix args;\ + ret x264_pixel_##name##_4x16_##suffix args;\ + ret x264_pixel_##name##_4x8_##suffix args;\ + ret x264_pixel_##name##_4x4_##suffix args;\ + +#define DECL_X1( name, suffix ) \ + DECL_PIXELS( int, name, suffix, ( pixel *, intptr_t, pixel *, intptr_t ) ) + +#define DECL_X4( name, suffix ) \ + DECL_PIXELS( void, name##_x3, suffix, ( pixel *, pixel *, pixel *, pixel *, intptr_t, int * ) )\ + DECL_PIXELS( void, name##_x4, suffix, ( pixel *, pixel *, pixel *, pixel *, pixel *, intptr_t, int * ) ) + +DECL_X1( sad, mmx2 ) +DECL_X1( sad, sse2 ) +DECL_X1( sad, sse3 ) +DECL_X1( sad, sse2_aligned ) +DECL_X1( sad, ssse3 ) +DECL_X1( sad, ssse3_aligned ) +DECL_X1( sad, avx2 ) +DECL_X1( sad, avx512 ) +DECL_X4( sad, mmx2 ) +DECL_X4( sad, sse2 ) +DECL_X4( sad, sse3 ) +DECL_X4( sad, ssse3 ) +DECL_X4( sad, xop ) +DECL_X4( sad, avx ) +DECL_X4( sad, avx2 ) +DECL_X4( sad, avx512 ) +DECL_X1( ssd, mmx ) +DECL_X1( ssd, mmx2 ) +DECL_X1( ssd, sse2slow ) +DECL_X1( ssd, sse2 ) +DECL_X1( ssd, ssse3 ) +DECL_X1( ssd, avx ) +DECL_X1( ssd, xop ) +DECL_X1( ssd, avx2 ) +DECL_X1( satd, mmx2 ) +DECL_X1( satd, sse2 ) +DECL_X1( satd, ssse3 ) +DECL_X1( satd, ssse3_atom ) +DECL_X1( satd, sse4 ) +DECL_X1( satd, avx ) +DECL_X1( satd, xop ) +DECL_X1( satd, avx2 ) +DECL_X1( satd, avx512 ) +DECL_X1( sa8d, mmx2 ) +DECL_X1( sa8d, sse2 ) +DECL_X1( sa8d, ssse3 ) +DECL_X1( sa8d, ssse3_atom ) +DECL_X1( sa8d, sse4 ) +DECL_X1( sa8d, avx ) +DECL_X1( sa8d, xop ) +DECL_X1( sa8d, avx2 ) +DECL_X1( sa8d, avx512 ) +DECL_X1( sad, cache32_mmx2 ); +DECL_X1( sad, cache64_mmx2 ); +DECL_X1( sad, cache64_sse2 ); +DECL_X1( sad, cache64_ssse3 ); +DECL_X4( sad, cache32_mmx2 ); +DECL_X4( sad, cache64_mmx2 ); +DECL_X4( sad, cache64_sse2 ); +DECL_X4( sad, cache64_ssse3 ); + +DECL_PIXELS( uint64_t, var, sse2, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, var, avx, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, var, avx2, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, var, avx512, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, mmx2, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, sse2, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, ssse3, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, ssse3_atom, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, sse4, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, avx, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, xop, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, avx2, ( pixel *pix, intptr_t i_stride )) + + +void x264_intra_satd_x3_4x4_mmx2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_4x4_mmx2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_4x4_sse2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_4x4_ssse3 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_4x4_avx ( pixel *, pixel *, int * ); +void x264_intra_satd_x3_8x8c_mmx2 ( pixel *, pixel *, int * ); +void x264_intra_satd_x3_8x8c_ssse3 ( uint8_t *, uint8_t *, int * ); +void x264_intra_sad_x3_8x8c_mmx2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_8x8c_sse2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_8x8c_ssse3 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_8x8c_avx2 ( pixel *, pixel *, int * ); +void x264_intra_satd_x3_16x16_mmx2 ( pixel *, pixel *, int * ); +void x264_intra_satd_x3_16x16_ssse3( uint8_t *, uint8_t *, int * ); +void x264_intra_sad_x3_16x16_mmx2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_16x16_sse2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_16x16_ssse3 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_16x16_avx2 ( pixel *, pixel *, int * ); +void x264_intra_sa8d_x3_8x8_mmx2 ( uint8_t *, uint8_t *, int * ); +void x264_intra_sa8d_x3_8x8_sse2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_8x8_mmx2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_8x8_sse2 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_8x8_ssse3 ( pixel *, pixel *, int * ); +void x264_intra_sad_x3_8x8_avx2 ( uint16_t*, uint16_t*, int * ); +int x264_intra_satd_x9_4x4_ssse3( uint8_t *, uint8_t *, uint16_t * ); +int x264_intra_satd_x9_4x4_sse4 ( uint8_t *, uint8_t *, uint16_t * ); +int x264_intra_satd_x9_4x4_avx ( uint8_t *, uint8_t *, uint16_t * ); +int x264_intra_satd_x9_4x4_xop ( uint8_t *, uint8_t *, uint16_t * ); +int x264_intra_sad_x9_4x4_ssse3 ( uint8_t *, uint8_t *, uint16_t * ); +int x264_intra_sad_x9_4x4_sse4 ( uint8_t *, uint8_t *, uint16_t * ); +int x264_intra_sad_x9_4x4_avx ( uint8_t *, uint8_t *, uint16_t * ); +int x264_intra_sa8d_x9_8x8_ssse3( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * ); +int x264_intra_sa8d_x9_8x8_sse4 ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * ); +int x264_intra_sa8d_x9_8x8_avx ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * ); +int x264_intra_sad_x9_8x8_ssse3 ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * ); +int x264_intra_sad_x9_8x8_sse4 ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * ); +int x264_intra_sad_x9_8x8_avx ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * ); +int x264_intra_sad_x9_8x8_avx2 ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * ); + +void x264_pixel_ssd_nv12_core_sse2( pixel *pixuv1, intptr_t stride1, + pixel *pixuv2, intptr_t stride2, int width, + int height, uint64_t *ssd_u, uint64_t *ssd_v ); +void x264_pixel_ssd_nv12_core_avx ( pixel *pixuv1, intptr_t stride1, + pixel *pixuv2, intptr_t stride2, int width, + int height, uint64_t *ssd_u, uint64_t *ssd_v ); +void x264_pixel_ssd_nv12_core_xop ( pixel *pixuv1, intptr_t stride1, + pixel *pixuv2, intptr_t stride2, int width, + int height, uint64_t *ssd_u, uint64_t *ssd_v ); +void x264_pixel_ssd_nv12_core_avx2( pixel *pixuv1, intptr_t stride1, + pixel *pixuv2, intptr_t stride2, int width, + int height, uint64_t *ssd_u, uint64_t *ssd_v ); +void x264_pixel_ssim_4x4x2_core_mmx2( const uint8_t *pix1, intptr_t stride1, + const uint8_t *pix2, intptr_t stride2, int sums[2][4] ); +void x264_pixel_ssim_4x4x2_core_sse2( const pixel *pix1, intptr_t stride1, + const pixel *pix2, intptr_t stride2, int sums[2][4] ); +void x264_pixel_ssim_4x4x2_core_avx ( const pixel *pix1, intptr_t stride1, + const pixel *pix2, intptr_t stride2, int sums[2][4] ); +float x264_pixel_ssim_end4_sse2( int sum0[5][4], int sum1[5][4], int width ); +float x264_pixel_ssim_end4_avx ( int sum0[5][4], int sum1[5][4], int width ); +int x264_pixel_var2_8x8_sse2 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x8_ssse3 ( uint8_t *fenc, uint8_t *fdec, int ssd[2] ); +int x264_pixel_var2_8x8_avx2 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x8_avx512 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x16_sse2 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x16_ssse3 ( uint8_t *fenc, uint8_t *fdec, int ssd[2] ); +int x264_pixel_var2_8x16_avx2 ( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_var2_8x16_avx512( pixel *fenc, pixel *fdec, int ssd[2] ); +int x264_pixel_vsad_mmx2 ( pixel *src, intptr_t stride, int height ); +int x264_pixel_vsad_sse2 ( pixel *src, intptr_t stride, int height ); +int x264_pixel_vsad_ssse3( pixel *src, intptr_t stride, int height ); +int x264_pixel_vsad_xop ( pixel *src, intptr_t stride, int height ); +int x264_pixel_vsad_avx2 ( uint16_t *src, intptr_t stride, int height ); +int x264_pixel_asd8_sse2 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); +int x264_pixel_asd8_ssse3( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); +int x264_pixel_asd8_xop ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); +uint64_t x264_pixel_sa8d_satd_16x16_sse2 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_ssse3 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_ssse3_atom( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_sse4 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_avx ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_xop ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_avx2 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); + + +#define DECL_ADS( size, suffix ) \ +int x264_pixel_ads##size##_##suffix( int enc_dc[size], uint16_t *sums, int delta,\ + uint16_t *cost_mvx, int16_t *mvs, int width, int thresh ); +DECL_ADS( 4, mmx2 ) +DECL_ADS( 2, mmx2 ) +DECL_ADS( 1, mmx2 ) +DECL_ADS( 4, sse2 ) +DECL_ADS( 2, sse2 ) +DECL_ADS( 1, sse2 ) +DECL_ADS( 4, ssse3 ) +DECL_ADS( 2, ssse3 ) +DECL_ADS( 1, ssse3 ) +DECL_ADS( 4, avx ) +DECL_ADS( 2, avx ) +DECL_ADS( 1, avx ) +DECL_ADS( 4, avx2 ) +DECL_ADS( 2, avx2 ) +DECL_ADS( 1, avx2 ) + +#undef DECL_PIXELS +#undef DECL_X1 +#undef DECL_X4 +#undef DECL_ADS + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/predict-c.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/predict-c.c new file mode 100644 index 00000000..27da63a2 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/predict-c.c @@ -0,0 +1,609 @@ +/***************************************************************************** + * predict-c.c: intra prediction + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "predict.h" +#include "pixel.h" + +#define PREDICT_P_SUM(j,i)\ + H += i * ( src[j+i - FDEC_STRIDE ] - src[j-i - FDEC_STRIDE ] );\ + V += i * ( src[(j+i)*FDEC_STRIDE -1] - src[(j-i)*FDEC_STRIDE -1] ); + +#if HAVE_X86_INLINE_ASM +#if HIGH_BIT_DEPTH +ALIGNED_16( static const int16_t pw_12345678[8] ) = {1,2,3,4,5,6,7,8}; +ALIGNED_16( static const int16_t pw_m87654321[8] ) = {-8,-7,-6,-5,-4,-3,-2,-1}; +ALIGNED_16( static const int16_t pw_m32101234[8] ) = {-3,-2,-1,0,1,2,3,4}; +#else // !HIGH_BIT_DEPTH +ALIGNED_8( static const int8_t pb_12345678[8] ) = {1,2,3,4,5,6,7,8}; +ALIGNED_8( static const int8_t pb_m87654321[8] ) = {-8,-7,-6,-5,-4,-3,-2,-1}; +ALIGNED_8( static const int8_t pb_m32101234[8] ) = {-3,-2,-1,0,1,2,3,4}; +#endif // HIGH_BIT_DEPTH +#endif // HAVE_X86_INLINE_ASM + +#define PREDICT_16x16_P_CORE\ + int H = 0;\ + int V = 0;\ + PREDICT_P_SUM(7,1)\ + PREDICT_P_SUM(7,2)\ + PREDICT_P_SUM(7,3)\ + PREDICT_P_SUM(7,4)\ + PREDICT_P_SUM(7,5)\ + PREDICT_P_SUM(7,6)\ + PREDICT_P_SUM(7,7)\ + PREDICT_P_SUM(7,8) + +#define PREDICT_16x16_P_END(name)\ + int a = 16 * ( src[15*FDEC_STRIDE -1] + src[15 - FDEC_STRIDE] );\ + int b = ( 5 * H + 32 ) >> 6;\ + int c = ( 5 * V + 32 ) >> 6;\ + int i00 = a - b * 7 - c * 7 + 16;\ + /* b*15 + c*15 can overflow: it's easier to just branch away in this rare case + * than to try to consider it in the asm. */\ + if( BIT_DEPTH > 8 && (i00 > 0x7fff || abs(b) > 1092 || abs(c) > 1092) )\ + x264_predict_16x16_p_c( src );\ + else\ + x264_predict_16x16_p_core_##name( src, i00, b, c ); + +#define PREDICT_16x16_P(name, name2)\ +static void x264_predict_16x16_p_##name( pixel *src )\ +{\ + PREDICT_16x16_P_CORE\ + PREDICT_16x16_P_END(name2)\ +} + +#if HAVE_X86_INLINE_ASM +#if HIGH_BIT_DEPTH +#define PREDICT_16x16_P_ASM\ + asm (\ + "movdqu %1, %%xmm1 \n"\ + "movdqa %2, %%xmm0 \n"\ + "pmaddwd %3, %%xmm0 \n"\ + "pmaddwd %4, %%xmm1 \n"\ + "paddd %%xmm1, %%xmm0 \n"\ + "movhlps %%xmm0, %%xmm1 \n"\ + "paddd %%xmm1, %%xmm0 \n"\ + "pshuflw $14, %%xmm0, %%xmm1 \n"\ + "paddd %%xmm1, %%xmm0 \n"\ + "movd %%xmm0, %0 \n"\ + :"=r"(H)\ + :"m"(src[-FDEC_STRIDE-1]), "m"(src[-FDEC_STRIDE+8]),\ + "m"(*pw_12345678), "m"(*pw_m87654321)\ + ); +#else // !HIGH_BIT_DEPTH +#define PREDICT_16x16_P_ASM\ + asm (\ + "movq %1, %%mm1 \n"\ + "movq %2, %%mm0 \n"\ + "palignr $7, %3, %%mm1 \n"\ + "pmaddubsw %4, %%mm0 \n"\ + "pmaddubsw %5, %%mm1 \n"\ + "paddw %%mm1, %%mm0 \n"\ + "pshufw $14, %%mm0, %%mm1 \n"\ + "paddw %%mm1, %%mm0 \n"\ + "pshufw $1, %%mm0, %%mm1 \n"\ + "paddw %%mm1, %%mm0 \n"\ + "movd %%mm0, %0 \n"\ + "movswl %w0, %0 \n"\ + :"=r"(H)\ + :"m"(src[-FDEC_STRIDE]), "m"(src[-FDEC_STRIDE+8]),\ + "m"(src[-FDEC_STRIDE-8]), "m"(*pb_12345678), "m"(*pb_m87654321)\ + ); +#endif // HIGH_BIT_DEPTH + +#define PREDICT_16x16_P_CORE_INLINE\ + int H, V;\ + PREDICT_16x16_P_ASM\ + V = 8 * ( src[15*FDEC_STRIDE-1] - src[-1*FDEC_STRIDE-1] )\ + + 7 * ( src[14*FDEC_STRIDE-1] - src[ 0*FDEC_STRIDE-1] )\ + + 6 * ( src[13*FDEC_STRIDE-1] - src[ 1*FDEC_STRIDE-1] )\ + + 5 * ( src[12*FDEC_STRIDE-1] - src[ 2*FDEC_STRIDE-1] )\ + + 4 * ( src[11*FDEC_STRIDE-1] - src[ 3*FDEC_STRIDE-1] )\ + + 3 * ( src[10*FDEC_STRIDE-1] - src[ 4*FDEC_STRIDE-1] )\ + + 2 * ( src[ 9*FDEC_STRIDE-1] - src[ 5*FDEC_STRIDE-1] )\ + + 1 * ( src[ 8*FDEC_STRIDE-1] - src[ 6*FDEC_STRIDE-1] ); + +#define PREDICT_16x16_P_INLINE(name, name2)\ +static void x264_predict_16x16_p_##name( pixel *src )\ +{\ + PREDICT_16x16_P_CORE_INLINE\ + PREDICT_16x16_P_END(name2)\ +} +#else // !HAVE_X86_INLINE_ASM +#define PREDICT_16x16_P_INLINE(name, name2) PREDICT_16x16_P(name, name2) +#endif // HAVE_X86_INLINE_ASM + +#if HIGH_BIT_DEPTH +PREDICT_16x16_P_INLINE( sse2, sse2 ) +#else // !HIGH_BIT_DEPTH +#if !ARCH_X86_64 +PREDICT_16x16_P( mmx2, mmx2 ) +#endif // !ARCH_X86_64 +PREDICT_16x16_P( sse2, sse2 ) +#if HAVE_X86_INLINE_ASM +PREDICT_16x16_P_INLINE( ssse3, sse2 ) +#endif // HAVE_X86_INLINE_ASM +PREDICT_16x16_P_INLINE( avx, avx ) +#endif // HIGH_BIT_DEPTH +PREDICT_16x16_P_INLINE( avx2, avx2 ) + +#define PREDICT_8x16C_P_CORE\ + int H = 0, V = 0;\ + for( int i = 0; i < 4; i++ )\ + H += ( i + 1 ) * ( src[4 + i - FDEC_STRIDE] - src[2 - i - FDEC_STRIDE] );\ + for( int i = 0; i < 8; i++ )\ + V += ( i + 1 ) * ( src[-1 + (i+8)*FDEC_STRIDE] - src[-1 + (6-i)*FDEC_STRIDE] ); + +#if HIGH_BIT_DEPTH +#define PREDICT_8x16C_P_END(name)\ + int a = 16 * ( src[-1 + 15*FDEC_STRIDE] + src[7 - FDEC_STRIDE] );\ + int b = ( 17 * H + 16 ) >> 5;\ + int c = ( 5 * V + 32 ) >> 6;\ + x264_predict_8x16c_p_core_##name( src, a, b, c ); +#else // !HIGH_BIT_DEPTH +#define PREDICT_8x16C_P_END(name)\ + int a = 16 * ( src[-1 + 15*FDEC_STRIDE] + src[7 - FDEC_STRIDE] );\ + int b = ( 17 * H + 16 ) >> 5;\ + int c = ( 5 * V + 32 ) >> 6;\ + int i00 = a -3*b -7*c + 16;\ + x264_predict_8x16c_p_core_##name( src, i00, b, c ); +#endif // HIGH_BIT_DEPTH + +#define PREDICT_8x16C_P(name)\ +static void x264_predict_8x16c_p_##name( pixel *src )\ +{\ + PREDICT_8x16C_P_CORE\ + PREDICT_8x16C_P_END(name)\ +} + +#if !ARCH_X86_64 && !HIGH_BIT_DEPTH +PREDICT_8x16C_P( mmx2 ) +#endif // !ARCH_X86_64 && !HIGH_BIT_DEPTH +PREDICT_8x16C_P( sse2 ) +PREDICT_8x16C_P( avx ) +PREDICT_8x16C_P( avx2 ) + +#define PREDICT_8x8C_P_CORE\ + int H = 0;\ + int V = 0;\ + PREDICT_P_SUM(3,1)\ + PREDICT_P_SUM(3,2)\ + PREDICT_P_SUM(3,3)\ + PREDICT_P_SUM(3,4) + +#if HIGH_BIT_DEPTH +#define PREDICT_8x8C_P_END(name)\ + int a = 16 * ( src[7*FDEC_STRIDE -1] + src[7 - FDEC_STRIDE] );\ + int b = ( 17 * H + 16 ) >> 5;\ + int c = ( 17 * V + 16 ) >> 5;\ + x264_predict_8x8c_p_core_##name( src, a, b, c ); +#else // !HIGH_BIT_DEPTH +#define PREDICT_8x8C_P_END(name)\ + int a = 16 * ( src[7*FDEC_STRIDE -1] + src[7 - FDEC_STRIDE] );\ + int b = ( 17 * H + 16 ) >> 5;\ + int c = ( 17 * V + 16 ) >> 5;\ + int i00 = a -3*b -3*c + 16;\ + x264_predict_8x8c_p_core_##name( src, i00, b, c ); +#endif // HIGH_BIT_DEPTH + +#define PREDICT_8x8C_P(name, name2)\ +static void x264_predict_8x8c_p_##name( pixel *src )\ +{\ + PREDICT_8x8C_P_CORE\ + PREDICT_8x8C_P_END(name2)\ +} + +#if HAVE_X86_INLINE_ASM +#if HIGH_BIT_DEPTH +#define PREDICT_8x8C_P_ASM\ + asm (\ + "movdqa %1, %%xmm0 \n"\ + "pmaddwd %2, %%xmm0 \n"\ + "movhlps %%xmm0, %%xmm1 \n"\ + "paddd %%xmm1, %%xmm0 \n"\ + "pshuflw $14, %%xmm0, %%xmm1 \n"\ + "paddd %%xmm1, %%xmm0 \n"\ + "movd %%xmm0, %0 \n"\ + :"=r"(H)\ + :"m"(src[-FDEC_STRIDE]), "m"(*pw_m32101234)\ + ); +#else // !HIGH_BIT_DEPTH +#define PREDICT_8x8C_P_ASM\ + asm (\ + "movq %1, %%mm0 \n"\ + "pmaddubsw %2, %%mm0 \n"\ + "pshufw $14, %%mm0, %%mm1 \n"\ + "paddw %%mm1, %%mm0 \n"\ + "pshufw $1, %%mm0, %%mm1 \n"\ + "paddw %%mm1, %%mm0 \n"\ + "movd %%mm0, %0 \n"\ + "movswl %w0, %0 \n"\ + :"=r"(H)\ + :"m"(src[-FDEC_STRIDE]), "m"(*pb_m32101234)\ + ); +#endif // HIGH_BIT_DEPTH + +#define PREDICT_8x8C_P_CORE_INLINE\ + int H, V;\ + PREDICT_8x8C_P_ASM\ + V = 1 * ( src[4*FDEC_STRIDE -1] - src[ 2*FDEC_STRIDE -1] )\ + + 2 * ( src[5*FDEC_STRIDE -1] - src[ 1*FDEC_STRIDE -1] )\ + + 3 * ( src[6*FDEC_STRIDE -1] - src[ 0*FDEC_STRIDE -1] )\ + + 4 * ( src[7*FDEC_STRIDE -1] - src[-1*FDEC_STRIDE -1] );\ + H += -4 * src[-1*FDEC_STRIDE -1]; + +#define PREDICT_8x8C_P_INLINE(name, name2)\ +static void x264_predict_8x8c_p_##name( pixel *src )\ +{\ + PREDICT_8x8C_P_CORE_INLINE\ + PREDICT_8x8C_P_END(name2)\ +} +#else // !HAVE_X86_INLINE_ASM +#define PREDICT_8x8C_P_INLINE(name, name2) PREDICT_8x8C_P(name, name2) +#endif // HAVE_X86_INLINE_ASM + +#if HIGH_BIT_DEPTH +PREDICT_8x8C_P_INLINE( sse2, sse2 ) +#else //!HIGH_BIT_DEPTH +#if !ARCH_X86_64 +PREDICT_8x8C_P( mmx2, mmx2 ) +#endif // !ARCH_X86_64 +PREDICT_8x8C_P( sse2, sse2 ) +#if HAVE_X86_INLINE_ASM +PREDICT_8x8C_P_INLINE( ssse3, sse2 ) +#endif // HAVE_X86_INLINE_ASM +#endif // HIGH_BIT_DEPTH +PREDICT_8x8C_P_INLINE( avx, avx ) +PREDICT_8x8C_P_INLINE( avx2, avx2 ) + +#if ARCH_X86_64 && !HIGH_BIT_DEPTH +static void x264_predict_8x8c_dc_left( uint8_t *src ) +{ + int y; + uint32_t s0 = 0, s1 = 0; + uint64_t dc0, dc1; + + for( y = 0; y < 4; y++ ) + { + s0 += src[y * FDEC_STRIDE - 1]; + s1 += src[(y+4) * FDEC_STRIDE - 1]; + } + dc0 = (( s0 + 2 ) >> 2) * 0x0101010101010101ULL; + dc1 = (( s1 + 2 ) >> 2) * 0x0101010101010101ULL; + + for( y = 0; y < 4; y++ ) + { + M64( src ) = dc0; + src += FDEC_STRIDE; + } + for( y = 0; y < 4; y++ ) + { + M64( src ) = dc1; + src += FDEC_STRIDE; + } +} +#endif // ARCH_X86_64 && !HIGH_BIT_DEPTH + +/**************************************************************************** + * Exported functions: + ****************************************************************************/ +void x264_predict_16x16_init_mmx( int cpu, x264_predict_t pf[7] ) +{ + if( !(cpu&X264_CPU_MMX2) ) + return; + pf[I_PRED_16x16_V] = x264_predict_16x16_v_mmx2; + pf[I_PRED_16x16_H] = x264_predict_16x16_h_mmx2; +#if HIGH_BIT_DEPTH + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_16x16_V] = x264_predict_16x16_v_sse; + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_sse2; + pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_sse2; + pf[I_PRED_16x16_DC_LEFT] = x264_predict_16x16_dc_left_sse2; + pf[I_PRED_16x16_H] = x264_predict_16x16_h_sse2; + pf[I_PRED_16x16_P] = x264_predict_16x16_p_sse2; + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_16x16_V] = x264_predict_16x16_v_avx; + if( !(cpu&X264_CPU_AVX2) ) + return; + pf[I_PRED_16x16_H] = x264_predict_16x16_h_avx2; +#else +#if !ARCH_X86_64 + pf[I_PRED_16x16_P] = x264_predict_16x16_p_mmx2; +#endif + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_16x16_V] = x264_predict_16x16_v_sse; + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_sse2; + if( cpu&X264_CPU_SSE2_IS_SLOW ) + return; + pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_sse2; + pf[I_PRED_16x16_DC_LEFT] = x264_predict_16x16_dc_left_sse2; + pf[I_PRED_16x16_P] = x264_predict_16x16_p_sse2; + if( !(cpu&X264_CPU_SSSE3) ) + return; + if( !(cpu&X264_CPU_SLOW_PSHUFB) ) + pf[I_PRED_16x16_H] = x264_predict_16x16_h_ssse3; +#if HAVE_X86_INLINE_ASM + pf[I_PRED_16x16_P] = x264_predict_16x16_p_ssse3; +#endif + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_16x16_P] = x264_predict_16x16_p_avx; +#endif // HIGH_BIT_DEPTH + + if( cpu&X264_CPU_AVX2 ) + { + pf[I_PRED_16x16_P] = x264_predict_16x16_p_avx2; + pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_avx2; + pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_avx2; + pf[I_PRED_16x16_DC_LEFT] = x264_predict_16x16_dc_left_avx2; + } +} + +void x264_predict_8x8c_init_mmx( int cpu, x264_predict_t pf[7] ) +{ + if( !(cpu&X264_CPU_MMX) ) + return; +#if HIGH_BIT_DEPTH + pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_mmx; + if( !(cpu&X264_CPU_MMX2) ) + return; + pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_mmx2; + pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_mmx2; + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_sse; + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_sse2; + pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_sse2; + pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_sse2; + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_sse2; + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_avx; + if( !(cpu&X264_CPU_AVX2) ) + return; + pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_avx2; +#else +#if ARCH_X86_64 + pf[I_PRED_CHROMA_DC_LEFT] = x264_predict_8x8c_dc_left; +#endif + pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_mmx; + if( !(cpu&X264_CPU_MMX2) ) + return; + pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_mmx2; + pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_mmx2; +#if !ARCH_X86_64 + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_mmx2; +#endif + pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_mmx2; + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_sse2; + if( !(cpu&X264_CPU_SSSE3) ) + return; + pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_ssse3; +#if HAVE_X86_INLINE_ASM + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_ssse3; +#endif + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_avx; +#endif // HIGH_BIT_DEPTH + + if( cpu&X264_CPU_AVX2 ) + { + pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_avx2; + } +} + +void x264_predict_8x16c_init_mmx( int cpu, x264_predict_t pf[7] ) +{ + if( !(cpu&X264_CPU_MMX) ) + return; +#if HIGH_BIT_DEPTH + if( !(cpu&X264_CPU_MMX2) ) + return; + pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_mmx2; + pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_mmx2; + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_CHROMA_V] = x264_predict_8x16c_v_sse; + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x16c_dc_top_sse2; + pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_sse2; + pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_sse2; + pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_sse2; + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_avx; + if( !(cpu&X264_CPU_AVX2) ) + return; + pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_avx2; +#else + pf[I_PRED_CHROMA_V] = x264_predict_8x16c_v_mmx; + if( !(cpu&X264_CPU_MMX2) ) + return; + pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x16c_dc_top_mmx2; + pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_mmx2; + pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_mmx2; +#if !ARCH_X86_64 + pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_mmx2; +#endif + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_sse2; + if( !(cpu&X264_CPU_SSSE3) ) + return; + pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_ssse3; + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_avx; +#endif // HIGH_BIT_DEPTH + + if( cpu&X264_CPU_AVX2 ) + { + pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_avx2; + } +} + +void x264_predict_8x8_init_mmx( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_8x8_filter ) +{ + if( !(cpu&X264_CPU_MMX2) ) + return; +#if HIGH_BIT_DEPTH + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_8x8_V] = x264_predict_8x8_v_sse; + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_8x8_H] = x264_predict_8x8_h_sse2; + pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_sse2; + pf[I_PRED_8x8_DC_TOP] = x264_predict_8x8_dc_top_sse2; + pf[I_PRED_8x8_DC_LEFT]= x264_predict_8x8_dc_left_sse2; + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_sse2; + pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_sse2; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_sse2; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_sse2; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_sse2; + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_sse2; + *predict_8x8_filter = x264_predict_8x8_filter_sse2; + if( !(cpu&X264_CPU_SSSE3) ) + return; + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_ssse3; + pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_ssse3; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_ssse3; + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_ssse3; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_ssse3; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_ssse3; + *predict_8x8_filter = x264_predict_8x8_filter_ssse3; + if( cpu&X264_CPU_CACHELINE_64 ) + { + pf[I_PRED_8x8_DDL]= x264_predict_8x8_ddl_cache64_ssse3; + pf[I_PRED_8x8_DDR]= x264_predict_8x8_ddr_cache64_ssse3; + } + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_avx; + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_avx; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_avx; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_avx; + *predict_8x8_filter = x264_predict_8x8_filter_avx; +#else + pf[I_PRED_8x8_V] = x264_predict_8x8_v_mmx2; + pf[I_PRED_8x8_H] = x264_predict_8x8_h_mmx2; + pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_mmx2; + pf[I_PRED_8x8_DC_TOP] = x264_predict_8x8_dc_top_mmx2; + pf[I_PRED_8x8_DC_LEFT]= x264_predict_8x8_dc_left_mmx2; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_mmx2; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_mmx2; + *predict_8x8_filter = x264_predict_8x8_filter_mmx2; +#if ARCH_X86 + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_mmx2; + pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_mmx2; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_mmx2; + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_mmx2; +#endif + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_sse2; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_sse2; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_sse2; + pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_sse2; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_sse2; + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_sse2; + if( !(cpu&X264_CPU_SSSE3) ) + return; + if( !(cpu&X264_CPU_SLOW_PALIGNR) ) + { + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_ssse3; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_ssse3; + } + pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_ssse3; + *predict_8x8_filter = x264_predict_8x8_filter_ssse3; + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_avx; + pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_avx; + pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_avx; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_avx; + pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_avx; +#endif // HIGH_BIT_DEPTH +} + +void x264_predict_4x4_init_mmx( int cpu, x264_predict_t pf[12] ) +{ + if( !(cpu&X264_CPU_MMX2) ) + return; + pf[I_PRED_4x4_DC] = x264_predict_4x4_dc_mmx2; + pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_mmx2; + pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_mmx2; + pf[I_PRED_4x4_VL] = x264_predict_4x4_vl_mmx2; + pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_mmx2; + pf[I_PRED_4x4_HU] = x264_predict_4x4_hu_mmx2; +#if HIGH_BIT_DEPTH + if( !(cpu&X264_CPU_SSE2) ) + return; + pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_sse2; + pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_sse2; + pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_sse2; + pf[I_PRED_4x4_VL] = x264_predict_4x4_vl_sse2; + pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_sse2; + if( !(cpu&X264_CPU_SSSE3) ) + return; + pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_ssse3; + pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_ssse3; + pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_ssse3; + if( !(cpu&X264_CPU_AVX) ) + return; + pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_avx; + pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_avx; + pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_avx; + pf[I_PRED_4x4_VL] = x264_predict_4x4_vl_avx; + pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_avx; + if( !(cpu&X264_CPU_AVX2) ) + return; + pf[I_PRED_4x4_H] = x264_predict_4x4_h_avx2; +#else + pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_mmx2; + if( !(cpu&X264_CPU_SSSE3) ) + return; + pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_ssse3; + pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_ssse3; + pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_ssse3; + if( cpu&X264_CPU_CACHELINE_64 ) + pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_cache64_ssse3; +#endif // HIGH_BIT_DEPTH +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/predict.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/predict.h new file mode 100644 index 00000000..9f9052c2 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/predict.h @@ -0,0 +1,144 @@ +/***************************************************************************** + * predict.h: x86 intra prediction + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_I386_PREDICT_H +#define X264_I386_PREDICT_H + +void x264_predict_16x16_init_mmx( int cpu, x264_predict_t pf[7] ); +void x264_predict_8x16c_init_mmx( int cpu, x264_predict_t pf[7] ); +void x264_predict_8x8c_init_mmx ( int cpu, x264_predict_t pf[7] ); +void x264_predict_4x4_init_mmx ( int cpu, x264_predict_t pf[12] ); +void x264_predict_8x8_init_mmx ( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_8x8_filter ); + +void x264_predict_16x16_v_mmx2( pixel *src ); +void x264_predict_16x16_v_sse ( pixel *src ); +void x264_predict_16x16_v_avx ( uint16_t *src ); +void x264_predict_16x16_h_mmx2( pixel *src ); +void x264_predict_16x16_h_sse2( uint16_t *src ); +void x264_predict_16x16_h_ssse3( uint8_t *src ); +void x264_predict_16x16_h_avx2( uint16_t *src ); +void x264_predict_16x16_dc_sse2( pixel *src ); +void x264_predict_16x16_dc_avx2( pixel *src ); +void x264_predict_16x16_dc_left_sse2( pixel *src ); +void x264_predict_16x16_dc_left_avx2( pixel *src ); +void x264_predict_16x16_dc_top_sse2( pixel *src ); +void x264_predict_16x16_dc_top_avx2( pixel *src ); +void x264_predict_16x16_p_core_mmx2( uint8_t *src, int i00, int b, int c ); +void x264_predict_16x16_p_core_sse2( pixel *src, int i00, int b, int c ); +void x264_predict_16x16_p_core_avx( pixel *src, int i00, int b, int c ); +void x264_predict_16x16_p_core_avx2( pixel *src, int i00, int b, int c ); +void x264_predict_8x16c_dc_mmx2( pixel *src ); +void x264_predict_8x16c_dc_sse2( uint16_t *src ); +void x264_predict_8x16c_dc_top_mmx2( uint8_t *src ); +void x264_predict_8x16c_dc_top_sse2( uint16_t *src ); +void x264_predict_8x16c_v_mmx( uint8_t *src ); +void x264_predict_8x16c_v_sse( uint16_t *src ); +void x264_predict_8x16c_h_mmx2( pixel *src ); +void x264_predict_8x16c_h_sse2( uint16_t *src ); +void x264_predict_8x16c_h_ssse3( uint8_t *src ); +void x264_predict_8x16c_h_avx2( uint16_t *src ); +void x264_predict_8x16c_p_core_mmx2( uint8_t *src, int i00, int b, int c ); +void x264_predict_8x16c_p_core_sse2( pixel *src, int i00, int b, int c ); +void x264_predict_8x16c_p_core_avx ( pixel *src, int i00, int b, int c ); +void x264_predict_8x16c_p_core_avx2( pixel *src, int i00, int b, int c ); +void x264_predict_8x8c_p_core_mmx2( uint8_t *src, int i00, int b, int c ); +void x264_predict_8x8c_p_core_sse2( pixel *src, int i00, int b, int c ); +void x264_predict_8x8c_p_core_avx ( pixel *src, int i00, int b, int c ); +void x264_predict_8x8c_p_core_avx2( pixel *src, int i00, int b, int c ); +void x264_predict_8x8c_dc_mmx2( pixel *src ); +void x264_predict_8x8c_dc_sse2( uint16_t *src ); +void x264_predict_8x8c_dc_top_mmx2( uint8_t *src ); +void x264_predict_8x8c_dc_top_sse2( uint16_t *src ); +void x264_predict_8x8c_v_mmx( pixel *src ); +void x264_predict_8x8c_v_sse( uint16_t *src ); +void x264_predict_8x8c_h_mmx2( pixel *src ); +void x264_predict_8x8c_h_sse2( uint16_t *src ); +void x264_predict_8x8c_h_ssse3( uint8_t *src ); +void x264_predict_8x8c_h_avx2( uint16_t *src ); +void x264_predict_8x8_v_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_v_sse ( uint16_t *src, uint16_t edge[36] ); +void x264_predict_8x8_h_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_h_sse2( uint16_t *src, uint16_t edge[36] ); +void x264_predict_8x8_hd_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_hu_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_dc_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_dc_sse2( uint16_t *src, uint16_t edge[36] ); +void x264_predict_8x8_dc_top_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_dc_top_sse2( uint16_t *src, uint16_t edge[36] ); +void x264_predict_8x8_dc_left_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_dc_left_sse2( uint16_t *src, uint16_t edge[36] ); +void x264_predict_8x8_ddl_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_ddl_sse2( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddl_ssse3( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddl_cache64_ssse3( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddl_avx( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddr_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_ddr_sse2( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddr_ssse3( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddr_cache64_ssse3( pixel *src, pixel edge[36] ); +void x264_predict_8x8_ddr_avx( pixel *src, pixel edge[36] ); +void x264_predict_8x8_vl_sse2( pixel *src, pixel edge[36] ); +void x264_predict_8x8_vl_ssse3( pixel *src, pixel edge[36] ); +void x264_predict_8x8_vl_avx( pixel *src, pixel edge[36] ); +void x264_predict_8x8_vl_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_vr_mmx2( uint8_t *src, uint8_t edge[36] ); +void x264_predict_8x8_vr_sse2( pixel *src, pixel edge[36] ); +void x264_predict_8x8_vr_ssse3( pixel *src, pixel edge[36] ); +void x264_predict_8x8_vr_avx( pixel *src, pixel edge[36] ); +void x264_predict_8x8_hu_sse2( pixel *src, pixel edge[36] ); +void x264_predict_8x8_hu_ssse3( pixel *src, pixel edge[36] ); +void x264_predict_8x8_hu_avx( pixel *src, pixel edge[36] ); +void x264_predict_8x8_hd_sse2( pixel *src, pixel edge[36] ); +void x264_predict_8x8_hd_ssse3( pixel *src, pixel edge[36] ); +void x264_predict_8x8_hd_avx( pixel *src, pixel edge[36] ); +void x264_predict_8x8_filter_mmx2( uint8_t *src, uint8_t edge[36], int i_neighbor, int i_filters ); +void x264_predict_8x8_filter_sse2( uint16_t *src, uint16_t edge[36], int i_neighbor, int i_filters ); +void x264_predict_8x8_filter_ssse3( pixel *src, pixel edge[36], int i_neighbor, int i_filters ); +void x264_predict_8x8_filter_avx( uint16_t *src, uint16_t edge[36], int i_neighbor, int i_filters ); +void x264_predict_4x4_h_avx2( uint16_t *src ); +void x264_predict_4x4_ddl_mmx2( pixel *src ); +void x264_predict_4x4_ddl_sse2( uint16_t *src ); +void x264_predict_4x4_ddl_avx( uint16_t *src ); +void x264_predict_4x4_ddr_mmx2( pixel *src ); +void x264_predict_4x4_vl_mmx2( pixel *src ); +void x264_predict_4x4_vl_sse2( uint16_t *src ); +void x264_predict_4x4_vl_avx( uint16_t *src ); +void x264_predict_4x4_vr_mmx2( uint8_t *src ); +void x264_predict_4x4_vr_sse2( uint16_t *src ); +void x264_predict_4x4_vr_ssse3( pixel *src ); +void x264_predict_4x4_vr_cache64_ssse3( uint8_t *src ); +void x264_predict_4x4_vr_avx( uint16_t *src ); +void x264_predict_4x4_hd_mmx2( pixel *src ); +void x264_predict_4x4_hd_sse2( uint16_t *src ); +void x264_predict_4x4_hd_ssse3( pixel *src ); +void x264_predict_4x4_hd_avx( uint16_t *src ); +void x264_predict_4x4_dc_mmx2( pixel *src ); +void x264_predict_4x4_ddr_sse2( uint16_t *src ); +void x264_predict_4x4_ddr_ssse3( pixel *src ); +void x264_predict_4x4_ddr_avx( uint16_t *src ); +void x264_predict_4x4_hu_mmx2( pixel *src ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/quant.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/quant.h new file mode 100644 index 00000000..6b74aace --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/quant.h @@ -0,0 +1,156 @@ +/***************************************************************************** + * quant.h: x86 quantization and level-run + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: Loren Merritt + * Fiona Glaser + * Christian Heine + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_I386_QUANT_H +#define X264_I386_QUANT_H + +int x264_quant_2x2_dc_mmx2( dctcoef dct[4], int mf, int bias ); +int x264_quant_4x4_dc_mmx2( dctcoef dct[16], int mf, int bias ); +int x264_quant_4x4_mmx2( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_8x8_mmx2( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); +int x264_quant_2x2_dc_sse2( dctcoef dct[16], int mf, int bias ); +int x264_quant_4x4_dc_sse2( dctcoef dct[16], int mf, int bias ); +int x264_quant_4x4_sse2( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_4x4x4_sse2( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_8x8_sse2( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); +int x264_quant_2x2_dc_ssse3( dctcoef dct[4], int mf, int bias ); +int x264_quant_4x4_dc_ssse3( dctcoef dct[16], int mf, int bias ); +int x264_quant_4x4_ssse3( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_4x4x4_ssse3( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_8x8_ssse3( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); +int x264_quant_2x2_dc_sse4( dctcoef dct[16], int mf, int bias ); +int x264_quant_4x4_dc_sse4( dctcoef dct[16], int mf, int bias ); +int x264_quant_4x4_sse4( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_4x4x4_sse4( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_8x8_sse4( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); +int x264_quant_4x4_avx2( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_4x4_dc_avx2( dctcoef dct[16], int mf, int bias ); +int x264_quant_8x8_avx2( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); +int x264_quant_4x4x4_avx2( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); +void x264_dequant_4x4_mmx( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_4x4dc_mmx2( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_mmx( int16_t dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_sse2( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_4x4dc_sse2( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_sse2( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_avx( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_4x4dc_avx( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_avx( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_xop( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_4x4dc_xop( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_xop( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_avx2( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_4x4dc_avx2( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_avx2( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_avx512( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_avx512( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_flat16_mmx( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_flat16_mmx( int16_t dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_flat16_sse2( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_flat16_sse2( int16_t dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_4x4_flat16_avx2( int16_t dct[16], int dequant_mf[6][16], int i_qp ); +void x264_dequant_8x8_flat16_avx2( int16_t dct[64], int dequant_mf[6][64], int i_qp ); +void x264_dequant_8x8_flat16_avx512( int16_t dct[64], int dequant_mf[6][64], int i_qp ); +void x264_idct_dequant_2x4_dc_sse2( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp ); +void x264_idct_dequant_2x4_dc_avx ( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp ); +void x264_idct_dequant_2x4_dconly_sse2( dctcoef dct[8], int dequant_mf[6][16], int i_qp ); +void x264_idct_dequant_2x4_dconly_avx ( dctcoef dct[8], int dequant_mf[6][16], int i_qp ); +int x264_optimize_chroma_2x2_dc_sse2( dctcoef dct[4], int dequant_mf ); +int x264_optimize_chroma_2x2_dc_ssse3( dctcoef dct[4], int dequant_mf ); +int x264_optimize_chroma_2x2_dc_sse4( dctcoef dct[4], int dequant_mf ); +int x264_optimize_chroma_2x2_dc_avx( dctcoef dct[4], int dequant_mf ); +void x264_denoise_dct_mmx ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); +void x264_denoise_dct_sse2 ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); +void x264_denoise_dct_ssse3( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); +void x264_denoise_dct_avx ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); +void x264_denoise_dct_avx2 ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); +int x264_decimate_score15_sse2( dctcoef *dct ); +int x264_decimate_score15_ssse3( dctcoef *dct ); +int x264_decimate_score15_avx512( dctcoef *dct ); +int x264_decimate_score16_sse2( dctcoef *dct ); +int x264_decimate_score16_ssse3( dctcoef *dct ); +int x264_decimate_score16_avx512( dctcoef *dct ); +int x264_decimate_score64_sse2( dctcoef *dct ); +int x264_decimate_score64_ssse3( dctcoef *dct ); +int x264_decimate_score64_avx2( int16_t *dct ); +int x264_decimate_score64_avx512( dctcoef *dct ); +int x264_coeff_last4_mmx2( dctcoef *dct ); +int x264_coeff_last8_mmx2( dctcoef *dct ); +int x264_coeff_last15_mmx2( dctcoef *dct ); +int x264_coeff_last16_mmx2( dctcoef *dct ); +int x264_coeff_last64_mmx2( dctcoef *dct ); +int x264_coeff_last8_sse2( dctcoef *dct ); +int x264_coeff_last15_sse2( dctcoef *dct ); +int x264_coeff_last16_sse2( dctcoef *dct ); +int x264_coeff_last64_sse2( dctcoef *dct ); +int x264_coeff_last4_lzcnt( dctcoef *dct ); +int x264_coeff_last8_lzcnt( dctcoef *dct ); +int x264_coeff_last15_lzcnt( dctcoef *dct ); +int x264_coeff_last16_lzcnt( dctcoef *dct ); +int x264_coeff_last64_lzcnt( dctcoef *dct ); +int x264_coeff_last64_avx2 ( dctcoef *dct ); +int x264_coeff_last4_avx512( int32_t *dct ); +int x264_coeff_last8_avx512( dctcoef *dct ); +int x264_coeff_last15_avx512( dctcoef *dct ); +int x264_coeff_last16_avx512( dctcoef *dct ); +int x264_coeff_last64_avx512( dctcoef *dct ); +int x264_coeff_level_run16_mmx2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run16_sse2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run16_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run16_ssse3( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run16_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run16_avx2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run15_mmx2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run15_sse2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run15_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run15_ssse3( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run15_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run15_avx2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run4_mmx2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run4_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run4_ssse3( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run4_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run8_mmx2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run8_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run8_sse2( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run8_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run8_ssse3( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_coeff_level_run8_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel ); +int x264_trellis_cabac_4x4_sse2 ( TRELLIS_PARAMS, int b_ac ); +int x264_trellis_cabac_4x4_ssse3( TRELLIS_PARAMS, int b_ac ); +int x264_trellis_cabac_8x8_sse2 ( TRELLIS_PARAMS, int b_interlaced ); +int x264_trellis_cabac_8x8_ssse3( TRELLIS_PARAMS, int b_interlaced ); +int x264_trellis_cabac_4x4_psy_sse2 ( TRELLIS_PARAMS, int b_ac, dctcoef *fenc_dct, int i_psy_trellis ); +int x264_trellis_cabac_4x4_psy_ssse3( TRELLIS_PARAMS, int b_ac, dctcoef *fenc_dct, int i_psy_trellis ); +int x264_trellis_cabac_8x8_psy_sse2 ( TRELLIS_PARAMS, int b_interlaced, dctcoef *fenc_dct, int i_psy_trellis ); +int x264_trellis_cabac_8x8_psy_ssse3( TRELLIS_PARAMS, int b_interlaced, dctcoef *fenc_dct, int i_psy_trellis ); +int x264_trellis_cabac_dc_sse2 ( TRELLIS_PARAMS, int i_coefs ); +int x264_trellis_cabac_dc_ssse3( TRELLIS_PARAMS, int i_coefs ); +int x264_trellis_cabac_chroma_422_dc_sse2 ( TRELLIS_PARAMS ); +int x264_trellis_cabac_chroma_422_dc_ssse3( TRELLIS_PARAMS ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/util.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/util.h new file mode 100644 index 00000000..d5e15ba3 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/common/x86/util.h @@ -0,0 +1,254 @@ +/***************************************************************************** + * util.h: x86 inline asm + ***************************************************************************** + * Copyright (C) 2008-2017 x264 project + * + * Authors: Fiona Glaser + * Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_X86_UTIL_H +#define X264_X86_UTIL_H + +#ifdef __SSE__ +#include + +#undef M128_ZERO +#define M128_ZERO ((__m128){0,0,0,0}) +#define x264_union128_t x264_union128_sse_t +typedef union { __m128 i; uint64_t a[2]; uint32_t b[4]; uint16_t c[8]; uint8_t d[16]; } MAY_ALIAS x264_union128_sse_t; +#if HAVE_VECTOREXT +typedef uint32_t v4si __attribute__((vector_size (16))); +#endif +#endif // __SSE__ + +#if HAVE_X86_INLINE_ASM && HAVE_MMX + +#define x264_median_mv x264_median_mv_mmx2 +static ALWAYS_INLINE void x264_median_mv_mmx2( int16_t *dst, int16_t *a, int16_t *b, int16_t *c ) +{ + asm( + "movd %1, %%mm0 \n" + "movd %2, %%mm1 \n" + "movq %%mm0, %%mm3 \n" + "movd %3, %%mm2 \n" + "pmaxsw %%mm1, %%mm0 \n" + "pminsw %%mm3, %%mm1 \n" + "pminsw %%mm2, %%mm0 \n" + "pmaxsw %%mm1, %%mm0 \n" + "movd %%mm0, %0 \n" + :"=m"(*(x264_union32_t*)dst) + :"m"(M32( a )), "m"(M32( b )), "m"(M32( c )) + ); +} + +#define x264_predictor_difference x264_predictor_difference_mmx2 +static ALWAYS_INLINE int x264_predictor_difference_mmx2( int16_t (*mvc)[2], intptr_t i_mvc ) +{ + int sum; + static const uint64_t pw_1 = 0x0001000100010001ULL; + + asm( + "pxor %%mm4, %%mm4 \n" + "test $1, %1 \n" + "jnz 3f \n" + "movd -8(%2,%1,4), %%mm0 \n" + "movd -4(%2,%1,4), %%mm3 \n" + "psubw %%mm3, %%mm0 \n" + "jmp 2f \n" + "3: \n" + "dec %1 \n" + "1: \n" + "movq -8(%2,%1,4), %%mm0 \n" + "psubw -4(%2,%1,4), %%mm0 \n" + "2: \n" + "sub $2, %1 \n" + "pxor %%mm2, %%mm2 \n" + "psubw %%mm0, %%mm2 \n" + "pmaxsw %%mm2, %%mm0 \n" + "paddusw %%mm0, %%mm4 \n" + "jg 1b \n" + "pmaddwd %4, %%mm4 \n" + "pshufw $14, %%mm4, %%mm0 \n" + "paddd %%mm0, %%mm4 \n" + "movd %%mm4, %0 \n" + :"=r"(sum), "+r"(i_mvc) + :"r"(mvc), "m"(M64( mvc )), "m"(pw_1) + ); + return sum; +} + +#define x264_cabac_mvd_sum x264_cabac_mvd_sum_mmx2 +static ALWAYS_INLINE uint16_t x264_cabac_mvd_sum_mmx2(uint8_t *mvdleft, uint8_t *mvdtop) +{ + static const uint64_t pb_2 = 0x0202020202020202ULL; + static const uint64_t pb_32 = 0x2020202020202020ULL; + static const uint64_t pb_33 = 0x2121212121212121ULL; + int amvd; + asm( + "movd %1, %%mm0 \n" + "movd %2, %%mm1 \n" + "paddusb %%mm1, %%mm0 \n" + "pminub %5, %%mm0 \n" + "pxor %%mm2, %%mm2 \n" + "movq %%mm0, %%mm1 \n" + "pcmpgtb %3, %%mm0 \n" + "pcmpgtb %4, %%mm1 \n" + "psubb %%mm0, %%mm2 \n" + "psubb %%mm1, %%mm2 \n" + "movd %%mm2, %0 \n" + :"=r"(amvd) + :"m"(M16( mvdleft )),"m"(M16( mvdtop )), + "m"(pb_2),"m"(pb_32),"m"(pb_33) + ); + return amvd; +} + +#define x264_predictor_clip x264_predictor_clip_mmx2 +static int ALWAYS_INLINE x264_predictor_clip_mmx2( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv ) +{ + static const uint32_t pd_32 = 0x20; + intptr_t tmp = (intptr_t)mv_limit, mvc_max = i_mvc, i = 0; + + asm( + "movq (%2), %%mm5 \n" + "movd %6, %%mm3 \n" + "psllw $2, %%mm5 \n" // Convert to subpel + "pshufw $0xEE, %%mm5, %%mm6 \n" + "dec %k3 \n" + "jz 2f \n" // if( i_mvc == 1 ) {do the last iteration} + "punpckldq %%mm3, %%mm3 \n" + "punpckldq %%mm5, %%mm5 \n" + "movd %7, %%mm4 \n" + "lea (%0,%3,4), %3 \n" + "1: \n" + "movq (%0), %%mm0 \n" + "add $8, %0 \n" + "movq %%mm3, %%mm1 \n" + "pxor %%mm2, %%mm2 \n" + "pcmpeqd %%mm0, %%mm1 \n" // mv == pmv + "pcmpeqd %%mm0, %%mm2 \n" // mv == 0 + "por %%mm1, %%mm2 \n" // (mv == pmv || mv == 0) * -1 + "pmovmskb %%mm2, %k2 \n" // (mv == pmv || mv == 0) * 0xf + "pmaxsw %%mm5, %%mm0 \n" + "pminsw %%mm6, %%mm0 \n" + "pand %%mm4, %%mm2 \n" // (mv0 == pmv || mv0 == 0) * 32 + "psrlq %%mm2, %%mm0 \n" // drop mv0 if it's skipped + "movq %%mm0, (%5,%4,4) \n" + "and $24, %k2 \n" + "add $2, %4 \n" + "add $8, %k2 \n" + "shr $4, %k2 \n" // (4-val)>>1 + "sub %2, %4 \n" // +1 for each valid motion vector + "cmp %3, %0 \n" + "jl 1b \n" + "jg 3f \n" // if( i == i_mvc - 1 ) {do the last iteration} + + /* Do the last iteration */ + "2: \n" + "movd (%0), %%mm0 \n" + "pxor %%mm2, %%mm2 \n" + "pcmpeqd %%mm0, %%mm3 \n" + "pcmpeqd %%mm0, %%mm2 \n" + "por %%mm3, %%mm2 \n" + "pmovmskb %%mm2, %k2 \n" + "pmaxsw %%mm5, %%mm0 \n" + "pminsw %%mm6, %%mm0 \n" + "movd %%mm0, (%5,%4,4) \n" + "inc %4 \n" + "and $1, %k2 \n" + "sub %2, %4 \n" // output += !(mv == pmv || mv == 0) + "3: \n" + :"+r"(mvc), "=m"(M64( dst )), "+r"(tmp), "+r"(mvc_max), "+r"(i) + :"r"(dst), "g"(pmv), "m"(pd_32), "m"(M64( mvc )) + ); + return i; +} + +/* Same as the above, except we do (mv + 2) >> 2 on the input. */ +#define x264_predictor_roundclip x264_predictor_roundclip_mmx2 +static int ALWAYS_INLINE x264_predictor_roundclip_mmx2( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv ) +{ + static const uint64_t pw_2 = 0x0002000200020002ULL; + static const uint32_t pd_32 = 0x20; + intptr_t tmp = (intptr_t)mv_limit, mvc_max = i_mvc, i = 0; + + asm( + "movq (%2), %%mm5 \n" + "movq %6, %%mm7 \n" + "movd %7, %%mm3 \n" + "pshufw $0xEE, %%mm5, %%mm6 \n" + "dec %k3 \n" + "jz 2f \n" + "punpckldq %%mm3, %%mm3 \n" + "punpckldq %%mm5, %%mm5 \n" + "movd %8, %%mm4 \n" + "lea (%0,%3,4), %3 \n" + "1: \n" + "movq (%0), %%mm0 \n" + "add $8, %0 \n" + "paddw %%mm7, %%mm0 \n" + "psraw $2, %%mm0 \n" + "movq %%mm3, %%mm1 \n" + "pxor %%mm2, %%mm2 \n" + "pcmpeqd %%mm0, %%mm1 \n" + "pcmpeqd %%mm0, %%mm2 \n" + "por %%mm1, %%mm2 \n" + "pmovmskb %%mm2, %k2 \n" + "pmaxsw %%mm5, %%mm0 \n" + "pminsw %%mm6, %%mm0 \n" + "pand %%mm4, %%mm2 \n" + "psrlq %%mm2, %%mm0 \n" + "movq %%mm0, (%5,%4,4) \n" + "and $24, %k2 \n" + "add $2, %4 \n" + "add $8, %k2 \n" + "shr $4, %k2 \n" + "sub %2, %4 \n" + "cmp %3, %0 \n" + "jl 1b \n" + "jg 3f \n" + + /* Do the last iteration */ + "2: \n" + "movd (%0), %%mm0 \n" + "paddw %%mm7, %%mm0 \n" + "psraw $2, %%mm0 \n" + "pxor %%mm2, %%mm2 \n" + "pcmpeqd %%mm0, %%mm3 \n" + "pcmpeqd %%mm0, %%mm2 \n" + "por %%mm3, %%mm2 \n" + "pmovmskb %%mm2, %k2 \n" + "pmaxsw %%mm5, %%mm0 \n" + "pminsw %%mm6, %%mm0 \n" + "movd %%mm0, (%5,%4,4) \n" + "inc %4 \n" + "and $1, %k2 \n" + "sub %2, %4 \n" + "3: \n" + :"+r"(mvc), "=m"(M64( dst )), "+r"(tmp), "+r"(mvc_max), "+r"(i) + :"r"(dst), "m"(pw_2), "g"(pmv), "m"(pd_32), "m"(M64( mvc )) + ); + return i; +} + +#endif + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/analyse.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/analyse.c new file mode 100644 index 00000000..036d6c15 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/analyse.c @@ -0,0 +1,4009 @@ +/***************************************************************************** + * analyse.c: macroblock analysis + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "macroblock.h" +#include "me.h" +#include "ratecontrol.h" +#include "analyse.h" +#include "rdo.c" + +typedef struct +{ + x264_me_t me16x16; + x264_me_t bi16x16; /* for b16x16 BI mode, since MVs can differ from l0/l1 */ + x264_me_t me8x8[4]; + x264_me_t me4x4[4][4]; + x264_me_t me8x4[4][2]; + x264_me_t me4x8[4][2]; + x264_me_t me16x8[2]; + x264_me_t me8x16[2]; + int i_rd16x16; + int i_cost8x8; + int i_cost4x4[4]; /* cost per 8x8 partition */ + int i_cost8x4[4]; /* cost per 8x8 partition */ + int i_cost4x8[4]; /* cost per 8x8 partition */ + int i_cost16x8; + int i_cost8x16; + /* [ref][0] is 16x16 mv, [ref][1..4] are 8x8 mv from partition [0..3] */ + ALIGNED_4( int16_t mvc[32][5][2] ); +} x264_mb_analysis_list_t; + +typedef struct +{ + /* conduct the analysis using this lamda and QP */ + int i_lambda; + int i_lambda2; + int i_qp; + uint16_t *p_cost_mv; + uint16_t *p_cost_ref[2]; + int i_mbrd; + + + /* I: Intra part */ + /* Take some shortcuts in intra search if intra is deemed unlikely */ + int b_fast_intra; + int b_force_intra; /* For Periodic Intra Refresh. Only supported in P-frames. */ + int b_avoid_topright; /* For Periodic Intra Refresh: don't predict from top-right pixels. */ + int b_try_skip; + + /* Luma part */ + int i_satd_i16x16; + int i_satd_i16x16_dir[7]; + int i_predict16x16; + + int i_satd_i8x8; + int i_cbp_i8x8_luma; + ALIGNED_16( uint16_t i_satd_i8x8_dir[4][16] ); + int i_predict8x8[4]; + + int i_satd_i4x4; + int i_predict4x4[16]; + + int i_satd_pcm; + + /* Chroma part */ + int i_satd_chroma; + int i_satd_chroma_dir[7]; + int i_predict8x8chroma; + + /* II: Inter part P/B frame */ + x264_mb_analysis_list_t l0; + x264_mb_analysis_list_t l1; + + int i_cost16x16bi; /* used the same ref and mv as l0 and l1 (at least for now) */ + int i_cost16x16direct; + int i_cost8x8bi; + int i_cost8x8direct[4]; + int i_satd8x8[3][4]; /* [L0,L1,BI][8x8 0..3] SATD only */ + int i_cost_est16x8[2]; /* Per-partition estimated cost */ + int i_cost_est8x16[2]; + int i_cost16x8bi; + int i_cost8x16bi; + int i_rd16x16bi; + int i_rd16x16direct; + int i_rd16x8bi; + int i_rd8x16bi; + int i_rd8x8bi; + + int i_mb_partition16x8[2]; /* mb_partition_e */ + int i_mb_partition8x16[2]; + int i_mb_type16x8; /* mb_class_e */ + int i_mb_type8x16; + + int b_direct_available; + int b_early_terminate; + +} x264_mb_analysis_t; + +/* lambda = pow(2,qp/6-2) */ +const uint16_t x264_lambda_tab[QP_MAX_MAX+1] = +{ + 1, 1, 1, 1, 1, 1, 1, 1, /* 0- 7 */ + 1, 1, 1, 1, 1, 1, 1, 1, /* 8-15 */ + 2, 2, 2, 2, 3, 3, 3, 4, /* 16-23 */ + 4, 4, 5, 6, 6, 7, 8, 9, /* 24-31 */ + 10, 11, 13, 14, 16, 18, 20, 23, /* 32-39 */ + 25, 29, 32, 36, 40, 45, 51, 57, /* 40-47 */ + 64, 72, 81, 91, 102, 114, 128, 144, /* 48-55 */ + 161, 181, 203, 228, 256, 287, 323, 362, /* 56-63 */ + 406, 456, 512, 575, 645, 724, 813, 912, /* 64-71 */ +1024,1149,1290,1448,1625,1825,2048,2299, /* 72-79 */ +2580,2896, /* 80-81 */ +}; + +/* lambda2 = pow(lambda,2) * .9 * 256 */ +/* Capped to avoid overflow */ +const int x264_lambda2_tab[QP_MAX_MAX+1] = +{ + 14, 18, 22, 28, 36, 45, 57, 72, /* 0- 7 */ + 91, 115, 145, 182, 230, 290, 365, 460, /* 8-15 */ + 580, 731, 921, 1161, 1462, 1843, 2322, 2925, /* 16-23 */ + 3686, 4644, 5851, 7372, 9289, 11703, 14745, 18578, /* 24-31 */ + 23407, 29491, 37156, 46814, 58982, 74313, 93628, 117964, /* 32-39 */ + 148626, 187257, 235929, 297252, 374514, 471859, 594505, 749029, /* 40-47 */ + 943718, 1189010, 1498059, 1887436, 2378021, 2996119, 3774873, 4756042, /* 48-55 */ + 5992238, 7549747, 9512085, 11984476, 15099494, 19024170,23968953,30198988, /* 56-63 */ + 38048341, 47937906, 60397977, 76096683, 95875813,120795955, /* 64-69 */ +134217727,134217727,134217727,134217727,134217727,134217727, /* 70-75 */ +134217727,134217727,134217727,134217727,134217727,134217727, /* 76-81 */ +}; + +const uint8_t x264_exp2_lut[64] = +{ + 0, 3, 6, 8, 11, 14, 17, 20, 23, 26, 29, 32, 36, 39, 42, 45, + 48, 52, 55, 58, 62, 65, 69, 72, 76, 80, 83, 87, 91, 94, 98, 102, + 106, 110, 114, 118, 122, 126, 130, 135, 139, 143, 147, 152, 156, 161, 165, 170, + 175, 179, 184, 189, 194, 198, 203, 208, 214, 219, 224, 229, 234, 240, 245, 250 +}; + +const float x264_log2_lut[128] = +{ + 0.00000, 0.01123, 0.02237, 0.03342, 0.04439, 0.05528, 0.06609, 0.07682, + 0.08746, 0.09803, 0.10852, 0.11894, 0.12928, 0.13955, 0.14975, 0.15987, + 0.16993, 0.17991, 0.18982, 0.19967, 0.20945, 0.21917, 0.22882, 0.23840, + 0.24793, 0.25739, 0.26679, 0.27612, 0.28540, 0.29462, 0.30378, 0.31288, + 0.32193, 0.33092, 0.33985, 0.34873, 0.35755, 0.36632, 0.37504, 0.38370, + 0.39232, 0.40088, 0.40939, 0.41785, 0.42626, 0.43463, 0.44294, 0.45121, + 0.45943, 0.46761, 0.47573, 0.48382, 0.49185, 0.49985, 0.50779, 0.51570, + 0.52356, 0.53138, 0.53916, 0.54689, 0.55459, 0.56224, 0.56986, 0.57743, + 0.58496, 0.59246, 0.59991, 0.60733, 0.61471, 0.62205, 0.62936, 0.63662, + 0.64386, 0.65105, 0.65821, 0.66534, 0.67243, 0.67948, 0.68650, 0.69349, + 0.70044, 0.70736, 0.71425, 0.72110, 0.72792, 0.73471, 0.74147, 0.74819, + 0.75489, 0.76155, 0.76818, 0.77479, 0.78136, 0.78790, 0.79442, 0.80090, + 0.80735, 0.81378, 0.82018, 0.82655, 0.83289, 0.83920, 0.84549, 0.85175, + 0.85798, 0.86419, 0.87036, 0.87652, 0.88264, 0.88874, 0.89482, 0.90087, + 0.90689, 0.91289, 0.91886, 0.92481, 0.93074, 0.93664, 0.94251, 0.94837, + 0.95420, 0.96000, 0.96578, 0.97154, 0.97728, 0.98299, 0.98868, 0.99435, +}; + +/* Avoid an int/float conversion. */ +const float x264_log2_lz_lut[32] = +{ + 31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +}; + +// should the intra and inter lambdas be different? +// I'm just matching the behaviour of deadzone quant. +static const int x264_trellis_lambda2_tab[2][QP_MAX_MAX+1] = +{ + // inter lambda = .85 * .85 * 2**(qp/3. + 10 - LAMBDA_BITS) + { + 46, 58, 73, 92, 117, 147, + 185, 233, 294, 370, 466, 587, + 740, 932, 1174, 1480, 1864, 2349, + 2959, 3728, 4697, 5918, 7457, 9395, + 11837, 14914, 18790, 23674, 29828, 37581, + 47349, 59656, 75163, 94699, 119313, 150326, + 189399, 238627, 300652, 378798, 477255, 601304, + 757596, 954511, 1202608, 1515192, 1909022, 2405217, + 3030384, 3818045, 4810435, 6060769, 7636091, 9620872, + 12121539, 15272182, 19241743, 24243077, 30544363, 38483486, + 48486154, 61088726, 76966972, 96972308, + 122177453,134217727,134217727,134217727,134217727,134217727, + 134217727,134217727,134217727,134217727,134217727,134217727, + }, + // intra lambda = .65 * .65 * 2**(qp/3. + 10 - LAMBDA_BITS) + { + 27, 34, 43, 54, 68, 86, + 108, 136, 172, 216, 273, 343, + 433, 545, 687, 865, 1090, 1374, + 1731, 2180, 2747, 3461, 4361, 5494, + 6922, 8721, 10988, 13844, 17442, 21976, + 27688, 34885, 43953, 55377, 69771, 87906, + 110755, 139543, 175813, 221511, 279087, 351627, + 443023, 558174, 703255, 886046, 1116348, 1406511, + 1772093, 2232697, 2813022, 3544186, 4465396, 5626046, + 7088374, 8930791, 11252092, 14176748, 17861583, 22504184, + 28353495, 35723165, 45008368, 56706990, + 71446330, 90016736,113413980,134217727,134217727,134217727, + 134217727,134217727,134217727,134217727,134217727,134217727, + 134217727,134217727,134217727,134217727,134217727,134217727, + } +}; + +#define MAX_CHROMA_LAMBDA_OFFSET 36 +static const uint16_t x264_chroma_lambda2_offset_tab[MAX_CHROMA_LAMBDA_OFFSET+1] = +{ + 16, 20, 25, 32, 40, 50, + 64, 80, 101, 128, 161, 203, + 256, 322, 406, 512, 645, 812, + 1024, 1290, 1625, 2048, 2580, 3250, + 4096, 5160, 6501, 8192, 10321, 13003, + 16384, 20642, 26007, 32768, 41285, 52015, + 65535 +}; + +/* TODO: calculate CABAC costs */ +static const uint8_t i_mb_b_cost_table[X264_MBTYPE_MAX] = +{ + 9, 9, 9, 9, 0, 0, 0, 1, 3, 7, 7, 7, 3, 7, 7, 7, 5, 9, 0 +}; +static const uint8_t i_mb_b16x8_cost_table[17] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 7, 5, 7, 9, 9, 9 +}; +static const uint8_t i_sub_mb_b_cost_table[13] = +{ + 7, 5, 5, 3, 7, 5, 7, 3, 7, 7, 7, 5, 1 +}; +static const uint8_t i_sub_mb_p_cost_table[4] = +{ + 5, 3, 3, 1 +}; + +static void x264_analyse_update_cache( x264_t *h, x264_mb_analysis_t *a ); + +static uint16_t x264_cost_ref[QP_MAX+1][3][33]; +static UNUSED x264_pthread_mutex_t cost_ref_mutex = X264_PTHREAD_MUTEX_INITIALIZER; +static uint16_t x264_cost_i4x4_mode[(QP_MAX+2)*32]; + +static int init_costs( x264_t *h, float *logs, int qp ) +{ + if( h->cost_mv[qp] ) + return 0; + + int mv_range = h->param.analyse.i_mv_range; + int lambda = x264_lambda_tab[qp]; + /* factor of 4 from qpel, 2 from sign, and 2 because mv can be opposite from mvp */ + CHECKED_MALLOC( h->cost_mv[qp], (4*4*mv_range + 1) * sizeof(uint16_t) ); + h->cost_mv[qp] += 2*4*mv_range; + for( int i = 0; i <= 2*4*mv_range; i++ ) + { + h->cost_mv[qp][-i] = + h->cost_mv[qp][i] = X264_MIN( (int)(lambda * logs[i] + .5f), UINT16_MAX ); + } + x264_pthread_mutex_lock( &cost_ref_mutex ); + for( int i = 0; i < 3; i++ ) + for( int j = 0; j < 33; j++ ) + x264_cost_ref[qp][i][j] = i ? X264_MIN( lambda * bs_size_te( i, j ), UINT16_MAX ) : 0; + x264_pthread_mutex_unlock( &cost_ref_mutex ); + if( h->param.analyse.i_me_method >= X264_ME_ESA && !h->cost_mv_fpel[qp][0] ) + { + for( int j = 0; j < 4; j++ ) + { + CHECKED_MALLOC( h->cost_mv_fpel[qp][j], (4*mv_range + 1) * sizeof(uint16_t) ); + h->cost_mv_fpel[qp][j] += 2*mv_range; + for( int i = -2*mv_range; i < 2*mv_range; i++ ) + h->cost_mv_fpel[qp][j][i] = h->cost_mv[qp][i*4+j]; + } + } + uint16_t *cost_i4x4_mode = (uint16_t*)ALIGN((intptr_t)x264_cost_i4x4_mode,64) + qp*32; + for( int i = 0; i < 17; i++ ) + cost_i4x4_mode[i] = 3*lambda*(i!=8); + return 0; +fail: + return -1; +} + +int x264_analyse_init_costs( x264_t *h ) +{ + int mv_range = h->param.analyse.i_mv_range; + float *logs = x264_malloc( (2*4*mv_range+1) * sizeof(float) ); + if( !logs ) + return -1; + + logs[0] = 0.718f; + for( int i = 1; i <= 2*4*mv_range; i++ ) + logs[i] = log2f( i+1 ) * 2.0f + 1.718f; + + for( int qp = X264_MIN( h->param.rc.i_qp_min, QP_MAX_SPEC ); qp <= h->param.rc.i_qp_max; qp++ ) + if( init_costs( h, logs, qp ) ) + goto fail; + + if( init_costs( h, logs, X264_LOOKAHEAD_QP ) ) + goto fail; + + x264_free( logs ); + return 0; +fail: + x264_free( logs ); + return -1; +} + +void x264_analyse_free_costs( x264_t *h ) +{ + int mv_range = h->param.analyse.i_mv_range; + for( int i = 0; i < QP_MAX+1; i++ ) + { + if( h->cost_mv[i] ) + x264_free( h->cost_mv[i] - 2*4*mv_range ); + if( h->cost_mv_fpel[i][0] ) + for( int j = 0; j < 4; j++ ) + x264_free( h->cost_mv_fpel[i][j] - 2*mv_range ); + } +} + +void x264_analyse_weight_frame( x264_t *h, int end ) +{ + for( int j = 0; j < h->i_ref[0]; j++ ) + { + if( h->sh.weight[j][0].weightfn ) + { + x264_frame_t *frame = h->fref[0][j]; + int width = frame->i_width[0] + 2*PADH; + int i_padv = PADV << PARAM_INTERLACED; + int offset, height; + pixel *src = frame->filtered[0][0] - frame->i_stride[0]*i_padv - PADH; + height = X264_MIN( 16 + end + i_padv, h->fref[0][j]->i_lines[0] + i_padv*2 ) - h->fenc->i_lines_weighted; + offset = h->fenc->i_lines_weighted*frame->i_stride[0]; + h->fenc->i_lines_weighted += height; + if( height ) + for( int k = j; k < h->i_ref[0]; k++ ) + if( h->sh.weight[k][0].weightfn ) + { + pixel *dst = h->fenc->weighted[k] - h->fenc->i_stride[0]*i_padv - PADH; + x264_weight_scale_plane( h, dst + offset, frame->i_stride[0], + src + offset, frame->i_stride[0], + width, height, &h->sh.weight[k][0] ); + } + break; + } + } +} + +/* initialize an array of lambda*nbits for all possible mvs */ +static void x264_mb_analyse_load_costs( x264_t *h, x264_mb_analysis_t *a ) +{ + a->p_cost_mv = h->cost_mv[a->i_qp]; + a->p_cost_ref[0] = x264_cost_ref[a->i_qp][x264_clip3(h->sh.i_num_ref_idx_l0_active-1,0,2)]; + a->p_cost_ref[1] = x264_cost_ref[a->i_qp][x264_clip3(h->sh.i_num_ref_idx_l1_active-1,0,2)]; +} + +static void x264_mb_analyse_init_qp( x264_t *h, x264_mb_analysis_t *a, int qp ) +{ + int effective_chroma_qp = h->chroma_qp_table[SPEC_QP(qp)] + X264_MAX( qp - QP_MAX_SPEC, 0 ); + a->i_lambda = x264_lambda_tab[qp]; + a->i_lambda2 = x264_lambda2_tab[qp]; + + h->mb.b_trellis = h->param.analyse.i_trellis > 1 && a->i_mbrd; + if( h->param.analyse.i_trellis ) + { + h->mb.i_trellis_lambda2[0][0] = x264_trellis_lambda2_tab[0][qp]; + h->mb.i_trellis_lambda2[0][1] = x264_trellis_lambda2_tab[1][qp]; + h->mb.i_trellis_lambda2[1][0] = x264_trellis_lambda2_tab[0][effective_chroma_qp]; + h->mb.i_trellis_lambda2[1][1] = x264_trellis_lambda2_tab[1][effective_chroma_qp]; + } + h->mb.i_psy_rd_lambda = a->i_lambda; + /* Adjusting chroma lambda based on QP offset hurts PSNR but improves visual quality. */ + int chroma_offset_idx = X264_MIN( qp-effective_chroma_qp+12, MAX_CHROMA_LAMBDA_OFFSET ); + h->mb.i_chroma_lambda2_offset = h->param.analyse.b_psy ? x264_chroma_lambda2_offset_tab[chroma_offset_idx] : 256; + + if( qp > QP_MAX_SPEC ) + { + h->nr_offset = h->nr_offset_emergency[qp-QP_MAX_SPEC-1]; + h->nr_residual_sum = h->nr_residual_sum_buf[1]; + h->nr_count = h->nr_count_buf[1]; + h->mb.b_noise_reduction = 1; + qp = QP_MAX_SPEC; /* Out-of-spec QPs are just used for calculating lambda values. */ + } + else + { + h->nr_offset = h->nr_offset_denoise; + h->nr_residual_sum = h->nr_residual_sum_buf[0]; + h->nr_count = h->nr_count_buf[0]; + h->mb.b_noise_reduction = 0; + } + + a->i_qp = h->mb.i_qp = qp; + h->mb.i_chroma_qp = h->chroma_qp_table[qp]; +} + +static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) +{ + int subme = h->param.analyse.i_subpel_refine - (h->sh.i_type == SLICE_TYPE_B); + + /* mbrd == 1 -> RD mode decision */ + /* mbrd == 2 -> RD refinement */ + /* mbrd == 3 -> QPRD */ + a->i_mbrd = (subme>=6) + (subme>=8) + (h->param.analyse.i_subpel_refine>=10); + h->mb.b_deblock_rdo = h->param.analyse.i_subpel_refine >= 9 && h->sh.i_disable_deblocking_filter_idc != 1; + a->b_early_terminate = h->param.analyse.i_subpel_refine < 11; + + x264_mb_analyse_init_qp( h, a, qp ); + + h->mb.b_transform_8x8 = 0; + + /* I: Intra part */ + a->i_satd_i16x16 = + a->i_satd_i8x8 = + a->i_satd_i4x4 = + a->i_satd_chroma = COST_MAX; + + /* non-RD PCM decision is inaccurate (as is psy-rd), so don't do it. + * PCM cost can overflow with high lambda2, so cap it at COST_MAX. */ + uint64_t pcm_cost = ((uint64_t)X264_PCM_COST*a->i_lambda2 + 128) >> 8; + a->i_satd_pcm = !h->param.i_avcintra_class && !h->mb.i_psy_rd && a->i_mbrd && pcm_cost < COST_MAX ? pcm_cost : COST_MAX; + + a->b_fast_intra = 0; + a->b_avoid_topright = 0; + h->mb.i_skip_intra = + h->mb.b_lossless ? 0 : + a->i_mbrd ? 2 : + !h->param.analyse.i_trellis && !h->param.analyse.i_noise_reduction; + + /* II: Inter part P/B frame */ + if( h->sh.i_type != SLICE_TYPE_I ) + { + int i_fmv_range = 4 * h->param.analyse.i_mv_range; + // limit motion search to a slightly smaller range than the theoretical limit, + // since the search may go a few iterations past its given range + int i_fpel_border = 6; // umh: 1 for diamond, 2 for octagon, 2 for hpel + + /* Calculate max allowed MV range */ + h->mb.mv_min[0] = 4*( -16*h->mb.i_mb_x - 24 ); + h->mb.mv_max[0] = 4*( 16*( h->mb.i_mb_width - h->mb.i_mb_x - 1 ) + 24 ); + h->mb.mv_min_spel[0] = X264_MAX( h->mb.mv_min[0], -i_fmv_range ); + h->mb.mv_max_spel[0] = X264_MIN( h->mb.mv_max[0], i_fmv_range-1 ); + if( h->param.b_intra_refresh && h->sh.i_type == SLICE_TYPE_P ) + { + int max_x = (h->fref[0][0]->i_pir_end_col * 16 - 3)*4; /* 3 pixels of hpel border */ + int max_mv = max_x - 4*16*h->mb.i_mb_x; + /* If we're left of the refresh bar, don't reference right of it. */ + if( max_mv > 0 && h->mb.i_mb_x < h->fdec->i_pir_start_col ) + h->mb.mv_max_spel[0] = X264_MIN( h->mb.mv_max_spel[0], max_mv ); + } + h->mb.mv_limit_fpel[0][0] = (h->mb.mv_min_spel[0]>>2) + i_fpel_border; + h->mb.mv_limit_fpel[1][0] = (h->mb.mv_max_spel[0]>>2) - i_fpel_border; + if( h->mb.i_mb_x == 0 && !(h->mb.i_mb_y & PARAM_INTERLACED) ) + { + int mb_y = h->mb.i_mb_y >> SLICE_MBAFF; + int thread_mvy_range = i_fmv_range; + + if( h->i_thread_frames > 1 ) + { + int pix_y = (h->mb.i_mb_y | PARAM_INTERLACED) * 16; + int thresh = pix_y + h->param.analyse.i_mv_range_thread; + for( int i = (h->sh.i_type == SLICE_TYPE_B); i >= 0; i-- ) + for( int j = 0; j < h->i_ref[i]; j++ ) + { + x264_frame_cond_wait( h->fref[i][j]->orig, thresh ); + thread_mvy_range = X264_MIN( thread_mvy_range, h->fref[i][j]->orig->i_lines_completed - pix_y ); + } + + if( h->param.b_deterministic ) + thread_mvy_range = h->param.analyse.i_mv_range_thread; + if( PARAM_INTERLACED ) + thread_mvy_range >>= 1; + + x264_analyse_weight_frame( h, pix_y + thread_mvy_range ); + } + + if( PARAM_INTERLACED ) + { + /* 0 == top progressive, 1 == bot progressive, 2 == interlaced */ + for( int i = 0; i < 3; i++ ) + { + int j = i == 2; + mb_y = (h->mb.i_mb_y >> j) + (i == 1); + h->mb.mv_miny_row[i] = 4*( -16*mb_y - 24 ); + h->mb.mv_maxy_row[i] = 4*( 16*( (h->mb.i_mb_height>>j) - mb_y - 1 ) + 24 ); + h->mb.mv_miny_spel_row[i] = X264_MAX( h->mb.mv_miny_row[i], -i_fmv_range ); + h->mb.mv_maxy_spel_row[i] = X264_MIN3( h->mb.mv_maxy_row[i], i_fmv_range-1, 4*thread_mvy_range ); + h->mb.mv_miny_fpel_row[i] = (h->mb.mv_miny_spel_row[i]>>2) + i_fpel_border; + h->mb.mv_maxy_fpel_row[i] = (h->mb.mv_maxy_spel_row[i]>>2) - i_fpel_border; + } + } + else + { + h->mb.mv_min[1] = 4*( -16*mb_y - 24 ); + h->mb.mv_max[1] = 4*( 16*( h->mb.i_mb_height - mb_y - 1 ) + 24 ); + h->mb.mv_min_spel[1] = X264_MAX( h->mb.mv_min[1], -i_fmv_range ); + h->mb.mv_max_spel[1] = X264_MIN3( h->mb.mv_max[1], i_fmv_range-1, 4*thread_mvy_range ); + h->mb.mv_limit_fpel[0][1] = (h->mb.mv_min_spel[1]>>2) + i_fpel_border; + h->mb.mv_limit_fpel[1][1] = (h->mb.mv_max_spel[1]>>2) - i_fpel_border; + } + } + if( PARAM_INTERLACED ) + { + int i = MB_INTERLACED ? 2 : h->mb.i_mb_y&1; + h->mb.mv_min[1] = h->mb.mv_miny_row[i]; + h->mb.mv_max[1] = h->mb.mv_maxy_row[i]; + h->mb.mv_min_spel[1] = h->mb.mv_miny_spel_row[i]; + h->mb.mv_max_spel[1] = h->mb.mv_maxy_spel_row[i]; + h->mb.mv_limit_fpel[0][1] = h->mb.mv_miny_fpel_row[i]; + h->mb.mv_limit_fpel[1][1] = h->mb.mv_maxy_fpel_row[i]; + } + + a->l0.me16x16.cost = + a->l0.i_rd16x16 = + a->l0.i_cost8x8 = + a->l0.i_cost16x8 = + a->l0.i_cost8x16 = COST_MAX; + if( h->sh.i_type == SLICE_TYPE_B ) + { + a->l1.me16x16.cost = + a->l1.i_rd16x16 = + a->l1.i_cost8x8 = + a->i_cost8x8direct[0] = + a->i_cost8x8direct[1] = + a->i_cost8x8direct[2] = + a->i_cost8x8direct[3] = + a->l1.i_cost16x8 = + a->l1.i_cost8x16 = + a->i_rd16x16bi = + a->i_rd16x16direct = + a->i_rd8x8bi = + a->i_rd16x8bi = + a->i_rd8x16bi = + a->i_cost16x16bi = + a->i_cost16x16direct = + a->i_cost8x8bi = + a->i_cost16x8bi = + a->i_cost8x16bi = COST_MAX; + } + else if( h->param.analyse.inter & X264_ANALYSE_PSUB8x8 ) + for( int i = 0; i < 4; i++ ) + { + a->l0.i_cost4x4[i] = + a->l0.i_cost8x4[i] = + a->l0.i_cost4x8[i] = COST_MAX; + } + + /* Fast intra decision */ + if( a->b_early_terminate && h->mb.i_mb_xy - h->sh.i_first_mb > 4 ) + { + /* Always run in fast-intra mode for subme < 3 */ + if( h->mb.i_subpel_refine > 2 && + ( IS_INTRA( h->mb.i_mb_type_left[0] ) || + IS_INTRA( h->mb.i_mb_type_top ) || + IS_INTRA( h->mb.i_mb_type_topleft ) || + IS_INTRA( h->mb.i_mb_type_topright ) || + (h->sh.i_type == SLICE_TYPE_P && IS_INTRA( h->fref[0][0]->mb_type[h->mb.i_mb_xy] )) || + (h->mb.i_mb_xy - h->sh.i_first_mb < 3*(h->stat.frame.i_mb_count[I_4x4] + h->stat.frame.i_mb_count[I_8x8] + h->stat.frame.i_mb_count[I_16x16])) ) ) + { /* intra is likely */ } + else + { + a->b_fast_intra = 1; + } + } + h->mb.b_skip_mc = 0; + if( h->param.b_intra_refresh && h->sh.i_type == SLICE_TYPE_P && + h->mb.i_mb_x >= h->fdec->i_pir_start_col && h->mb.i_mb_x <= h->fdec->i_pir_end_col ) + { + a->b_force_intra = 1; + a->b_fast_intra = 0; + a->b_avoid_topright = h->mb.i_mb_x == h->fdec->i_pir_end_col; + } + else + a->b_force_intra = 0; + } +} + +/* Prediction modes allowed for various combinations of neighbors. */ +/* Terminated by a -1. */ +/* In order, no neighbors, left, top, top/left, top/left/topleft */ +static const int8_t i16x16_mode_available[5][5] = +{ + {I_PRED_16x16_DC_128, -1, -1, -1, -1}, + {I_PRED_16x16_DC_LEFT, I_PRED_16x16_H, -1, -1, -1}, + {I_PRED_16x16_DC_TOP, I_PRED_16x16_V, -1, -1, -1}, + {I_PRED_16x16_V, I_PRED_16x16_H, I_PRED_16x16_DC, -1, -1}, + {I_PRED_16x16_V, I_PRED_16x16_H, I_PRED_16x16_DC, I_PRED_16x16_P, -1}, +}; + +static const int8_t chroma_mode_available[5][5] = +{ + {I_PRED_CHROMA_DC_128, -1, -1, -1, -1}, + {I_PRED_CHROMA_DC_LEFT, I_PRED_CHROMA_H, -1, -1, -1}, + {I_PRED_CHROMA_DC_TOP, I_PRED_CHROMA_V, -1, -1, -1}, + {I_PRED_CHROMA_V, I_PRED_CHROMA_H, I_PRED_CHROMA_DC, -1, -1}, + {I_PRED_CHROMA_V, I_PRED_CHROMA_H, I_PRED_CHROMA_DC, I_PRED_CHROMA_P, -1}, +}; + +static const int8_t i8x8_mode_available[2][5][10] = +{ + { + {I_PRED_4x4_DC_128, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC_LEFT, I_PRED_4x4_H, I_PRED_4x4_HU, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC_TOP, I_PRED_4x4_V, I_PRED_4x4_DDL, I_PRED_4x4_VL, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC, I_PRED_4x4_H, I_PRED_4x4_V, I_PRED_4x4_DDL, I_PRED_4x4_VL, I_PRED_4x4_HU, -1, -1, -1, -1}, + {I_PRED_4x4_DC, I_PRED_4x4_H, I_PRED_4x4_V, I_PRED_4x4_DDL, I_PRED_4x4_DDR, I_PRED_4x4_VR, I_PRED_4x4_HD, I_PRED_4x4_VL, I_PRED_4x4_HU, -1}, + }, + { + {I_PRED_4x4_DC_128, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC_LEFT, I_PRED_4x4_H, I_PRED_4x4_HU, -1, -1, -1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_H, I_PRED_4x4_HU, -1, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_H, I_PRED_4x4_HD, I_PRED_4x4_HU, -1, -1, -1, -1, -1, -1, -1}, + } +}; + +static const int8_t i4x4_mode_available[2][5][10] = +{ + { + {I_PRED_4x4_DC_128, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC_LEFT, I_PRED_4x4_H, I_PRED_4x4_HU, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC_TOP, I_PRED_4x4_V, I_PRED_4x4_DDL, I_PRED_4x4_VL, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC, I_PRED_4x4_H, I_PRED_4x4_V, I_PRED_4x4_DDL, I_PRED_4x4_VL, I_PRED_4x4_HU, -1, -1, -1, -1}, + {I_PRED_4x4_DC, I_PRED_4x4_H, I_PRED_4x4_V, I_PRED_4x4_DDL, I_PRED_4x4_DDR, I_PRED_4x4_VR, I_PRED_4x4_HD, I_PRED_4x4_VL, I_PRED_4x4_HU, -1}, + }, + { + {I_PRED_4x4_DC_128, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC_LEFT, I_PRED_4x4_H, I_PRED_4x4_HU, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC_TOP, I_PRED_4x4_V, -1, -1, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC, I_PRED_4x4_H, I_PRED_4x4_V, I_PRED_4x4_HU, -1, -1, -1, -1, -1, -1}, + {I_PRED_4x4_DC, I_PRED_4x4_H, I_PRED_4x4_V, I_PRED_4x4_DDR, I_PRED_4x4_VR, I_PRED_4x4_HD, I_PRED_4x4_HU, -1, -1, -1}, + } +}; + +static ALWAYS_INLINE const int8_t *predict_16x16_mode_available( int i_neighbour ) +{ + int idx = i_neighbour & (MB_TOP|MB_LEFT|MB_TOPLEFT); + idx = (idx == (MB_TOP|MB_LEFT|MB_TOPLEFT)) ? 4 : idx & (MB_TOP|MB_LEFT); + return i16x16_mode_available[idx]; +} + +static ALWAYS_INLINE const int8_t *predict_chroma_mode_available( int i_neighbour ) +{ + int idx = i_neighbour & (MB_TOP|MB_LEFT|MB_TOPLEFT); + idx = (idx == (MB_TOP|MB_LEFT|MB_TOPLEFT)) ? 4 : idx & (MB_TOP|MB_LEFT); + return chroma_mode_available[idx]; +} + +static ALWAYS_INLINE const int8_t *predict_8x8_mode_available( int force_intra, int i_neighbour, int i ) +{ + int avoid_topright = force_intra && (i&1); + int idx = i_neighbour & (MB_TOP|MB_LEFT|MB_TOPLEFT); + idx = (idx == (MB_TOP|MB_LEFT|MB_TOPLEFT)) ? 4 : idx & (MB_TOP|MB_LEFT); + return i8x8_mode_available[avoid_topright][idx]; +} + +static ALWAYS_INLINE const int8_t *predict_4x4_mode_available( int force_intra, int i_neighbour, int i ) +{ + int avoid_topright = force_intra && ((i&5) == 5); + int idx = i_neighbour & (MB_TOP|MB_LEFT|MB_TOPLEFT); + idx = (idx == (MB_TOP|MB_LEFT|MB_TOPLEFT)) ? 4 : idx & (MB_TOP|MB_LEFT); + return i4x4_mode_available[avoid_topright][idx]; +} + +/* For trellis=2, we need to do this for both sizes of DCT, for trellis=1 we only need to use it on the chosen mode. */ +static void inline x264_psy_trellis_init( x264_t *h, int do_both_dct ) +{ + ALIGNED_16( static pixel zero[16*FDEC_STRIDE] ) = {0}; + + if( do_both_dct || h->mb.b_transform_8x8 ) + h->dctf.sub16x16_dct8( h->mb.pic.fenc_dct8, h->mb.pic.p_fenc[0], zero ); + if( do_both_dct || !h->mb.b_transform_8x8 ) + h->dctf.sub16x16_dct( h->mb.pic.fenc_dct4, h->mb.pic.p_fenc[0], zero ); +} + +/* Reset fenc satd scores cache for psy RD */ +static inline void x264_mb_init_fenc_cache( x264_t *h, int b_satd ) +{ + if( h->param.analyse.i_trellis == 2 && h->mb.i_psy_trellis ) + x264_psy_trellis_init( h, h->param.analyse.b_transform_8x8 ); + if( !h->mb.i_psy_rd ) + return; + + M128( &h->mb.pic.fenc_hadamard_cache[0] ) = M128_ZERO; + M128( &h->mb.pic.fenc_hadamard_cache[2] ) = M128_ZERO; + M128( &h->mb.pic.fenc_hadamard_cache[4] ) = M128_ZERO; + M128( &h->mb.pic.fenc_hadamard_cache[6] ) = M128_ZERO; + h->mb.pic.fenc_hadamard_cache[8] = 0; + if( b_satd ) + h->mc.memzero_aligned( h->mb.pic.fenc_satd_cache, sizeof(h->mb.pic.fenc_satd_cache) ); +} + +static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *a ) +{ + if( a->i_satd_chroma < COST_MAX ) + return; + + if( CHROMA444 ) + { + if( !h->mb.b_chroma_me ) + { + a->i_satd_chroma = 0; + return; + } + + /* Cheap approximation of chroma costs to avoid a full i4x4/i8x8 analysis. */ + if( h->mb.b_lossless ) + { + x264_predict_lossless_16x16( h, 1, a->i_predict16x16 ); + x264_predict_lossless_16x16( h, 2, a->i_predict16x16 ); + } + else + { + h->predict_16x16[a->i_predict16x16]( h->mb.pic.p_fdec[1] ); + h->predict_16x16[a->i_predict16x16]( h->mb.pic.p_fdec[2] ); + } + a->i_satd_chroma = h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE ) + + h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE ); + return; + } + + const int8_t *predict_mode = predict_chroma_mode_available( h->mb.i_neighbour_intra ); + int chromapix = h->luma2chroma_pixel[PIXEL_16x16]; + + /* Prediction selection for chroma */ + if( predict_mode[3] >= 0 && !h->mb.b_lossless ) + { + int satdu[4], satdv[4]; + h->pixf.intra_mbcmp_x3_chroma( h->mb.pic.p_fenc[1], h->mb.pic.p_fdec[1], satdu ); + h->pixf.intra_mbcmp_x3_chroma( h->mb.pic.p_fenc[2], h->mb.pic.p_fdec[2], satdv ); + h->predict_chroma[I_PRED_CHROMA_P]( h->mb.pic.p_fdec[1] ); + h->predict_chroma[I_PRED_CHROMA_P]( h->mb.pic.p_fdec[2] ); + satdu[I_PRED_CHROMA_P] = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE ); + satdv[I_PRED_CHROMA_P] = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE ); + + for( ; *predict_mode >= 0; predict_mode++ ) + { + int i_mode = *predict_mode; + int i_satd = satdu[i_mode] + satdv[i_mode] + a->i_lambda * bs_size_ue( i_mode ); + + a->i_satd_chroma_dir[i_mode] = i_satd; + COPY2_IF_LT( a->i_satd_chroma, i_satd, a->i_predict8x8chroma, i_mode ); + } + } + else + { + for( ; *predict_mode >= 0; predict_mode++ ) + { + int i_satd; + int i_mode = *predict_mode; + + /* we do the prediction */ + if( h->mb.b_lossless ) + x264_predict_lossless_chroma( h, i_mode ); + else + { + h->predict_chroma[i_mode]( h->mb.pic.p_fdec[1] ); + h->predict_chroma[i_mode]( h->mb.pic.p_fdec[2] ); + } + + /* we calculate the cost */ + i_satd = h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE ) + + h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE ) + + a->i_lambda * bs_size_ue( x264_mb_chroma_pred_mode_fix[i_mode] ); + + a->i_satd_chroma_dir[i_mode] = i_satd; + COPY2_IF_LT( a->i_satd_chroma, i_satd, a->i_predict8x8chroma, i_mode ); + } + } + + h->mb.i_chroma_pred_mode = a->i_predict8x8chroma; +} + +/* FIXME: should we do any sort of merged chroma analysis with 4:4:4? */ +static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_inter ) +{ + const unsigned int flags = h->sh.i_type == SLICE_TYPE_I ? h->param.analyse.intra : h->param.analyse.inter; + pixel *p_src = h->mb.pic.p_fenc[0]; + pixel *p_dst = h->mb.pic.p_fdec[0]; + static const int8_t intra_analysis_shortcut[2][2][2][5] = + { + {{{I_PRED_4x4_HU, -1, -1, -1, -1}, + {I_PRED_4x4_DDL, I_PRED_4x4_VL, -1, -1, -1}}, + {{I_PRED_4x4_DDR, I_PRED_4x4_HD, I_PRED_4x4_HU, -1, -1}, + {I_PRED_4x4_DDL, I_PRED_4x4_DDR, I_PRED_4x4_VR, I_PRED_4x4_VL, -1}}}, + {{{I_PRED_4x4_HU, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1}}, + {{I_PRED_4x4_DDR, I_PRED_4x4_HD, I_PRED_4x4_HU, -1, -1}, + {I_PRED_4x4_DDR, I_PRED_4x4_VR, -1, -1, -1}}}, + }; + + int idx; + int lambda = a->i_lambda; + + /*---------------- Try all mode and calculate their score ---------------*/ + /* Disabled i16x16 for AVC-Intra compat */ + if( !h->param.i_avcintra_class ) + { + const int8_t *predict_mode = predict_16x16_mode_available( h->mb.i_neighbour_intra ); + + /* Not heavily tuned */ + static const uint8_t i16x16_thresh_lut[11] = { 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4 }; + int i16x16_thresh = a->b_fast_intra ? (i16x16_thresh_lut[h->mb.i_subpel_refine]*i_satd_inter)>>1 : COST_MAX; + + if( !h->mb.b_lossless && predict_mode[3] >= 0 ) + { + h->pixf.intra_mbcmp_x3_16x16( p_src, p_dst, a->i_satd_i16x16_dir ); + a->i_satd_i16x16_dir[0] += lambda * bs_size_ue(0); + a->i_satd_i16x16_dir[1] += lambda * bs_size_ue(1); + a->i_satd_i16x16_dir[2] += lambda * bs_size_ue(2); + COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[0], a->i_predict16x16, 0 ); + COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[1], a->i_predict16x16, 1 ); + COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[2], a->i_predict16x16, 2 ); + + /* Plane is expensive, so don't check it unless one of the previous modes was useful. */ + if( a->i_satd_i16x16 <= i16x16_thresh ) + { + h->predict_16x16[I_PRED_16x16_P]( p_dst ); + a->i_satd_i16x16_dir[I_PRED_16x16_P] = h->pixf.mbcmp[PIXEL_16x16]( p_src, FENC_STRIDE, p_dst, FDEC_STRIDE ); + a->i_satd_i16x16_dir[I_PRED_16x16_P] += lambda * bs_size_ue(3); + COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[I_PRED_16x16_P], a->i_predict16x16, 3 ); + } + } + else + { + for( ; *predict_mode >= 0; predict_mode++ ) + { + int i_satd; + int i_mode = *predict_mode; + + if( h->mb.b_lossless ) + x264_predict_lossless_16x16( h, 0, i_mode ); + else + h->predict_16x16[i_mode]( p_dst ); + + i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_src, FENC_STRIDE, p_dst, FDEC_STRIDE ) + + lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] ); + COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode ); + a->i_satd_i16x16_dir[i_mode] = i_satd; + } + } + + if( h->sh.i_type == SLICE_TYPE_B ) + /* cavlc mb type prefix */ + a->i_satd_i16x16 += lambda * i_mb_b_cost_table[I_16x16]; + + if( a->i_satd_i16x16 > i16x16_thresh ) + return; + } + + uint16_t *cost_i4x4_mode = (uint16_t*)ALIGN((intptr_t)x264_cost_i4x4_mode,64) + a->i_qp*32 + 8; + /* 8x8 prediction selection */ + if( flags & X264_ANALYSE_I8x8 ) + { + ALIGNED_ARRAY_32( pixel, edge,[36] ); + x264_pixel_cmp_t sa8d = (h->pixf.mbcmp[0] == h->pixf.satd[0]) ? h->pixf.sa8d[PIXEL_8x8] : h->pixf.mbcmp[PIXEL_8x8]; + int i_satd_thresh = a->i_mbrd ? COST_MAX : X264_MIN( i_satd_inter, a->i_satd_i16x16 ); + + // FIXME some bias like in i4x4? + int i_cost = lambda * 4; /* base predmode costs */ + h->mb.i_cbp_luma = 0; + + if( h->sh.i_type == SLICE_TYPE_B ) + i_cost += lambda * i_mb_b_cost_table[I_8x8]; + + for( idx = 0;; idx++ ) + { + int x = idx&1; + int y = idx>>1; + pixel *p_src_by = p_src + 8*x + 8*y*FENC_STRIDE; + pixel *p_dst_by = p_dst + 8*x + 8*y*FDEC_STRIDE; + int i_best = COST_MAX; + int i_pred_mode = x264_mb_predict_intra4x4_mode( h, 4*idx ); + + const int8_t *predict_mode = predict_8x8_mode_available( a->b_avoid_topright, h->mb.i_neighbour8[idx], idx ); + h->predict_8x8_filter( p_dst_by, edge, h->mb.i_neighbour8[idx], ALL_NEIGHBORS ); + + if( h->pixf.intra_mbcmp_x9_8x8 && predict_mode[8] >= 0 ) + { + /* No shortcuts here. The SSSE3 implementation of intra_mbcmp_x9 is fast enough. */ + i_best = h->pixf.intra_mbcmp_x9_8x8( p_src_by, p_dst_by, edge, cost_i4x4_mode-i_pred_mode, a->i_satd_i8x8_dir[idx] ); + i_cost += i_best & 0xffff; + i_best >>= 16; + a->i_predict8x8[idx] = i_best; + if( idx == 3 || i_cost > i_satd_thresh ) + break; + x264_macroblock_cache_intra8x8_pred( h, 2*x, 2*y, i_best ); + } + else + { + if( !h->mb.b_lossless && predict_mode[5] >= 0 ) + { + ALIGNED_ARRAY_16( int32_t, satd,[9] ); + h->pixf.intra_mbcmp_x3_8x8( p_src_by, edge, satd ); + int favor_vertical = satd[I_PRED_4x4_H] > satd[I_PRED_4x4_V]; + satd[i_pred_mode] -= 3 * lambda; + for( int i = 2; i >= 0; i-- ) + { + int cost = satd[i]; + a->i_satd_i8x8_dir[idx][i] = cost + 4 * lambda; + COPY2_IF_LT( i_best, cost, a->i_predict8x8[idx], i ); + } + + /* Take analysis shortcuts: don't analyse modes that are too + * far away direction-wise from the favored mode. */ + if( a->i_mbrd < 1 + a->b_fast_intra ) + predict_mode = intra_analysis_shortcut[a->b_avoid_topright][predict_mode[8] >= 0][favor_vertical]; + else + predict_mode += 3; + } + + for( ; *predict_mode >= 0 && (i_best >= 0 || a->i_mbrd >= 2); predict_mode++ ) + { + int i_satd; + int i_mode = *predict_mode; + + if( h->mb.b_lossless ) + x264_predict_lossless_8x8( h, p_dst_by, 0, idx, i_mode, edge ); + else + h->predict_8x8[i_mode]( p_dst_by, edge ); + + i_satd = sa8d( p_dst_by, FDEC_STRIDE, p_src_by, FENC_STRIDE ); + if( i_pred_mode == x264_mb_pred_mode4x4_fix(i_mode) ) + i_satd -= 3 * lambda; + + COPY2_IF_LT( i_best, i_satd, a->i_predict8x8[idx], i_mode ); + a->i_satd_i8x8_dir[idx][i_mode] = i_satd + 4 * lambda; + } + i_cost += i_best + 3*lambda; + + if( idx == 3 || i_cost > i_satd_thresh ) + break; + if( h->mb.b_lossless ) + x264_predict_lossless_8x8( h, p_dst_by, 0, idx, a->i_predict8x8[idx], edge ); + else + h->predict_8x8[a->i_predict8x8[idx]]( p_dst_by, edge ); + x264_macroblock_cache_intra8x8_pred( h, 2*x, 2*y, a->i_predict8x8[idx] ); + } + /* we need to encode this block now (for next ones) */ + x264_mb_encode_i8x8( h, 0, idx, a->i_qp, a->i_predict8x8[idx], edge, 0 ); + } + + if( idx == 3 ) + { + a->i_satd_i8x8 = i_cost; + if( h->mb.i_skip_intra ) + { + h->mc.copy[PIXEL_16x16]( h->mb.pic.i8x8_fdec_buf, 16, p_dst, FDEC_STRIDE, 16 ); + h->mb.pic.i8x8_nnz_buf[0] = M32( &h->mb.cache.non_zero_count[x264_scan8[ 0]] ); + h->mb.pic.i8x8_nnz_buf[1] = M32( &h->mb.cache.non_zero_count[x264_scan8[ 2]] ); + h->mb.pic.i8x8_nnz_buf[2] = M32( &h->mb.cache.non_zero_count[x264_scan8[ 8]] ); + h->mb.pic.i8x8_nnz_buf[3] = M32( &h->mb.cache.non_zero_count[x264_scan8[10]] ); + h->mb.pic.i8x8_cbp = h->mb.i_cbp_luma; + if( h->mb.i_skip_intra == 2 ) + h->mc.memcpy_aligned( h->mb.pic.i8x8_dct_buf, h->dct.luma8x8, sizeof(h->mb.pic.i8x8_dct_buf) ); + } + } + else + { + static const uint16_t cost_div_fix8[3] = {1024,512,341}; + a->i_satd_i8x8 = COST_MAX; + i_cost = (i_cost * cost_div_fix8[idx]) >> 8; + } + /* Not heavily tuned */ + static const uint8_t i8x8_thresh[11] = { 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6 }; + if( a->b_early_terminate && X264_MIN(i_cost, a->i_satd_i16x16) > (i_satd_inter*i8x8_thresh[h->mb.i_subpel_refine])>>2 ) + return; + } + + /* 4x4 prediction selection */ + if( flags & X264_ANALYSE_I4x4 ) + { + int i_cost = lambda * (24+16); /* 24from JVT (SATD0), 16 from base predmode costs */ + int i_satd_thresh = a->b_early_terminate ? X264_MIN3( i_satd_inter, a->i_satd_i16x16, a->i_satd_i8x8 ) : COST_MAX; + h->mb.i_cbp_luma = 0; + + if( a->b_early_terminate && a->i_mbrd ) + i_satd_thresh = i_satd_thresh * (10-a->b_fast_intra)/8; + + if( h->sh.i_type == SLICE_TYPE_B ) + i_cost += lambda * i_mb_b_cost_table[I_4x4]; + + for( idx = 0;; idx++ ) + { + pixel *p_src_by = p_src + block_idx_xy_fenc[idx]; + pixel *p_dst_by = p_dst + block_idx_xy_fdec[idx]; + int i_best = COST_MAX; + int i_pred_mode = x264_mb_predict_intra4x4_mode( h, idx ); + + const int8_t *predict_mode = predict_4x4_mode_available( a->b_avoid_topright, h->mb.i_neighbour4[idx], idx ); + + if( (h->mb.i_neighbour4[idx] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP ) + /* emulate missing topright samples */ + MPIXEL_X4( &p_dst_by[4 - FDEC_STRIDE] ) = PIXEL_SPLAT_X4( p_dst_by[3 - FDEC_STRIDE] ); + + if( h->pixf.intra_mbcmp_x9_4x4 && predict_mode[8] >= 0 ) + { + /* No shortcuts here. The SSSE3 implementation of intra_mbcmp_x9 is fast enough. */ + i_best = h->pixf.intra_mbcmp_x9_4x4( p_src_by, p_dst_by, cost_i4x4_mode-i_pred_mode ); + i_cost += i_best & 0xffff; + i_best >>= 16; + a->i_predict4x4[idx] = i_best; + if( i_cost > i_satd_thresh || idx == 15 ) + break; + h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = i_best; + } + else + { + if( !h->mb.b_lossless && predict_mode[5] >= 0 ) + { + ALIGNED_ARRAY_16( int32_t, satd,[9] ); + h->pixf.intra_mbcmp_x3_4x4( p_src_by, p_dst_by, satd ); + int favor_vertical = satd[I_PRED_4x4_H] > satd[I_PRED_4x4_V]; + satd[i_pred_mode] -= 3 * lambda; + i_best = satd[I_PRED_4x4_DC]; a->i_predict4x4[idx] = I_PRED_4x4_DC; + COPY2_IF_LT( i_best, satd[I_PRED_4x4_H], a->i_predict4x4[idx], I_PRED_4x4_H ); + COPY2_IF_LT( i_best, satd[I_PRED_4x4_V], a->i_predict4x4[idx], I_PRED_4x4_V ); + + /* Take analysis shortcuts: don't analyse modes that are too + * far away direction-wise from the favored mode. */ + if( a->i_mbrd < 1 + a->b_fast_intra ) + predict_mode = intra_analysis_shortcut[a->b_avoid_topright][predict_mode[8] >= 0][favor_vertical]; + else + predict_mode += 3; + } + + if( i_best > 0 ) + { + for( ; *predict_mode >= 0; predict_mode++ ) + { + int i_satd; + int i_mode = *predict_mode; + + if( h->mb.b_lossless ) + x264_predict_lossless_4x4( h, p_dst_by, 0, idx, i_mode ); + else + h->predict_4x4[i_mode]( p_dst_by ); + + i_satd = h->pixf.mbcmp[PIXEL_4x4]( p_src_by, FENC_STRIDE, p_dst_by, FDEC_STRIDE ); + if( i_pred_mode == x264_mb_pred_mode4x4_fix(i_mode) ) + { + i_satd -= lambda * 3; + if( i_satd <= 0 ) + { + i_best = i_satd; + a->i_predict4x4[idx] = i_mode; + break; + } + } + + COPY2_IF_LT( i_best, i_satd, a->i_predict4x4[idx], i_mode ); + } + } + + i_cost += i_best + 3 * lambda; + if( i_cost > i_satd_thresh || idx == 15 ) + break; + if( h->mb.b_lossless ) + x264_predict_lossless_4x4( h, p_dst_by, 0, idx, a->i_predict4x4[idx] ); + else + h->predict_4x4[a->i_predict4x4[idx]]( p_dst_by ); + h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = a->i_predict4x4[idx]; + } + /* we need to encode this block now (for next ones) */ + x264_mb_encode_i4x4( h, 0, idx, a->i_qp, a->i_predict4x4[idx], 0 ); + } + if( idx == 15 ) + { + a->i_satd_i4x4 = i_cost; + if( h->mb.i_skip_intra ) + { + h->mc.copy[PIXEL_16x16]( h->mb.pic.i4x4_fdec_buf, 16, p_dst, FDEC_STRIDE, 16 ); + h->mb.pic.i4x4_nnz_buf[0] = M32( &h->mb.cache.non_zero_count[x264_scan8[ 0]] ); + h->mb.pic.i4x4_nnz_buf[1] = M32( &h->mb.cache.non_zero_count[x264_scan8[ 2]] ); + h->mb.pic.i4x4_nnz_buf[2] = M32( &h->mb.cache.non_zero_count[x264_scan8[ 8]] ); + h->mb.pic.i4x4_nnz_buf[3] = M32( &h->mb.cache.non_zero_count[x264_scan8[10]] ); + h->mb.pic.i4x4_cbp = h->mb.i_cbp_luma; + if( h->mb.i_skip_intra == 2 ) + h->mc.memcpy_aligned( h->mb.pic.i4x4_dct_buf, h->dct.luma4x4, sizeof(h->mb.pic.i4x4_dct_buf) ); + } + } + else + a->i_satd_i4x4 = COST_MAX; + } +} + +static void x264_intra_rd( x264_t *h, x264_mb_analysis_t *a, int i_satd_thresh ) +{ + if( !a->b_early_terminate ) + i_satd_thresh = COST_MAX; + + if( a->i_satd_i16x16 < i_satd_thresh ) + { + h->mb.i_type = I_16x16; + x264_analyse_update_cache( h, a ); + a->i_satd_i16x16 = x264_rd_cost_mb( h, a->i_lambda2 ); + } + else + a->i_satd_i16x16 = COST_MAX; + + if( a->i_satd_i4x4 < i_satd_thresh ) + { + h->mb.i_type = I_4x4; + x264_analyse_update_cache( h, a ); + a->i_satd_i4x4 = x264_rd_cost_mb( h, a->i_lambda2 ); + } + else + a->i_satd_i4x4 = COST_MAX; + + if( a->i_satd_i8x8 < i_satd_thresh ) + { + h->mb.i_type = I_8x8; + x264_analyse_update_cache( h, a ); + a->i_satd_i8x8 = x264_rd_cost_mb( h, a->i_lambda2 ); + a->i_cbp_i8x8_luma = h->mb.i_cbp_luma; + } + else + a->i_satd_i8x8 = COST_MAX; +} + +static void x264_intra_rd_refine( x264_t *h, x264_mb_analysis_t *a ) +{ + uint64_t i_satd, i_best; + int plane_count = CHROMA444 ? 3 : 1; + h->mb.i_skip_intra = 0; + + if( h->mb.i_type == I_16x16 ) + { + int old_pred_mode = a->i_predict16x16; + const int8_t *predict_mode = predict_16x16_mode_available( h->mb.i_neighbour_intra ); + int i_thresh = a->b_early_terminate ? a->i_satd_i16x16_dir[old_pred_mode] * 9/8 : COST_MAX; + i_best = a->i_satd_i16x16; + for( ; *predict_mode >= 0; predict_mode++ ) + { + int i_mode = *predict_mode; + if( i_mode == old_pred_mode || a->i_satd_i16x16_dir[i_mode] > i_thresh ) + continue; + h->mb.i_intra16x16_pred_mode = i_mode; + i_satd = x264_rd_cost_mb( h, a->i_lambda2 ); + COPY2_IF_LT( i_best, i_satd, a->i_predict16x16, i_mode ); + } + } + + /* RD selection for chroma prediction */ + if( !CHROMA444 ) + { + const int8_t *predict_mode = predict_chroma_mode_available( h->mb.i_neighbour_intra ); + if( predict_mode[1] >= 0 ) + { + int8_t predict_mode_sorted[4]; + int i_max; + int i_thresh = a->b_early_terminate ? a->i_satd_chroma * 5/4 : COST_MAX; + + for( i_max = 0; *predict_mode >= 0; predict_mode++ ) + { + int i_mode = *predict_mode; + if( a->i_satd_chroma_dir[i_mode] < i_thresh && i_mode != a->i_predict8x8chroma ) + predict_mode_sorted[i_max++] = i_mode; + } + + if( i_max > 0 ) + { + int i_cbp_chroma_best = h->mb.i_cbp_chroma; + int i_chroma_lambda = x264_lambda2_tab[h->mb.i_chroma_qp]; + /* the previous thing encoded was x264_intra_rd(), so the pixels and + * coefs for the current chroma mode are still around, so we only + * have to recount the bits. */ + i_best = x264_rd_cost_chroma( h, i_chroma_lambda, a->i_predict8x8chroma, 0 ); + for( int i = 0; i < i_max; i++ ) + { + int i_mode = predict_mode_sorted[i]; + if( h->mb.b_lossless ) + x264_predict_lossless_chroma( h, i_mode ); + else + { + h->predict_chroma[i_mode]( h->mb.pic.p_fdec[1] ); + h->predict_chroma[i_mode]( h->mb.pic.p_fdec[2] ); + } + /* if we've already found a mode that needs no residual, then + * probably any mode with a residual will be worse. + * so avoid dct on the remaining modes to improve speed. */ + i_satd = x264_rd_cost_chroma( h, i_chroma_lambda, i_mode, h->mb.i_cbp_chroma != 0x00 ); + COPY3_IF_LT( i_best, i_satd, a->i_predict8x8chroma, i_mode, i_cbp_chroma_best, h->mb.i_cbp_chroma ); + } + h->mb.i_chroma_pred_mode = a->i_predict8x8chroma; + h->mb.i_cbp_chroma = i_cbp_chroma_best; + } + } + } + + if( h->mb.i_type == I_4x4 ) + { + pixel4 pels[3][4] = {{0}}; // doesn't need initting, just shuts up a gcc warning + int nnz[3] = {0}; + for( int idx = 0; idx < 16; idx++ ) + { + pixel *dst[3] = {h->mb.pic.p_fdec[0] + block_idx_xy_fdec[idx], + h->mb.pic.p_fdec[1] + block_idx_xy_fdec[idx], + h->mb.pic.p_fdec[2] + block_idx_xy_fdec[idx]}; + i_best = COST_MAX64; + + const int8_t *predict_mode = predict_4x4_mode_available( a->b_avoid_topright, h->mb.i_neighbour4[idx], idx ); + + if( (h->mb.i_neighbour4[idx] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP ) + for( int p = 0; p < plane_count; p++ ) + /* emulate missing topright samples */ + MPIXEL_X4( dst[p]+4-FDEC_STRIDE ) = PIXEL_SPLAT_X4( dst[p][3-FDEC_STRIDE] ); + + for( ; *predict_mode >= 0; predict_mode++ ) + { + int i_mode = *predict_mode; + i_satd = x264_rd_cost_i4x4( h, a->i_lambda2, idx, i_mode ); + + if( i_best > i_satd ) + { + a->i_predict4x4[idx] = i_mode; + i_best = i_satd; + for( int p = 0; p < plane_count; p++ ) + { + pels[p][0] = MPIXEL_X4( dst[p]+0*FDEC_STRIDE ); + pels[p][1] = MPIXEL_X4( dst[p]+1*FDEC_STRIDE ); + pels[p][2] = MPIXEL_X4( dst[p]+2*FDEC_STRIDE ); + pels[p][3] = MPIXEL_X4( dst[p]+3*FDEC_STRIDE ); + nnz[p] = h->mb.cache.non_zero_count[x264_scan8[idx+p*16]]; + } + } + } + + for( int p = 0; p < plane_count; p++ ) + { + MPIXEL_X4( dst[p]+0*FDEC_STRIDE ) = pels[p][0]; + MPIXEL_X4( dst[p]+1*FDEC_STRIDE ) = pels[p][1]; + MPIXEL_X4( dst[p]+2*FDEC_STRIDE ) = pels[p][2]; + MPIXEL_X4( dst[p]+3*FDEC_STRIDE ) = pels[p][3]; + h->mb.cache.non_zero_count[x264_scan8[idx+p*16]] = nnz[p]; + } + + h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = a->i_predict4x4[idx]; + } + } + else if( h->mb.i_type == I_8x8 ) + { + ALIGNED_ARRAY_32( pixel, edge,[4],[32] ); // really [3][36], but they can overlap + pixel4 pels_h[3][2] = {{0}}; + pixel pels_v[3][7] = {{0}}; + uint16_t nnz[3][2] = {{0}}; //shut up gcc + for( int idx = 0; idx < 4; idx++ ) + { + int x = idx&1; + int y = idx>>1; + int s8 = X264_SCAN8_0 + 2*x + 16*y; + pixel *dst[3] = {h->mb.pic.p_fdec[0] + 8*x + 8*y*FDEC_STRIDE, + h->mb.pic.p_fdec[1] + 8*x + 8*y*FDEC_STRIDE, + h->mb.pic.p_fdec[2] + 8*x + 8*y*FDEC_STRIDE}; + int cbp_luma_new = 0; + int i_thresh = a->b_early_terminate ? a->i_satd_i8x8_dir[idx][a->i_predict8x8[idx]] * 11/8 : COST_MAX; + + i_best = COST_MAX64; + + const int8_t *predict_mode = predict_8x8_mode_available( a->b_avoid_topright, h->mb.i_neighbour8[idx], idx ); + for( int p = 0; p < plane_count; p++ ) + h->predict_8x8_filter( dst[p], edge[p], h->mb.i_neighbour8[idx], ALL_NEIGHBORS ); + + for( ; *predict_mode >= 0; predict_mode++ ) + { + int i_mode = *predict_mode; + if( a->i_satd_i8x8_dir[idx][i_mode] > i_thresh ) + continue; + + h->mb.i_cbp_luma = a->i_cbp_i8x8_luma; + i_satd = x264_rd_cost_i8x8( h, a->i_lambda2, idx, i_mode, edge ); + + if( i_best > i_satd ) + { + a->i_predict8x8[idx] = i_mode; + cbp_luma_new = h->mb.i_cbp_luma; + i_best = i_satd; + + for( int p = 0; p < plane_count; p++ ) + { + pels_h[p][0] = MPIXEL_X4( dst[p]+7*FDEC_STRIDE+0 ); + pels_h[p][1] = MPIXEL_X4( dst[p]+7*FDEC_STRIDE+4 ); + if( !(idx&1) ) + for( int j = 0; j < 7; j++ ) + pels_v[p][j] = dst[p][7+j*FDEC_STRIDE]; + nnz[p][0] = M16( &h->mb.cache.non_zero_count[s8 + 0*8 + p*16] ); + nnz[p][1] = M16( &h->mb.cache.non_zero_count[s8 + 1*8 + p*16] ); + } + } + } + a->i_cbp_i8x8_luma = cbp_luma_new; + for( int p = 0; p < plane_count; p++ ) + { + MPIXEL_X4( dst[p]+7*FDEC_STRIDE+0 ) = pels_h[p][0]; + MPIXEL_X4( dst[p]+7*FDEC_STRIDE+4 ) = pels_h[p][1]; + if( !(idx&1) ) + for( int j = 0; j < 7; j++ ) + dst[p][7+j*FDEC_STRIDE] = pels_v[p][j]; + M16( &h->mb.cache.non_zero_count[s8 + 0*8 + p*16] ) = nnz[p][0]; + M16( &h->mb.cache.non_zero_count[s8 + 1*8 + p*16] ) = nnz[p][1]; + } + + x264_macroblock_cache_intra8x8_pred( h, 2*x, 2*y, a->i_predict8x8[idx] ); + } + } +} + +#define LOAD_FENC(m, src, xoff, yoff) \ +{ \ + (m)->p_cost_mv = a->p_cost_mv; \ + (m)->i_stride[0] = h->mb.pic.i_stride[0]; \ + (m)->i_stride[1] = h->mb.pic.i_stride[1]; \ + (m)->i_stride[2] = h->mb.pic.i_stride[2]; \ + (m)->p_fenc[0] = &(src)[0][(xoff)+(yoff)*FENC_STRIDE]; \ + (m)->p_fenc[1] = &(src)[1][((xoff)>>CHROMA_H_SHIFT)+((yoff)>>CHROMA_V_SHIFT)*FENC_STRIDE]; \ + (m)->p_fenc[2] = &(src)[2][((xoff)>>CHROMA_H_SHIFT)+((yoff)>>CHROMA_V_SHIFT)*FENC_STRIDE]; \ +} + +#define LOAD_HPELS(m, src, list, ref, xoff, yoff) \ +{ \ + (m)->p_fref_w = (m)->p_fref[0] = &(src)[0][(xoff)+(yoff)*(m)->i_stride[0]]; \ + (m)->p_fref[1] = &(src)[1][(xoff)+(yoff)*(m)->i_stride[0]]; \ + (m)->p_fref[2] = &(src)[2][(xoff)+(yoff)*(m)->i_stride[0]]; \ + (m)->p_fref[3] = &(src)[3][(xoff)+(yoff)*(m)->i_stride[0]]; \ + if( CHROMA444 ) \ + { \ + (m)->p_fref[ 4] = &(src)[ 4][(xoff)+(yoff)*(m)->i_stride[1]]; \ + (m)->p_fref[ 5] = &(src)[ 5][(xoff)+(yoff)*(m)->i_stride[1]]; \ + (m)->p_fref[ 6] = &(src)[ 6][(xoff)+(yoff)*(m)->i_stride[1]]; \ + (m)->p_fref[ 7] = &(src)[ 7][(xoff)+(yoff)*(m)->i_stride[1]]; \ + (m)->p_fref[ 8] = &(src)[ 8][(xoff)+(yoff)*(m)->i_stride[2]]; \ + (m)->p_fref[ 9] = &(src)[ 9][(xoff)+(yoff)*(m)->i_stride[2]]; \ + (m)->p_fref[10] = &(src)[10][(xoff)+(yoff)*(m)->i_stride[2]]; \ + (m)->p_fref[11] = &(src)[11][(xoff)+(yoff)*(m)->i_stride[2]]; \ + } \ + else \ + (m)->p_fref[4] = &(src)[4][(xoff)+((yoff)>>CHROMA_V_SHIFT)*(m)->i_stride[1]]; \ + (m)->integral = &h->mb.pic.p_integral[list][ref][(xoff)+(yoff)*(m)->i_stride[0]]; \ + (m)->weight = x264_weight_none; \ + (m)->i_ref = ref; \ +} + +#define LOAD_WPELS(m, src, list, ref, xoff, yoff) \ + (m)->p_fref_w = &(src)[(xoff)+(yoff)*(m)->i_stride[0]]; \ + (m)->weight = h->sh.weight[i_ref]; + +#define REF_COST(list, ref) \ + (a->p_cost_ref[list][ref]) + +static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a ) +{ + x264_me_t m; + int i_mvc; + ALIGNED_4( int16_t mvc[8][2] ); + int i_halfpel_thresh = INT_MAX; + int *p_halfpel_thresh = (a->b_early_terminate && h->mb.pic.i_fref[0]>1) ? &i_halfpel_thresh : NULL; + + /* 16x16 Search on all ref frame */ + m.i_pixel = PIXEL_16x16; + LOAD_FENC( &m, h->mb.pic.p_fenc, 0, 0 ); + + a->l0.me16x16.cost = INT_MAX; + for( int i_ref = 0; i_ref < h->mb.pic.i_fref[0]; i_ref++ ) + { + m.i_ref_cost = REF_COST( 0, i_ref ); + i_halfpel_thresh -= m.i_ref_cost; + + /* search with ref */ + LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 0, 0 ); + LOAD_WPELS( &m, h->mb.pic.p_fref_w[i_ref], 0, i_ref, 0, 0 ); + + x264_mb_predict_mv_16x16( h, 0, i_ref, m.mvp ); + + if( h->mb.ref_blind_dupe == i_ref ) + { + CP32( m.mv, a->l0.mvc[0][0] ); + x264_me_refine_qpel_refdupe( h, &m, p_halfpel_thresh ); + } + else + { + x264_mb_predict_mv_ref16x16( h, 0, i_ref, mvc, &i_mvc ); + x264_me_search_ref( h, &m, mvc, i_mvc, p_halfpel_thresh ); + } + + /* save mv for predicting neighbors */ + CP32( h->mb.mvr[0][i_ref][h->mb.i_mb_xy], m.mv ); + CP32( a->l0.mvc[i_ref][0], m.mv ); + + /* early termination + * SSD threshold would probably be better than SATD */ + if( i_ref == 0 + && a->b_try_skip + && m.cost-m.cost_mv < 300*a->i_lambda + && abs(m.mv[0]-h->mb.cache.pskip_mv[0]) + + abs(m.mv[1]-h->mb.cache.pskip_mv[1]) <= 1 + && x264_macroblock_probe_pskip( h ) ) + { + h->mb.i_type = P_SKIP; + x264_analyse_update_cache( h, a ); + assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->i_thread_frames == 1 ); + return; + } + + m.cost += m.i_ref_cost; + i_halfpel_thresh += m.i_ref_cost; + + if( m.cost < a->l0.me16x16.cost ) + h->mc.memcpy_aligned( &a->l0.me16x16, &m, sizeof(x264_me_t) ); + } + + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.me16x16.i_ref ); + assert( a->l0.me16x16.mv[1] <= h->mb.mv_max_spel[1] || h->i_thread_frames == 1 ); + + h->mb.i_type = P_L0; + if( a->i_mbrd ) + { + x264_mb_init_fenc_cache( h, a->i_mbrd >= 2 || h->param.analyse.inter & X264_ANALYSE_PSUB8x8 ); + if( a->l0.me16x16.i_ref == 0 && M32( a->l0.me16x16.mv ) == M32( h->mb.cache.pskip_mv ) && !a->b_force_intra ) + { + h->mb.i_partition = D_16x16; + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv ); + a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 ); + if( !(h->mb.i_cbp_luma|h->mb.i_cbp_chroma) ) + h->mb.i_type = P_SKIP; + } + } +} + +static void x264_mb_analyse_inter_p8x8_mixed_ref( x264_t *h, x264_mb_analysis_t *a ) +{ + x264_me_t m; + pixel **p_fenc = h->mb.pic.p_fenc; + int i_maxref = h->mb.pic.i_fref[0]-1; + + h->mb.i_partition = D_8x8; + + #define CHECK_NEIGHBOUR(i)\ + {\ + int ref = h->mb.cache.ref[0][X264_SCAN8_0+i];\ + if( ref > i_maxref && ref != h->mb.ref_blind_dupe )\ + i_maxref = ref;\ + } + + /* early termination: if 16x16 chose ref 0, then evalute no refs older + * than those used by the neighbors */ + if( a->b_early_terminate && (i_maxref > 0 && (a->l0.me16x16.i_ref == 0 || a->l0.me16x16.i_ref == h->mb.ref_blind_dupe) && + h->mb.i_mb_type_top > 0 && h->mb.i_mb_type_left[0] > 0) ) + { + i_maxref = 0; + CHECK_NEIGHBOUR( -8 - 1 ); + CHECK_NEIGHBOUR( -8 + 0 ); + CHECK_NEIGHBOUR( -8 + 2 ); + CHECK_NEIGHBOUR( -8 + 4 ); + CHECK_NEIGHBOUR( 0 - 1 ); + CHECK_NEIGHBOUR( 2*8 - 1 ); + } + #undef CHECK_NEIGHBOUR + + for( int i_ref = 0; i_ref <= i_maxref; i_ref++ ) + CP32( a->l0.mvc[i_ref][0], h->mb.mvr[0][i_ref][h->mb.i_mb_xy] ); + + for( int i = 0; i < 4; i++ ) + { + x264_me_t *l0m = &a->l0.me8x8[i]; + int x8 = i&1; + int y8 = i>>1; + + m.i_pixel = PIXEL_8x8; + + LOAD_FENC( &m, p_fenc, 8*x8, 8*y8 ); + l0m->cost = INT_MAX; + for( int i_ref = 0; i_ref <= i_maxref || i_ref == h->mb.ref_blind_dupe; ) + { + m.i_ref_cost = REF_COST( 0, i_ref ); + + LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 8*x8, 8*y8 ); + LOAD_WPELS( &m, h->mb.pic.p_fref_w[i_ref], 0, i_ref, 8*x8, 8*y8 ); + + x264_macroblock_cache_ref( h, 2*x8, 2*y8, 2, 2, 0, i_ref ); + x264_mb_predict_mv( h, 0, 4*i, 2, m.mvp ); + if( h->mb.ref_blind_dupe == i_ref ) + { + CP32( m.mv, a->l0.mvc[0][i+1] ); + x264_me_refine_qpel_refdupe( h, &m, NULL ); + } + else + x264_me_search( h, &m, a->l0.mvc[i_ref], i+1 ); + + m.cost += m.i_ref_cost; + + CP32( a->l0.mvc[i_ref][i+1], m.mv ); + + if( m.cost < l0m->cost ) + h->mc.memcpy_aligned( l0m, &m, sizeof(x264_me_t) ); + if( i_ref == i_maxref && i_maxref < h->mb.ref_blind_dupe ) + i_ref = h->mb.ref_blind_dupe; + else + i_ref++; + } + x264_macroblock_cache_mv_ptr( h, 2*x8, 2*y8, 2, 2, 0, l0m->mv ); + x264_macroblock_cache_ref( h, 2*x8, 2*y8, 2, 2, 0, l0m->i_ref ); + + a->i_satd8x8[0][i] = l0m->cost - ( l0m->cost_mv + l0m->i_ref_cost ); + + /* If CABAC is on and we're not doing sub-8x8 analysis, the costs + are effectively zero. */ + if( !h->param.b_cabac || (h->param.analyse.inter & X264_ANALYSE_PSUB8x8) ) + l0m->cost += a->i_lambda * i_sub_mb_p_cost_table[D_L0_8x8]; + } + + a->l0.i_cost8x8 = a->l0.me8x8[0].cost + a->l0.me8x8[1].cost + + a->l0.me8x8[2].cost + a->l0.me8x8[3].cost; + /* P_8x8 ref0 has no ref cost */ + if( !h->param.b_cabac && !(a->l0.me8x8[0].i_ref | a->l0.me8x8[1].i_ref | + a->l0.me8x8[2].i_ref | a->l0.me8x8[3].i_ref) ) + a->l0.i_cost8x8 -= REF_COST( 0, 0 ) * 4; + M32( h->mb.i_sub_partition ) = D_L0_8x8 * 0x01010101; +} + +static void x264_mb_analyse_inter_p8x8( x264_t *h, x264_mb_analysis_t *a ) +{ + /* Duplicate refs are rarely useful in p8x8 due to the high cost of the + * reference frame flags. Thus, if we're not doing mixedrefs, just + * don't bother analysing the dupes. */ + const int i_ref = h->mb.ref_blind_dupe == a->l0.me16x16.i_ref ? 0 : a->l0.me16x16.i_ref; + const int i_ref_cost = h->param.b_cabac || i_ref ? REF_COST( 0, i_ref ) : 0; + pixel **p_fenc = h->mb.pic.p_fenc; + int i_mvc; + int16_t (*mvc)[2] = a->l0.mvc[i_ref]; + + /* XXX Needed for x264_mb_predict_mv */ + h->mb.i_partition = D_8x8; + + i_mvc = 1; + CP32( mvc[0], a->l0.me16x16.mv ); + + for( int i = 0; i < 4; i++ ) + { + x264_me_t *m = &a->l0.me8x8[i]; + int x8 = i&1; + int y8 = i>>1; + + m->i_pixel = PIXEL_8x8; + m->i_ref_cost = i_ref_cost; + + LOAD_FENC( m, p_fenc, 8*x8, 8*y8 ); + LOAD_HPELS( m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 8*x8, 8*y8 ); + LOAD_WPELS( m, h->mb.pic.p_fref_w[i_ref], 0, i_ref, 8*x8, 8*y8 ); + + x264_mb_predict_mv( h, 0, 4*i, 2, m->mvp ); + x264_me_search( h, m, mvc, i_mvc ); + + x264_macroblock_cache_mv_ptr( h, 2*x8, 2*y8, 2, 2, 0, m->mv ); + + CP32( mvc[i_mvc], m->mv ); + i_mvc++; + + a->i_satd8x8[0][i] = m->cost - m->cost_mv; + + /* mb type cost */ + m->cost += i_ref_cost; + if( !h->param.b_cabac || (h->param.analyse.inter & X264_ANALYSE_PSUB8x8) ) + m->cost += a->i_lambda * i_sub_mb_p_cost_table[D_L0_8x8]; + } + + a->l0.i_cost8x8 = a->l0.me8x8[0].cost + a->l0.me8x8[1].cost + + a->l0.me8x8[2].cost + a->l0.me8x8[3].cost; + /* theoretically this should include 4*ref_cost, + * but 3 seems a better approximation of cabac. */ + if( h->param.b_cabac ) + a->l0.i_cost8x8 -= i_ref_cost; + M32( h->mb.i_sub_partition ) = D_L0_8x8 * 0x01010101; +} + +static void x264_mb_analyse_inter_p16x8( x264_t *h, x264_mb_analysis_t *a, int i_best_satd ) +{ + x264_me_t m; + pixel **p_fenc = h->mb.pic.p_fenc; + ALIGNED_4( int16_t mvc[3][2] ); + + /* XXX Needed for x264_mb_predict_mv */ + h->mb.i_partition = D_16x8; + + for( int i = 0; i < 2; i++ ) + { + x264_me_t *l0m = &a->l0.me16x8[i]; + const int minref = X264_MIN( a->l0.me8x8[2*i].i_ref, a->l0.me8x8[2*i+1].i_ref ); + const int maxref = X264_MAX( a->l0.me8x8[2*i].i_ref, a->l0.me8x8[2*i+1].i_ref ); + const int ref8[2] = { minref, maxref }; + const int i_ref8s = ( ref8[0] == ref8[1] ) ? 1 : 2; + + m.i_pixel = PIXEL_16x8; + + LOAD_FENC( &m, p_fenc, 0, 8*i ); + l0m->cost = INT_MAX; + for( int j = 0; j < i_ref8s; j++ ) + { + const int i_ref = ref8[j]; + m.i_ref_cost = REF_COST( 0, i_ref ); + + /* if we skipped the 16x16 predictor, we wouldn't have to copy anything... */ + CP32( mvc[0], a->l0.mvc[i_ref][0] ); + CP32( mvc[1], a->l0.mvc[i_ref][2*i+1] ); + CP32( mvc[2], a->l0.mvc[i_ref][2*i+2] ); + + LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 0, 8*i ); + LOAD_WPELS( &m, h->mb.pic.p_fref_w[i_ref], 0, i_ref, 0, 8*i ); + + x264_macroblock_cache_ref( h, 0, 2*i, 4, 2, 0, i_ref ); + x264_mb_predict_mv( h, 0, 8*i, 4, m.mvp ); + /* We can only take this shortcut if the first search was performed on ref0. */ + if( h->mb.ref_blind_dupe == i_ref && !ref8[0] ) + { + /* We can just leave the MV from the previous ref search. */ + x264_me_refine_qpel_refdupe( h, &m, NULL ); + } + else + x264_me_search( h, &m, mvc, 3 ); + + m.cost += m.i_ref_cost; + + if( m.cost < l0m->cost ) + h->mc.memcpy_aligned( l0m, &m, sizeof(x264_me_t) ); + } + + /* Early termination based on the current SATD score of partition[0] + plus the estimated SATD score of partition[1] */ + if( a->b_early_terminate && (!i && l0m->cost + a->i_cost_est16x8[1] > i_best_satd * (4 + !!a->i_mbrd) / 4) ) + { + a->l0.i_cost16x8 = COST_MAX; + return; + } + + x264_macroblock_cache_mv_ptr( h, 0, 2*i, 4, 2, 0, l0m->mv ); + x264_macroblock_cache_ref( h, 0, 2*i, 4, 2, 0, l0m->i_ref ); + } + + a->l0.i_cost16x8 = a->l0.me16x8[0].cost + a->l0.me16x8[1].cost; +} + +static void x264_mb_analyse_inter_p8x16( x264_t *h, x264_mb_analysis_t *a, int i_best_satd ) +{ + x264_me_t m; + pixel **p_fenc = h->mb.pic.p_fenc; + ALIGNED_4( int16_t mvc[3][2] ); + + /* XXX Needed for x264_mb_predict_mv */ + h->mb.i_partition = D_8x16; + + for( int i = 0; i < 2; i++ ) + { + x264_me_t *l0m = &a->l0.me8x16[i]; + const int minref = X264_MIN( a->l0.me8x8[i].i_ref, a->l0.me8x8[i+2].i_ref ); + const int maxref = X264_MAX( a->l0.me8x8[i].i_ref, a->l0.me8x8[i+2].i_ref ); + const int ref8[2] = { minref, maxref }; + const int i_ref8s = ( ref8[0] == ref8[1] ) ? 1 : 2; + + m.i_pixel = PIXEL_8x16; + + LOAD_FENC( &m, p_fenc, 8*i, 0 ); + l0m->cost = INT_MAX; + for( int j = 0; j < i_ref8s; j++ ) + { + const int i_ref = ref8[j]; + m.i_ref_cost = REF_COST( 0, i_ref ); + + CP32( mvc[0], a->l0.mvc[i_ref][0] ); + CP32( mvc[1], a->l0.mvc[i_ref][i+1] ); + CP32( mvc[2], a->l0.mvc[i_ref][i+3] ); + + LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 8*i, 0 ); + LOAD_WPELS( &m, h->mb.pic.p_fref_w[i_ref], 0, i_ref, 8*i, 0 ); + + x264_macroblock_cache_ref( h, 2*i, 0, 2, 4, 0, i_ref ); + x264_mb_predict_mv( h, 0, 4*i, 2, m.mvp ); + /* We can only take this shortcut if the first search was performed on ref0. */ + if( h->mb.ref_blind_dupe == i_ref && !ref8[0] ) + { + /* We can just leave the MV from the previous ref search. */ + x264_me_refine_qpel_refdupe( h, &m, NULL ); + } + else + x264_me_search( h, &m, mvc, 3 ); + + m.cost += m.i_ref_cost; + + if( m.cost < l0m->cost ) + h->mc.memcpy_aligned( l0m, &m, sizeof(x264_me_t) ); + } + + /* Early termination based on the current SATD score of partition[0] + plus the estimated SATD score of partition[1] */ + if( a->b_early_terminate && (!i && l0m->cost + a->i_cost_est8x16[1] > i_best_satd * (4 + !!a->i_mbrd) / 4) ) + { + a->l0.i_cost8x16 = COST_MAX; + return; + } + + x264_macroblock_cache_mv_ptr( h, 2*i, 0, 2, 4, 0, l0m->mv ); + x264_macroblock_cache_ref( h, 2*i, 0, 2, 4, 0, l0m->i_ref ); + } + + a->l0.i_cost8x16 = a->l0.me8x16[0].cost + a->l0.me8x16[1].cost; +} + +static ALWAYS_INLINE int x264_mb_analyse_inter_p4x4_chroma_internal( x264_t *h, x264_mb_analysis_t *a, + pixel **p_fref, int i8x8, int size, int chroma ) +{ + ALIGNED_ARRAY_32( pixel, pix1,[16*16] ); + pixel *pix2 = pix1+8; + int i_stride = h->mb.pic.i_stride[1]; + int chroma_h_shift = chroma <= CHROMA_422; + int chroma_v_shift = chroma == CHROMA_420; + int or = 8*(i8x8&1) + (4>>chroma_v_shift)*(i8x8&2)*i_stride; + int i_ref = a->l0.me8x8[i8x8].i_ref; + int mvy_offset = chroma_v_shift && MB_INTERLACED & i_ref ? (h->mb.i_mb_y & 1)*4 - 2 : 0; + x264_weight_t *weight = h->sh.weight[i_ref]; + + // FIXME weight can be done on 4x4 blocks even if mc is smaller +#define CHROMA4x4MC( width, height, me, x, y ) \ + if( chroma == CHROMA_444 ) \ + { \ + int mvx = (me).mv[0] + 4*2*x; \ + int mvy = (me).mv[1] + 4*2*y; \ + h->mc.mc_luma( &pix1[2*x+2*y*16], 16, &h->mb.pic.p_fref[0][i_ref][4], i_stride, \ + mvx, mvy, 2*width, 2*height, &h->sh.weight[i_ref][1] ); \ + h->mc.mc_luma( &pix2[2*x+2*y*16], 16, &h->mb.pic.p_fref[0][i_ref][8], i_stride, \ + mvx, mvy, 2*width, 2*height, &h->sh.weight[i_ref][2] ); \ + } \ + else \ + { \ + int offset = x + (2>>chroma_v_shift)*16*y; \ + int chroma_height = (2>>chroma_v_shift)*height; \ + h->mc.mc_chroma( &pix1[offset], &pix2[offset], 16, &p_fref[4][or+2*x+(2>>chroma_v_shift)*y*i_stride], i_stride, \ + (me).mv[0], (2>>chroma_v_shift)*((me).mv[1]+mvy_offset), width, chroma_height ); \ + if( weight[1].weightfn ) \ + weight[1].weightfn[width>>2]( &pix1[offset], 16, &pix1[offset], 16, &weight[1], chroma_height ); \ + if( weight[2].weightfn ) \ + weight[2].weightfn[width>>2]( &pix2[offset], 16, &pix2[offset], 16, &weight[2], chroma_height ); \ + } + + if( size == PIXEL_4x4 ) + { + x264_me_t *m = a->l0.me4x4[i8x8]; + CHROMA4x4MC( 2,2, m[0], 0,0 ); + CHROMA4x4MC( 2,2, m[1], 2,0 ); + CHROMA4x4MC( 2,2, m[2], 0,2 ); + CHROMA4x4MC( 2,2, m[3], 2,2 ); + } + else if( size == PIXEL_8x4 ) + { + x264_me_t *m = a->l0.me8x4[i8x8]; + CHROMA4x4MC( 4,2, m[0], 0,0 ); + CHROMA4x4MC( 4,2, m[1], 0,2 ); + } + else + { + x264_me_t *m = a->l0.me4x8[i8x8]; + CHROMA4x4MC( 2,4, m[0], 0,0 ); + CHROMA4x4MC( 2,4, m[1], 2,0 ); + } +#undef CHROMA4x4MC + + int oe = (8>>chroma_h_shift)*(i8x8&1) + (4>>chroma_v_shift)*(i8x8&2)*FENC_STRIDE; + int chromapix = chroma == CHROMA_444 ? PIXEL_8x8 : chroma == CHROMA_422 ? PIXEL_4x8 : PIXEL_4x4; + return h->pixf.mbcmp[chromapix]( &h->mb.pic.p_fenc[1][oe], FENC_STRIDE, pix1, 16 ) + + h->pixf.mbcmp[chromapix]( &h->mb.pic.p_fenc[2][oe], FENC_STRIDE, pix2, 16 ); +} + +static int x264_mb_analyse_inter_p4x4_chroma( x264_t *h, x264_mb_analysis_t *a, pixel **p_fref, int i8x8, int size ) +{ + if( CHROMA_FORMAT == CHROMA_444 ) + return x264_mb_analyse_inter_p4x4_chroma_internal( h, a, p_fref, i8x8, size, CHROMA_444 ); + else if( CHROMA_FORMAT == CHROMA_422 ) + return x264_mb_analyse_inter_p4x4_chroma_internal( h, a, p_fref, i8x8, size, CHROMA_422 ); + else + return x264_mb_analyse_inter_p4x4_chroma_internal( h, a, p_fref, i8x8, size, CHROMA_420 ); +} + +static void x264_mb_analyse_inter_p4x4( x264_t *h, x264_mb_analysis_t *a, int i8x8 ) +{ + pixel **p_fref = h->mb.pic.p_fref[0][a->l0.me8x8[i8x8].i_ref]; + pixel **p_fenc = h->mb.pic.p_fenc; + const int i_ref = a->l0.me8x8[i8x8].i_ref; + + /* XXX Needed for x264_mb_predict_mv */ + h->mb.i_partition = D_8x8; + + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + { + const int idx = 4*i8x8 + i4x4; + const int x4 = block_idx_x[idx]; + const int y4 = block_idx_y[idx]; + const int i_mvc = (i4x4 == 0); + + x264_me_t *m = &a->l0.me4x4[i8x8][i4x4]; + + m->i_pixel = PIXEL_4x4; + + LOAD_FENC( m, p_fenc, 4*x4, 4*y4 ); + LOAD_HPELS( m, p_fref, 0, i_ref, 4*x4, 4*y4 ); + LOAD_WPELS( m, h->mb.pic.p_fref_w[i_ref], 0, i_ref, 4*x4, 4*y4 ); + + x264_mb_predict_mv( h, 0, idx, 1, m->mvp ); + x264_me_search( h, m, &a->l0.me8x8[i8x8].mv, i_mvc ); + + x264_macroblock_cache_mv_ptr( h, x4, y4, 1, 1, 0, m->mv ); + } + a->l0.i_cost4x4[i8x8] = a->l0.me4x4[i8x8][0].cost + + a->l0.me4x4[i8x8][1].cost + + a->l0.me4x4[i8x8][2].cost + + a->l0.me4x4[i8x8][3].cost + + REF_COST( 0, i_ref ) + + a->i_lambda * i_sub_mb_p_cost_table[D_L0_4x4]; + if( h->mb.b_chroma_me && !CHROMA444 ) + a->l0.i_cost4x4[i8x8] += x264_mb_analyse_inter_p4x4_chroma( h, a, p_fref, i8x8, PIXEL_4x4 ); +} + +static void x264_mb_analyse_inter_p8x4( x264_t *h, x264_mb_analysis_t *a, int i8x8 ) +{ + pixel **p_fref = h->mb.pic.p_fref[0][a->l0.me8x8[i8x8].i_ref]; + pixel **p_fenc = h->mb.pic.p_fenc; + const int i_ref = a->l0.me8x8[i8x8].i_ref; + + /* XXX Needed for x264_mb_predict_mv */ + h->mb.i_partition = D_8x8; + + for( int i8x4 = 0; i8x4 < 2; i8x4++ ) + { + const int idx = 4*i8x8 + 2*i8x4; + const int x4 = block_idx_x[idx]; + const int y4 = block_idx_y[idx]; + const int i_mvc = (i8x4 == 0); + + x264_me_t *m = &a->l0.me8x4[i8x8][i8x4]; + + m->i_pixel = PIXEL_8x4; + + LOAD_FENC( m, p_fenc, 4*x4, 4*y4 ); + LOAD_HPELS( m, p_fref, 0, i_ref, 4*x4, 4*y4 ); + LOAD_WPELS( m, h->mb.pic.p_fref_w[i_ref], 0, i_ref, 4*x4, 4*y4 ); + + x264_mb_predict_mv( h, 0, idx, 2, m->mvp ); + x264_me_search( h, m, &a->l0.me4x4[i8x8][0].mv, i_mvc ); + + x264_macroblock_cache_mv_ptr( h, x4, y4, 2, 1, 0, m->mv ); + } + a->l0.i_cost8x4[i8x8] = a->l0.me8x4[i8x8][0].cost + a->l0.me8x4[i8x8][1].cost + + REF_COST( 0, i_ref ) + + a->i_lambda * i_sub_mb_p_cost_table[D_L0_8x4]; + if( h->mb.b_chroma_me && !CHROMA444 ) + a->l0.i_cost8x4[i8x8] += x264_mb_analyse_inter_p4x4_chroma( h, a, p_fref, i8x8, PIXEL_8x4 ); +} + +static void x264_mb_analyse_inter_p4x8( x264_t *h, x264_mb_analysis_t *a, int i8x8 ) +{ + pixel **p_fref = h->mb.pic.p_fref[0][a->l0.me8x8[i8x8].i_ref]; + pixel **p_fenc = h->mb.pic.p_fenc; + const int i_ref = a->l0.me8x8[i8x8].i_ref; + + /* XXX Needed for x264_mb_predict_mv */ + h->mb.i_partition = D_8x8; + + for( int i4x8 = 0; i4x8 < 2; i4x8++ ) + { + const int idx = 4*i8x8 + i4x8; + const int x4 = block_idx_x[idx]; + const int y4 = block_idx_y[idx]; + const int i_mvc = (i4x8 == 0); + + x264_me_t *m = &a->l0.me4x8[i8x8][i4x8]; + + m->i_pixel = PIXEL_4x8; + + LOAD_FENC( m, p_fenc, 4*x4, 4*y4 ); + LOAD_HPELS( m, p_fref, 0, i_ref, 4*x4, 4*y4 ); + LOAD_WPELS( m, h->mb.pic.p_fref_w[i_ref], 0, i_ref, 4*x4, 4*y4 ); + + x264_mb_predict_mv( h, 0, idx, 1, m->mvp ); + x264_me_search( h, m, &a->l0.me4x4[i8x8][0].mv, i_mvc ); + + x264_macroblock_cache_mv_ptr( h, x4, y4, 1, 2, 0, m->mv ); + } + a->l0.i_cost4x8[i8x8] = a->l0.me4x8[i8x8][0].cost + a->l0.me4x8[i8x8][1].cost + + REF_COST( 0, i_ref ) + + a->i_lambda * i_sub_mb_p_cost_table[D_L0_4x8]; + if( h->mb.b_chroma_me && !CHROMA444 ) + a->l0.i_cost4x8[i8x8] += x264_mb_analyse_inter_p4x4_chroma( h, a, p_fref, i8x8, PIXEL_4x8 ); +} + +static ALWAYS_INLINE int x264_analyse_bi_chroma( x264_t *h, x264_mb_analysis_t *a, int idx, int i_pixel ) +{ + ALIGNED_ARRAY_32( pixel, pix, [4],[16*16] ); + ALIGNED_ARRAY_32( pixel, bi, [2],[16*16] ); + int i_chroma_cost = 0; + int chromapix = h->luma2chroma_pixel[i_pixel]; + +#define COST_BI_CHROMA( m0, m1, width, height ) \ +{ \ + if( CHROMA444 ) \ + { \ + h->mc.mc_luma( pix[0], 16, &m0.p_fref[4], m0.i_stride[1], \ + m0.mv[0], m0.mv[1], width, height, x264_weight_none ); \ + h->mc.mc_luma( pix[1], 16, &m0.p_fref[8], m0.i_stride[2], \ + m0.mv[0], m0.mv[1], width, height, x264_weight_none ); \ + h->mc.mc_luma( pix[2], 16, &m1.p_fref[4], m1.i_stride[1], \ + m1.mv[0], m1.mv[1], width, height, x264_weight_none ); \ + h->mc.mc_luma( pix[3], 16, &m1.p_fref[8], m1.i_stride[2], \ + m1.mv[0], m1.mv[1], width, height, x264_weight_none ); \ + } \ + else \ + { \ + int v_shift = CHROMA_V_SHIFT; \ + int l0_mvy_offset = v_shift & MB_INTERLACED & m0.i_ref ? (h->mb.i_mb_y & 1)*4 - 2 : 0; \ + int l1_mvy_offset = v_shift & MB_INTERLACED & m1.i_ref ? (h->mb.i_mb_y & 1)*4 - 2 : 0; \ + h->mc.mc_chroma( pix[0], pix[1], 16, m0.p_fref[4], m0.i_stride[1], \ + m0.mv[0], 2*(m0.mv[1]+l0_mvy_offset)>>v_shift, width>>1, height>>v_shift ); \ + h->mc.mc_chroma( pix[2], pix[3], 16, m1.p_fref[4], m1.i_stride[1], \ + m1.mv[0], 2*(m1.mv[1]+l1_mvy_offset)>>v_shift, width>>1, height>>v_shift ); \ + } \ + h->mc.avg[chromapix]( bi[0], 16, pix[0], 16, pix[2], 16, h->mb.bipred_weight[m0.i_ref][m1.i_ref] ); \ + h->mc.avg[chromapix]( bi[1], 16, pix[1], 16, pix[3], 16, h->mb.bipred_weight[m0.i_ref][m1.i_ref] ); \ + i_chroma_cost = h->pixf.mbcmp[chromapix]( m0.p_fenc[1], FENC_STRIDE, bi[0], 16 ) \ + + h->pixf.mbcmp[chromapix]( m0.p_fenc[2], FENC_STRIDE, bi[1], 16 ); \ +} + + if( i_pixel == PIXEL_16x16 ) + COST_BI_CHROMA( a->l0.bi16x16, a->l1.bi16x16, 16, 16 ) + else if( i_pixel == PIXEL_16x8 ) + COST_BI_CHROMA( a->l0.me16x8[idx], a->l1.me16x8[idx], 16, 8 ) + else if( i_pixel == PIXEL_8x16 ) + COST_BI_CHROMA( a->l0.me8x16[idx], a->l1.me8x16[idx], 8, 16 ) + else + COST_BI_CHROMA( a->l0.me8x8[idx], a->l1.me8x8[idx], 8, 8 ) + + return i_chroma_cost; +} + +static void x264_mb_analyse_inter_direct( x264_t *h, x264_mb_analysis_t *a ) +{ + /* Assumes that fdec still contains the results of + * x264_mb_predict_mv_direct16x16 and x264_mb_mc */ + + pixel *p_fenc = h->mb.pic.p_fenc[0]; + pixel *p_fdec = h->mb.pic.p_fdec[0]; + + a->i_cost16x16direct = a->i_lambda * i_mb_b_cost_table[B_DIRECT]; + if( h->param.analyse.inter & X264_ANALYSE_BSUB16x16 ) + { + int chromapix = h->luma2chroma_pixel[PIXEL_8x8]; + + for( int i = 0; i < 4; i++ ) + { + const int x = (i&1)*8; + const int y = (i>>1)*8; + a->i_cost8x8direct[i] = h->pixf.mbcmp[PIXEL_8x8]( &p_fenc[x+y*FENC_STRIDE], FENC_STRIDE, + &p_fdec[x+y*FDEC_STRIDE], FDEC_STRIDE ); + if( h->mb.b_chroma_me ) + { + int fenc_offset = (x>>CHROMA_H_SHIFT) + (y>>CHROMA_V_SHIFT)*FENC_STRIDE; + int fdec_offset = (x>>CHROMA_H_SHIFT) + (y>>CHROMA_V_SHIFT)*FDEC_STRIDE; + a->i_cost8x8direct[i] += h->pixf.mbcmp[chromapix]( &h->mb.pic.p_fenc[1][fenc_offset], FENC_STRIDE, + &h->mb.pic.p_fdec[1][fdec_offset], FDEC_STRIDE ) + + h->pixf.mbcmp[chromapix]( &h->mb.pic.p_fenc[2][fenc_offset], FENC_STRIDE, + &h->mb.pic.p_fdec[2][fdec_offset], FDEC_STRIDE ); + } + a->i_cost16x16direct += a->i_cost8x8direct[i]; + + /* mb type cost */ + a->i_cost8x8direct[i] += a->i_lambda * i_sub_mb_b_cost_table[D_DIRECT_8x8]; + } + } + else + { + a->i_cost16x16direct += h->pixf.mbcmp[PIXEL_16x16]( p_fenc, FENC_STRIDE, p_fdec, FDEC_STRIDE ); + if( h->mb.b_chroma_me ) + { + int chromapix = h->luma2chroma_pixel[PIXEL_16x16]; + a->i_cost16x16direct += h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE ) + + h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE ); + } + } +} + +static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a ) +{ + ALIGNED_ARRAY_32( pixel, pix0,[16*16] ); + ALIGNED_ARRAY_32( pixel, pix1,[16*16] ); + pixel *src0, *src1; + intptr_t stride0 = 16, stride1 = 16; + int i_ref, i_mvc; + ALIGNED_4( int16_t mvc[9][2] ); + int try_skip = a->b_try_skip; + int list1_skipped = 0; + int i_halfpel_thresh[2] = {INT_MAX, INT_MAX}; + int *p_halfpel_thresh[2] = {(a->b_early_terminate && h->mb.pic.i_fref[0]>1) ? &i_halfpel_thresh[0] : NULL, + (a->b_early_terminate && h->mb.pic.i_fref[1]>1) ? &i_halfpel_thresh[1] : NULL}; + + x264_me_t m; + m.i_pixel = PIXEL_16x16; + + LOAD_FENC( &m, h->mb.pic.p_fenc, 0, 0 ); + + /* 16x16 Search on list 0 and list 1 */ + a->l0.me16x16.cost = INT_MAX; + a->l1.me16x16.cost = INT_MAX; + for( int l = 1; l >= 0; ) + { + x264_mb_analysis_list_t *lX = l ? &a->l1 : &a->l0; + + /* This loop is extremely munged in order to facilitate the following order of operations, + * necessary for an efficient fast skip. + * 1. Search list1 ref0. + * 2. Search list0 ref0. + * 3. Try skip. + * 4. Search the rest of list0. + * 5. Go back and finish list1. + */ + for( i_ref = (list1_skipped && l == 1) ? 1 : 0; i_ref < h->mb.pic.i_fref[l]; i_ref++ ) + { + if( try_skip && l == 1 && i_ref > 0 ) + { + list1_skipped = 1; + break; + } + + m.i_ref_cost = REF_COST( l, i_ref ); + + /* search with ref */ + LOAD_HPELS( &m, h->mb.pic.p_fref[l][i_ref], l, i_ref, 0, 0 ); + x264_mb_predict_mv_16x16( h, l, i_ref, m.mvp ); + x264_mb_predict_mv_ref16x16( h, l, i_ref, mvc, &i_mvc ); + x264_me_search_ref( h, &m, mvc, i_mvc, p_halfpel_thresh[l] ); + + /* add ref cost */ + m.cost += m.i_ref_cost; + + if( m.cost < lX->me16x16.cost ) + h->mc.memcpy_aligned( &lX->me16x16, &m, sizeof(x264_me_t) ); + + /* save mv for predicting neighbors */ + CP32( lX->mvc[i_ref][0], m.mv ); + CP32( h->mb.mvr[l][i_ref][h->mb.i_mb_xy], m.mv ); + + /* Fast skip detection. */ + if( i_ref == 0 && try_skip ) + { + if( abs(lX->me16x16.mv[0]-h->mb.cache.direct_mv[l][0][0]) + + abs(lX->me16x16.mv[1]-h->mb.cache.direct_mv[l][0][1]) > 1 ) + { + try_skip = 0; + } + else if( !l ) + { + /* We already tested skip */ + h->mb.i_type = B_SKIP; + x264_analyse_update_cache( h, a ); + return; + } + } + } + if( list1_skipped && l == 1 && i_ref == h->mb.pic.i_fref[1] ) + break; + if( list1_skipped && l == 0 ) + l = 1; + else + l--; + } + + /* get cost of BI mode */ + h->mc.memcpy_aligned( &a->l0.bi16x16, &a->l0.me16x16, sizeof(x264_me_t) ); + h->mc.memcpy_aligned( &a->l1.bi16x16, &a->l1.me16x16, sizeof(x264_me_t) ); + int ref_costs = REF_COST( 0, a->l0.bi16x16.i_ref ) + REF_COST( 1, a->l1.bi16x16.i_ref ); + src0 = h->mc.get_ref( pix0, &stride0, + h->mb.pic.p_fref[0][a->l0.bi16x16.i_ref], h->mb.pic.i_stride[0], + a->l0.bi16x16.mv[0], a->l0.bi16x16.mv[1], 16, 16, x264_weight_none ); + src1 = h->mc.get_ref( pix1, &stride1, + h->mb.pic.p_fref[1][a->l1.bi16x16.i_ref], h->mb.pic.i_stride[0], + a->l1.bi16x16.mv[0], a->l1.bi16x16.mv[1], 16, 16, x264_weight_none ); + + h->mc.avg[PIXEL_16x16]( pix0, 16, src0, stride0, src1, stride1, h->mb.bipred_weight[a->l0.bi16x16.i_ref][a->l1.bi16x16.i_ref] ); + + a->i_cost16x16bi = h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[0], FENC_STRIDE, pix0, 16 ) + + ref_costs + + a->l0.bi16x16.cost_mv + + a->l1.bi16x16.cost_mv; + + if( h->mb.b_chroma_me ) + a->i_cost16x16bi += x264_analyse_bi_chroma( h, a, 0, PIXEL_16x16 ); + + /* Always try the 0,0,0,0 vector; helps avoid errant motion vectors in fades */ + if( M32( a->l0.bi16x16.mv ) | M32( a->l1.bi16x16.mv ) ) + { + int l0_mv_cost = a->l0.bi16x16.p_cost_mv[-a->l0.bi16x16.mvp[0]] + + a->l0.bi16x16.p_cost_mv[-a->l0.bi16x16.mvp[1]]; + int l1_mv_cost = a->l1.bi16x16.p_cost_mv[-a->l1.bi16x16.mvp[0]] + + a->l1.bi16x16.p_cost_mv[-a->l1.bi16x16.mvp[1]]; + h->mc.avg[PIXEL_16x16]( pix0, 16, h->mb.pic.p_fref[0][a->l0.bi16x16.i_ref][0], h->mb.pic.i_stride[0], + h->mb.pic.p_fref[1][a->l1.bi16x16.i_ref][0], h->mb.pic.i_stride[0], + h->mb.bipred_weight[a->l0.bi16x16.i_ref][a->l1.bi16x16.i_ref] ); + int cost00 = h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[0], FENC_STRIDE, pix0, 16 ) + + ref_costs + l0_mv_cost + l1_mv_cost; + + if( h->mb.b_chroma_me && cost00 < a->i_cost16x16bi ) + { + ALIGNED_ARRAY_16( pixel, bi, [16*FENC_STRIDE] ); + + if( CHROMA444 ) + { + h->mc.avg[PIXEL_16x16]( bi, FENC_STRIDE, h->mb.pic.p_fref[0][a->l0.bi16x16.i_ref][4], h->mb.pic.i_stride[1], + h->mb.pic.p_fref[1][a->l1.bi16x16.i_ref][4], h->mb.pic.i_stride[1], + h->mb.bipred_weight[a->l0.bi16x16.i_ref][a->l1.bi16x16.i_ref] ); + cost00 += h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[1], FENC_STRIDE, bi, FENC_STRIDE ); + h->mc.avg[PIXEL_16x16]( bi, FENC_STRIDE, h->mb.pic.p_fref[0][a->l0.bi16x16.i_ref][8], h->mb.pic.i_stride[2], + h->mb.pic.p_fref[1][a->l1.bi16x16.i_ref][8], h->mb.pic.i_stride[2], + h->mb.bipred_weight[a->l0.bi16x16.i_ref][a->l1.bi16x16.i_ref] ); + cost00 += h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[2], FENC_STRIDE, bi, FENC_STRIDE ); + } + else + { + ALIGNED_ARRAY_32( pixel, pixuv, [2],[16*FENC_STRIDE] ); + int chromapix = h->luma2chroma_pixel[PIXEL_16x16]; + int v_shift = CHROMA_V_SHIFT; + + if( v_shift & MB_INTERLACED & a->l0.bi16x16.i_ref ) + { + int l0_mvy_offset = (h->mb.i_mb_y & 1)*4 - 2; + h->mc.mc_chroma( pixuv[0], pixuv[0]+8, FENC_STRIDE, h->mb.pic.p_fref[0][a->l0.bi16x16.i_ref][4], + h->mb.pic.i_stride[1], 0, 0 + l0_mvy_offset, 8, 8 ); + } + else + h->mc.load_deinterleave_chroma_fenc( pixuv[0], h->mb.pic.p_fref[0][a->l0.bi16x16.i_ref][4], + h->mb.pic.i_stride[1], 16>>v_shift ); + + if( v_shift & MB_INTERLACED & a->l1.bi16x16.i_ref ) + { + int l1_mvy_offset = (h->mb.i_mb_y & 1)*4 - 2; + h->mc.mc_chroma( pixuv[1], pixuv[1]+8, FENC_STRIDE, h->mb.pic.p_fref[1][a->l1.bi16x16.i_ref][4], + h->mb.pic.i_stride[1], 0, 0 + l1_mvy_offset, 8, 8 ); + } + else + h->mc.load_deinterleave_chroma_fenc( pixuv[1], h->mb.pic.p_fref[1][a->l1.bi16x16.i_ref][4], + h->mb.pic.i_stride[1], 16>>v_shift ); + + h->mc.avg[chromapix]( bi, FENC_STRIDE, pixuv[0], FENC_STRIDE, pixuv[1], FENC_STRIDE, + h->mb.bipred_weight[a->l0.bi16x16.i_ref][a->l1.bi16x16.i_ref] ); + h->mc.avg[chromapix]( bi+8, FENC_STRIDE, pixuv[0]+8, FENC_STRIDE, pixuv[1]+8, FENC_STRIDE, + h->mb.bipred_weight[a->l0.bi16x16.i_ref][a->l1.bi16x16.i_ref] ); + + cost00 += h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[1], FENC_STRIDE, bi, FENC_STRIDE ) + + h->pixf.mbcmp[chromapix]( h->mb.pic.p_fenc[2], FENC_STRIDE, bi+8, FENC_STRIDE ); + } + } + + if( cost00 < a->i_cost16x16bi ) + { + M32( a->l0.bi16x16.mv ) = 0; + M32( a->l1.bi16x16.mv ) = 0; + a->l0.bi16x16.cost_mv = l0_mv_cost; + a->l1.bi16x16.cost_mv = l1_mv_cost; + a->i_cost16x16bi = cost00; + } + } + + /* mb type cost */ + a->i_cost16x16bi += a->i_lambda * i_mb_b_cost_table[B_BI_BI]; + a->l0.me16x16.cost += a->i_lambda * i_mb_b_cost_table[B_L0_L0]; + a->l1.me16x16.cost += a->i_lambda * i_mb_b_cost_table[B_L1_L1]; +} + +static inline void x264_mb_cache_mv_p8x8( x264_t *h, x264_mb_analysis_t *a, int i ) +{ + int x = 2*(i&1); + int y = i&2; + + switch( h->mb.i_sub_partition[i] ) + { + case D_L0_8x8: + x264_macroblock_cache_mv_ptr( h, x, y, 2, 2, 0, a->l0.me8x8[i].mv ); + break; + case D_L0_8x4: + x264_macroblock_cache_mv_ptr( h, x, y+0, 2, 1, 0, a->l0.me8x4[i][0].mv ); + x264_macroblock_cache_mv_ptr( h, x, y+1, 2, 1, 0, a->l0.me8x4[i][1].mv ); + break; + case D_L0_4x8: + x264_macroblock_cache_mv_ptr( h, x+0, y, 1, 2, 0, a->l0.me4x8[i][0].mv ); + x264_macroblock_cache_mv_ptr( h, x+1, y, 1, 2, 0, a->l0.me4x8[i][1].mv ); + break; + case D_L0_4x4: + x264_macroblock_cache_mv_ptr( h, x+0, y+0, 1, 1, 0, a->l0.me4x4[i][0].mv ); + x264_macroblock_cache_mv_ptr( h, x+1, y+0, 1, 1, 0, a->l0.me4x4[i][1].mv ); + x264_macroblock_cache_mv_ptr( h, x+0, y+1, 1, 1, 0, a->l0.me4x4[i][2].mv ); + x264_macroblock_cache_mv_ptr( h, x+1, y+1, 1, 1, 0, a->l0.me4x4[i][3].mv ); + break; + default: + x264_log( h, X264_LOG_ERROR, "internal error\n" ); + break; + } +} + +static void x264_mb_load_mv_direct8x8( x264_t *h, int idx ) +{ + int x = 2*(idx&1); + int y = idx&2; + x264_macroblock_cache_ref( h, x, y, 2, 2, 0, h->mb.cache.direct_ref[0][idx] ); + x264_macroblock_cache_ref( h, x, y, 2, 2, 1, h->mb.cache.direct_ref[1][idx] ); + x264_macroblock_cache_mv_ptr( h, x, y, 2, 2, 0, h->mb.cache.direct_mv[0][idx] ); + x264_macroblock_cache_mv_ptr( h, x, y, 2, 2, 1, h->mb.cache.direct_mv[1][idx] ); +} + +#define CACHE_MV_BI(x,y,dx,dy,me0,me1,part) \ + if( x264_mb_partition_listX_table[0][part] ) \ + { \ + x264_macroblock_cache_ref( h, x,y,dx,dy, 0, me0.i_ref ); \ + x264_macroblock_cache_mv_ptr( h, x,y,dx,dy, 0, me0.mv ); \ + } \ + else \ + { \ + x264_macroblock_cache_ref( h, x,y,dx,dy, 0, -1 ); \ + x264_macroblock_cache_mv( h, x,y,dx,dy, 0, 0 ); \ + if( b_mvd ) \ + x264_macroblock_cache_mvd( h, x,y,dx,dy, 0, 0 ); \ + } \ + if( x264_mb_partition_listX_table[1][part] ) \ + { \ + x264_macroblock_cache_ref( h, x,y,dx,dy, 1, me1.i_ref ); \ + x264_macroblock_cache_mv_ptr( h, x,y,dx,dy, 1, me1.mv ); \ + } \ + else \ + { \ + x264_macroblock_cache_ref( h, x,y,dx,dy, 1, -1 ); \ + x264_macroblock_cache_mv( h, x,y,dx,dy, 1, 0 ); \ + if( b_mvd ) \ + x264_macroblock_cache_mvd( h, x,y,dx,dy, 1, 0 ); \ + } + +static inline void x264_mb_cache_mv_b8x8( x264_t *h, x264_mb_analysis_t *a, int i, int b_mvd ) +{ + int x = 2*(i&1); + int y = i&2; + if( h->mb.i_sub_partition[i] == D_DIRECT_8x8 ) + { + x264_mb_load_mv_direct8x8( h, i ); + if( b_mvd ) + { + x264_macroblock_cache_mvd( h, x, y, 2, 2, 0, 0 ); + x264_macroblock_cache_mvd( h, x, y, 2, 2, 1, 0 ); + x264_macroblock_cache_skip( h, x, y, 2, 2, 1 ); + } + } + else + { + CACHE_MV_BI( x, y, 2, 2, a->l0.me8x8[i], a->l1.me8x8[i], h->mb.i_sub_partition[i] ); + } +} +static inline void x264_mb_cache_mv_b16x8( x264_t *h, x264_mb_analysis_t *a, int i, int b_mvd ) +{ + CACHE_MV_BI( 0, 2*i, 4, 2, a->l0.me16x8[i], a->l1.me16x8[i], a->i_mb_partition16x8[i] ); +} +static inline void x264_mb_cache_mv_b8x16( x264_t *h, x264_mb_analysis_t *a, int i, int b_mvd ) +{ + CACHE_MV_BI( 2*i, 0, 2, 4, a->l0.me8x16[i], a->l1.me8x16[i], a->i_mb_partition8x16[i] ); +} +#undef CACHE_MV_BI + +static void x264_mb_analyse_inter_b8x8_mixed_ref( x264_t *h, x264_mb_analysis_t *a ) +{ + ALIGNED_ARRAY_16( pixel, pix,[2],[8*8] ); + int i_maxref[2] = {h->mb.pic.i_fref[0]-1, h->mb.pic.i_fref[1]-1}; + + /* early termination: if 16x16 chose ref 0, then evalute no refs older + * than those used by the neighbors */ + #define CHECK_NEIGHBOUR(i)\ + {\ + int ref = h->mb.cache.ref[l][X264_SCAN8_0+i];\ + if( ref > i_maxref[l] )\ + i_maxref[l] = ref;\ + } + + for( int l = 0; l < 2; l++ ) + { + x264_mb_analysis_list_t *lX = l ? &a->l1 : &a->l0; + if( i_maxref[l] > 0 && lX->me16x16.i_ref == 0 && + h->mb.i_mb_type_top > 0 && h->mb.i_mb_type_left[0] > 0 ) + { + i_maxref[l] = 0; + CHECK_NEIGHBOUR( -8 - 1 ); + CHECK_NEIGHBOUR( -8 + 0 ); + CHECK_NEIGHBOUR( -8 + 2 ); + CHECK_NEIGHBOUR( -8 + 4 ); + CHECK_NEIGHBOUR( 0 - 1 ); + CHECK_NEIGHBOUR( 2*8 - 1 ); + } + } + + /* XXX Needed for x264_mb_predict_mv */ + h->mb.i_partition = D_8x8; + + a->i_cost8x8bi = 0; + + for( int i = 0; i < 4; i++ ) + { + int x8 = i&1; + int y8 = i>>1; + int i_part_cost; + int i_part_cost_bi; + intptr_t stride[2] = {8,8}; + pixel *src[2]; + x264_me_t m; + m.i_pixel = PIXEL_8x8; + LOAD_FENC( &m, h->mb.pic.p_fenc, 8*x8, 8*y8 ); + + for( int l = 0; l < 2; l++ ) + { + x264_mb_analysis_list_t *lX = l ? &a->l1 : &a->l0; + + lX->me8x8[i].cost = INT_MAX; + for( int i_ref = 0; i_ref <= i_maxref[l]; i_ref++ ) + { + m.i_ref_cost = REF_COST( l, i_ref ); + + LOAD_HPELS( &m, h->mb.pic.p_fref[l][i_ref], l, i_ref, 8*x8, 8*y8 ); + + x264_macroblock_cache_ref( h, x8*2, y8*2, 2, 2, l, i_ref ); + x264_mb_predict_mv( h, l, 4*i, 2, m.mvp ); + x264_me_search( h, &m, lX->mvc[i_ref], i+1 ); + m.cost += m.i_ref_cost; + + if( m.cost < lX->me8x8[i].cost ) + { + h->mc.memcpy_aligned( &lX->me8x8[i], &m, sizeof(x264_me_t) ); + a->i_satd8x8[l][i] = m.cost - ( m.cost_mv + m.i_ref_cost ); + } + + /* save mv for predicting other partitions within this MB */ + CP32( lX->mvc[i_ref][i+1], m.mv ); + } + } + + /* BI mode */ + src[0] = h->mc.get_ref( pix[0], &stride[0], a->l0.me8x8[i].p_fref, a->l0.me8x8[i].i_stride[0], + a->l0.me8x8[i].mv[0], a->l0.me8x8[i].mv[1], 8, 8, x264_weight_none ); + src[1] = h->mc.get_ref( pix[1], &stride[1], a->l1.me8x8[i].p_fref, a->l1.me8x8[i].i_stride[0], + a->l1.me8x8[i].mv[0], a->l1.me8x8[i].mv[1], 8, 8, x264_weight_none ); + h->mc.avg[PIXEL_8x8]( pix[0], 8, src[0], stride[0], src[1], stride[1], + h->mb.bipred_weight[a->l0.me8x8[i].i_ref][a->l1.me8x8[i].i_ref] ); + + a->i_satd8x8[2][i] = h->pixf.mbcmp[PIXEL_8x8]( a->l0.me8x8[i].p_fenc[0], FENC_STRIDE, pix[0], 8 ); + i_part_cost_bi = a->i_satd8x8[2][i] + a->l0.me8x8[i].cost_mv + a->l1.me8x8[i].cost_mv + + a->l0.me8x8[i].i_ref_cost + a->l1.me8x8[i].i_ref_cost + + a->i_lambda * i_sub_mb_b_cost_table[D_BI_8x8]; + + if( h->mb.b_chroma_me ) + { + int i_chroma_cost = x264_analyse_bi_chroma( h, a, i, PIXEL_8x8 ); + i_part_cost_bi += i_chroma_cost; + a->i_satd8x8[2][i] += i_chroma_cost; + } + + a->l0.me8x8[i].cost += a->i_lambda * i_sub_mb_b_cost_table[D_L0_8x8]; + a->l1.me8x8[i].cost += a->i_lambda * i_sub_mb_b_cost_table[D_L1_8x8]; + + i_part_cost = a->l0.me8x8[i].cost; + h->mb.i_sub_partition[i] = D_L0_8x8; + COPY2_IF_LT( i_part_cost, a->l1.me8x8[i].cost, h->mb.i_sub_partition[i], D_L1_8x8 ); + COPY2_IF_LT( i_part_cost, i_part_cost_bi, h->mb.i_sub_partition[i], D_BI_8x8 ); + COPY2_IF_LT( i_part_cost, a->i_cost8x8direct[i], h->mb.i_sub_partition[i], D_DIRECT_8x8 ); + a->i_cost8x8bi += i_part_cost; + + /* XXX Needed for x264_mb_predict_mv */ + x264_mb_cache_mv_b8x8( h, a, i, 0 ); + } + + /* mb type cost */ + a->i_cost8x8bi += a->i_lambda * i_mb_b_cost_table[B_8x8]; +} + +static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a ) +{ + pixel **p_fref[2] = + { h->mb.pic.p_fref[0][a->l0.me16x16.i_ref], + h->mb.pic.p_fref[1][a->l1.me16x16.i_ref] }; + ALIGNED_ARRAY_16( pixel, pix,[2],[8*8] ); + + /* XXX Needed for x264_mb_predict_mv */ + h->mb.i_partition = D_8x8; + + a->i_cost8x8bi = 0; + + for( int i = 0; i < 4; i++ ) + { + int x8 = i&1; + int y8 = i>>1; + int i_part_cost; + int i_part_cost_bi = 0; + intptr_t stride[2] = {8,8}; + pixel *src[2]; + + for( int l = 0; l < 2; l++ ) + { + x264_mb_analysis_list_t *lX = l ? &a->l1 : &a->l0; + x264_me_t *m = &lX->me8x8[i]; + m->i_pixel = PIXEL_8x8; + LOAD_FENC( m, h->mb.pic.p_fenc, 8*x8, 8*y8 ); + + m->i_ref_cost = REF_COST( l, lX->me16x16.i_ref ); + m->i_ref = lX->me16x16.i_ref; + + LOAD_HPELS( m, p_fref[l], l, lX->me16x16.i_ref, 8*x8, 8*y8 ); + + x264_macroblock_cache_ref( h, x8*2, y8*2, 2, 2, l, lX->me16x16.i_ref ); + x264_mb_predict_mv( h, l, 4*i, 2, m->mvp ); + x264_me_search( h, m, &lX->me16x16.mv, 1 ); + a->i_satd8x8[l][i] = m->cost - m->cost_mv; + m->cost += m->i_ref_cost; + + x264_macroblock_cache_mv_ptr( h, 2*x8, 2*y8, 2, 2, l, m->mv ); + + /* save mv for predicting other partitions within this MB */ + CP32( lX->mvc[lX->me16x16.i_ref][i+1], m->mv ); + + /* BI mode */ + src[l] = h->mc.get_ref( pix[l], &stride[l], m->p_fref, m->i_stride[0], + m->mv[0], m->mv[1], 8, 8, x264_weight_none ); + i_part_cost_bi += m->cost_mv + m->i_ref_cost; + } + h->mc.avg[PIXEL_8x8]( pix[0], 8, src[0], stride[0], src[1], stride[1], h->mb.bipred_weight[a->l0.me16x16.i_ref][a->l1.me16x16.i_ref] ); + a->i_satd8x8[2][i] = h->pixf.mbcmp[PIXEL_8x8]( a->l0.me8x8[i].p_fenc[0], FENC_STRIDE, pix[0], 8 ); + i_part_cost_bi += a->i_satd8x8[2][i] + a->i_lambda * i_sub_mb_b_cost_table[D_BI_8x8]; + a->l0.me8x8[i].cost += a->i_lambda * i_sub_mb_b_cost_table[D_L0_8x8]; + a->l1.me8x8[i].cost += a->i_lambda * i_sub_mb_b_cost_table[D_L1_8x8]; + + if( h->mb.b_chroma_me ) + { + int i_chroma_cost = x264_analyse_bi_chroma( h, a, i, PIXEL_8x8 ); + i_part_cost_bi += i_chroma_cost; + a->i_satd8x8[2][i] += i_chroma_cost; + } + + i_part_cost = a->l0.me8x8[i].cost; + h->mb.i_sub_partition[i] = D_L0_8x8; + COPY2_IF_LT( i_part_cost, a->l1.me8x8[i].cost, h->mb.i_sub_partition[i], D_L1_8x8 ); + COPY2_IF_LT( i_part_cost, i_part_cost_bi, h->mb.i_sub_partition[i], D_BI_8x8 ); + COPY2_IF_LT( i_part_cost, a->i_cost8x8direct[i], h->mb.i_sub_partition[i], D_DIRECT_8x8 ); + a->i_cost8x8bi += i_part_cost; + + /* XXX Needed for x264_mb_predict_mv */ + x264_mb_cache_mv_b8x8( h, a, i, 0 ); + } + + /* mb type cost */ + a->i_cost8x8bi += a->i_lambda * i_mb_b_cost_table[B_8x8]; +} + +static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a, int i_best_satd ) +{ + ALIGNED_ARRAY_32( pixel, pix,[2],[16*8] ); + ALIGNED_4( int16_t mvc[3][2] ); + + h->mb.i_partition = D_16x8; + a->i_cost16x8bi = 0; + + for( int i = 0; i < 2; i++ ) + { + int i_part_cost; + int i_part_cost_bi = 0; + intptr_t stride[2] = {16,16}; + pixel *src[2]; + x264_me_t m; + m.i_pixel = PIXEL_16x8; + LOAD_FENC( &m, h->mb.pic.p_fenc, 0, 8*i ); + + for( int l = 0; l < 2; l++ ) + { + x264_mb_analysis_list_t *lX = l ? &a->l1 : &a->l0; + int ref8[2] = { lX->me8x8[2*i].i_ref, lX->me8x8[2*i+1].i_ref }; + int i_ref8s = ( ref8[0] == ref8[1] ) ? 1 : 2; + lX->me16x8[i].cost = INT_MAX; + for( int j = 0; j < i_ref8s; j++ ) + { + int i_ref = ref8[j]; + m.i_ref_cost = REF_COST( l, i_ref ); + + LOAD_HPELS( &m, h->mb.pic.p_fref[l][i_ref], l, i_ref, 0, 8*i ); + + CP32( mvc[0], lX->mvc[i_ref][0] ); + CP32( mvc[1], lX->mvc[i_ref][2*i+1] ); + CP32( mvc[2], lX->mvc[i_ref][2*i+2] ); + + x264_macroblock_cache_ref( h, 0, 2*i, 4, 2, l, i_ref ); + x264_mb_predict_mv( h, l, 8*i, 4, m.mvp ); + x264_me_search( h, &m, mvc, 3 ); + m.cost += m.i_ref_cost; + + if( m.cost < lX->me16x8[i].cost ) + h->mc.memcpy_aligned( &lX->me16x8[i], &m, sizeof(x264_me_t) ); + } + } + + /* BI mode */ + src[0] = h->mc.get_ref( pix[0], &stride[0], a->l0.me16x8[i].p_fref, a->l0.me16x8[i].i_stride[0], + a->l0.me16x8[i].mv[0], a->l0.me16x8[i].mv[1], 16, 8, x264_weight_none ); + src[1] = h->mc.get_ref( pix[1], &stride[1], a->l1.me16x8[i].p_fref, a->l1.me16x8[i].i_stride[0], + a->l1.me16x8[i].mv[0], a->l1.me16x8[i].mv[1], 16, 8, x264_weight_none ); + h->mc.avg[PIXEL_16x8]( pix[0], 16, src[0], stride[0], src[1], stride[1], + h->mb.bipred_weight[a->l0.me16x8[i].i_ref][a->l1.me16x8[i].i_ref] ); + + i_part_cost_bi = h->pixf.mbcmp[PIXEL_16x8]( a->l0.me16x8[i].p_fenc[0], FENC_STRIDE, pix[0], 16 ) + + a->l0.me16x8[i].cost_mv + a->l1.me16x8[i].cost_mv + a->l0.me16x8[i].i_ref_cost + + a->l1.me16x8[i].i_ref_cost; + + if( h->mb.b_chroma_me ) + i_part_cost_bi += x264_analyse_bi_chroma( h, a, i, PIXEL_16x8 ); + + i_part_cost = a->l0.me16x8[i].cost; + a->i_mb_partition16x8[i] = D_L0_8x8; /* not actually 8x8, only the L0 matters */ + + if( a->l1.me16x8[i].cost < i_part_cost ) + { + i_part_cost = a->l1.me16x8[i].cost; + a->i_mb_partition16x8[i] = D_L1_8x8; + } + if( i_part_cost_bi + a->i_lambda * 1 < i_part_cost ) + { + i_part_cost = i_part_cost_bi; + a->i_mb_partition16x8[i] = D_BI_8x8; + } + a->i_cost16x8bi += i_part_cost; + + /* Early termination based on the current SATD score of partition[0] + plus the estimated SATD score of partition[1] */ + if( a->b_early_terminate && (!i && i_part_cost + a->i_cost_est16x8[1] > i_best_satd + * (16 + (!!a->i_mbrd + !!h->mb.i_psy_rd))/16) ) + { + a->i_cost16x8bi = COST_MAX; + return; + } + + x264_mb_cache_mv_b16x8( h, a, i, 0 ); + } + + /* mb type cost */ + a->i_mb_type16x8 = B_L0_L0 + + (a->i_mb_partition16x8[0]>>2) * 3 + + (a->i_mb_partition16x8[1]>>2); + a->i_cost16x8bi += a->i_lambda * i_mb_b16x8_cost_table[a->i_mb_type16x8]; +} + +static void x264_mb_analyse_inter_b8x16( x264_t *h, x264_mb_analysis_t *a, int i_best_satd ) +{ + ALIGNED_ARRAY_16( pixel, pix,[2],[8*16] ); + ALIGNED_4( int16_t mvc[3][2] ); + + h->mb.i_partition = D_8x16; + a->i_cost8x16bi = 0; + + for( int i = 0; i < 2; i++ ) + { + int i_part_cost; + int i_part_cost_bi = 0; + intptr_t stride[2] = {8,8}; + pixel *src[2]; + x264_me_t m; + m.i_pixel = PIXEL_8x16; + LOAD_FENC( &m, h->mb.pic.p_fenc, 8*i, 0 ); + + for( int l = 0; l < 2; l++ ) + { + x264_mb_analysis_list_t *lX = l ? &a->l1 : &a->l0; + int ref8[2] = { lX->me8x8[i].i_ref, lX->me8x8[i+2].i_ref }; + int i_ref8s = ( ref8[0] == ref8[1] ) ? 1 : 2; + lX->me8x16[i].cost = INT_MAX; + for( int j = 0; j < i_ref8s; j++ ) + { + int i_ref = ref8[j]; + m.i_ref_cost = REF_COST( l, i_ref ); + + LOAD_HPELS( &m, h->mb.pic.p_fref[l][i_ref], l, i_ref, 8*i, 0 ); + + CP32( mvc[0], lX->mvc[i_ref][0] ); + CP32( mvc[1], lX->mvc[i_ref][i+1] ); + CP32( mvc[2], lX->mvc[i_ref][i+3] ); + + x264_macroblock_cache_ref( h, 2*i, 0, 2, 4, l, i_ref ); + x264_mb_predict_mv( h, l, 4*i, 2, m.mvp ); + x264_me_search( h, &m, mvc, 3 ); + m.cost += m.i_ref_cost; + + if( m.cost < lX->me8x16[i].cost ) + h->mc.memcpy_aligned( &lX->me8x16[i], &m, sizeof(x264_me_t) ); + } + } + + /* BI mode */ + src[0] = h->mc.get_ref( pix[0], &stride[0], a->l0.me8x16[i].p_fref, a->l0.me8x16[i].i_stride[0], + a->l0.me8x16[i].mv[0], a->l0.me8x16[i].mv[1], 8, 16, x264_weight_none ); + src[1] = h->mc.get_ref( pix[1], &stride[1], a->l1.me8x16[i].p_fref, a->l1.me8x16[i].i_stride[0], + a->l1.me8x16[i].mv[0], a->l1.me8x16[i].mv[1], 8, 16, x264_weight_none ); + h->mc.avg[PIXEL_8x16]( pix[0], 8, src[0], stride[0], src[1], stride[1], h->mb.bipred_weight[a->l0.me8x16[i].i_ref][a->l1.me8x16[i].i_ref] ); + + i_part_cost_bi = h->pixf.mbcmp[PIXEL_8x16]( a->l0.me8x16[i].p_fenc[0], FENC_STRIDE, pix[0], 8 ) + + a->l0.me8x16[i].cost_mv + a->l1.me8x16[i].cost_mv + a->l0.me8x16[i].i_ref_cost + + a->l1.me8x16[i].i_ref_cost; + + if( h->mb.b_chroma_me ) + i_part_cost_bi += x264_analyse_bi_chroma( h, a, i, PIXEL_8x16 ); + + i_part_cost = a->l0.me8x16[i].cost; + a->i_mb_partition8x16[i] = D_L0_8x8; + + if( a->l1.me8x16[i].cost < i_part_cost ) + { + i_part_cost = a->l1.me8x16[i].cost; + a->i_mb_partition8x16[i] = D_L1_8x8; + } + if( i_part_cost_bi + a->i_lambda * 1 < i_part_cost ) + { + i_part_cost = i_part_cost_bi; + a->i_mb_partition8x16[i] = D_BI_8x8; + } + a->i_cost8x16bi += i_part_cost; + + /* Early termination based on the current SATD score of partition[0] + plus the estimated SATD score of partition[1] */ + if( a->b_early_terminate && (!i && i_part_cost + a->i_cost_est8x16[1] > i_best_satd + * (16 + (!!a->i_mbrd + !!h->mb.i_psy_rd))/16) ) + { + a->i_cost8x16bi = COST_MAX; + return; + } + + x264_mb_cache_mv_b8x16( h, a, i, 0 ); + } + + /* mb type cost */ + a->i_mb_type8x16 = B_L0_L0 + + (a->i_mb_partition8x16[0]>>2) * 3 + + (a->i_mb_partition8x16[1]>>2); + a->i_cost8x16bi += a->i_lambda * i_mb_b16x8_cost_table[a->i_mb_type8x16]; +} + +static void x264_mb_analyse_p_rd( x264_t *h, x264_mb_analysis_t *a, int i_satd ) +{ + int thresh = a->b_early_terminate ? i_satd * 5/4 + 1 : COST_MAX; + + h->mb.i_type = P_L0; + if( a->l0.i_rd16x16 == COST_MAX && (!a->b_early_terminate || a->l0.me16x16.cost <= i_satd * 3/2) ) + { + h->mb.i_partition = D_16x16; + x264_analyse_update_cache( h, a ); + a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 ); + } + + if( a->l0.i_cost16x8 < thresh ) + { + h->mb.i_partition = D_16x8; + x264_analyse_update_cache( h, a ); + a->l0.i_cost16x8 = x264_rd_cost_mb( h, a->i_lambda2 ); + } + else + a->l0.i_cost16x8 = COST_MAX; + + if( a->l0.i_cost8x16 < thresh ) + { + h->mb.i_partition = D_8x16; + x264_analyse_update_cache( h, a ); + a->l0.i_cost8x16 = x264_rd_cost_mb( h, a->i_lambda2 ); + } + else + a->l0.i_cost8x16 = COST_MAX; + + if( a->l0.i_cost8x8 < thresh ) + { + h->mb.i_type = P_8x8; + h->mb.i_partition = D_8x8; + if( h->param.analyse.inter & X264_ANALYSE_PSUB8x8 ) + { + x264_macroblock_cache_ref( h, 0, 0, 2, 2, 0, a->l0.me8x8[0].i_ref ); + x264_macroblock_cache_ref( h, 2, 0, 2, 2, 0, a->l0.me8x8[1].i_ref ); + x264_macroblock_cache_ref( h, 0, 2, 2, 2, 0, a->l0.me8x8[2].i_ref ); + x264_macroblock_cache_ref( h, 2, 2, 2, 2, 0, a->l0.me8x8[3].i_ref ); + /* FIXME: In the 8x8 blocks where RDO isn't run, the NNZ values used for context selection + * for future blocks are those left over from previous RDO calls. */ + for( int i = 0; i < 4; i++ ) + { + int costs[4] = {a->l0.i_cost4x4[i], a->l0.i_cost8x4[i], a->l0.i_cost4x8[i], a->l0.me8x8[i].cost}; + int sub8x8_thresh = a->b_early_terminate ? X264_MIN4( costs[0], costs[1], costs[2], costs[3] ) * 5 / 4 : COST_MAX; + int subtype, btype = D_L0_8x8; + uint64_t bcost = COST_MAX64; + for( subtype = D_L0_4x4; subtype <= D_L0_8x8; subtype++ ) + { + uint64_t cost; + if( costs[subtype] > sub8x8_thresh ) + continue; + h->mb.i_sub_partition[i] = subtype; + x264_mb_cache_mv_p8x8( h, a, i ); + if( subtype == btype ) + continue; + cost = x264_rd_cost_part( h, a->i_lambda2, i<<2, PIXEL_8x8 ); + COPY2_IF_LT( bcost, cost, btype, subtype ); + } + if( h->mb.i_sub_partition[i] != btype ) + { + h->mb.i_sub_partition[i] = btype; + x264_mb_cache_mv_p8x8( h, a, i ); + } + } + } + else + x264_analyse_update_cache( h, a ); + a->l0.i_cost8x8 = x264_rd_cost_mb( h, a->i_lambda2 ); + } + else + a->l0.i_cost8x8 = COST_MAX; +} + +static void x264_mb_analyse_b_rd( x264_t *h, x264_mb_analysis_t *a, int i_satd_inter ) +{ + int thresh = a->b_early_terminate ? i_satd_inter * (17 + (!!h->mb.i_psy_rd))/16 + 1 : COST_MAX; + + if( a->b_direct_available && a->i_rd16x16direct == COST_MAX ) + { + h->mb.i_type = B_DIRECT; + /* Assumes direct/skip MC is still in fdec */ + /* Requires b-rdo to be done before intra analysis */ + h->mb.b_skip_mc = 1; + x264_analyse_update_cache( h, a ); + a->i_rd16x16direct = x264_rd_cost_mb( h, a->i_lambda2 ); + h->mb.b_skip_mc = 0; + } + + //FIXME not all the update_cache calls are needed + h->mb.i_partition = D_16x16; + /* L0 */ + if( a->l0.me16x16.cost < thresh && a->l0.i_rd16x16 == COST_MAX ) + { + h->mb.i_type = B_L0_L0; + x264_analyse_update_cache( h, a ); + a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 ); + } + + /* L1 */ + if( a->l1.me16x16.cost < thresh && a->l1.i_rd16x16 == COST_MAX ) + { + h->mb.i_type = B_L1_L1; + x264_analyse_update_cache( h, a ); + a->l1.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 ); + } + + /* BI */ + if( a->i_cost16x16bi < thresh && a->i_rd16x16bi == COST_MAX ) + { + h->mb.i_type = B_BI_BI; + x264_analyse_update_cache( h, a ); + a->i_rd16x16bi = x264_rd_cost_mb( h, a->i_lambda2 ); + } + + /* 8x8 */ + if( a->i_cost8x8bi < thresh && a->i_rd8x8bi == COST_MAX ) + { + h->mb.i_type = B_8x8; + h->mb.i_partition = D_8x8; + x264_analyse_update_cache( h, a ); + a->i_rd8x8bi = x264_rd_cost_mb( h, a->i_lambda2 ); + x264_macroblock_cache_skip( h, 0, 0, 4, 4, 0 ); + } + + /* 16x8 */ + if( a->i_cost16x8bi < thresh && a->i_rd16x8bi == COST_MAX ) + { + h->mb.i_type = a->i_mb_type16x8; + h->mb.i_partition = D_16x8; + x264_analyse_update_cache( h, a ); + a->i_rd16x8bi = x264_rd_cost_mb( h, a->i_lambda2 ); + } + + /* 8x16 */ + if( a->i_cost8x16bi < thresh && a->i_rd8x16bi == COST_MAX ) + { + h->mb.i_type = a->i_mb_type8x16; + h->mb.i_partition = D_8x16; + x264_analyse_update_cache( h, a ); + a->i_rd8x16bi = x264_rd_cost_mb( h, a->i_lambda2 ); + } +} + +static void x264_refine_bidir( x264_t *h, x264_mb_analysis_t *a ) +{ + int i_biweight; + + if( IS_INTRA(h->mb.i_type) ) + return; + + switch( h->mb.i_partition ) + { + case D_16x16: + if( h->mb.i_type == B_BI_BI ) + { + i_biweight = h->mb.bipred_weight[a->l0.bi16x16.i_ref][a->l1.bi16x16.i_ref]; + x264_me_refine_bidir_satd( h, &a->l0.bi16x16, &a->l1.bi16x16, i_biweight ); + } + break; + case D_16x8: + for( int i = 0; i < 2; i++ ) + if( a->i_mb_partition16x8[i] == D_BI_8x8 ) + { + i_biweight = h->mb.bipred_weight[a->l0.me16x8[i].i_ref][a->l1.me16x8[i].i_ref]; + x264_me_refine_bidir_satd( h, &a->l0.me16x8[i], &a->l1.me16x8[i], i_biweight ); + } + break; + case D_8x16: + for( int i = 0; i < 2; i++ ) + if( a->i_mb_partition8x16[i] == D_BI_8x8 ) + { + i_biweight = h->mb.bipred_weight[a->l0.me8x16[i].i_ref][a->l1.me8x16[i].i_ref]; + x264_me_refine_bidir_satd( h, &a->l0.me8x16[i], &a->l1.me8x16[i], i_biweight ); + } + break; + case D_8x8: + for( int i = 0; i < 4; i++ ) + if( h->mb.i_sub_partition[i] == D_BI_8x8 ) + { + i_biweight = h->mb.bipred_weight[a->l0.me8x8[i].i_ref][a->l1.me8x8[i].i_ref]; + x264_me_refine_bidir_satd( h, &a->l0.me8x8[i], &a->l1.me8x8[i], i_biweight ); + } + break; + } +} + +static inline void x264_mb_analyse_transform( x264_t *h ) +{ + if( x264_mb_transform_8x8_allowed( h ) && h->param.analyse.b_transform_8x8 && !h->mb.b_lossless ) + { + /* Only luma MC is really needed for 4:2:0, but the full MC is re-used in macroblock_encode. */ + x264_mb_mc( h ); + + int plane_count = CHROMA444 && h->mb.b_chroma_me ? 3 : 1; + int i_cost8 = 0, i_cost4 = 0; + /* Not all platforms have a merged SATD function */ + if( h->pixf.sa8d_satd[PIXEL_16x16] ) + { + uint64_t cost = 0; + for( int p = 0; p < plane_count; p++ ) + { + cost += h->pixf.sa8d_satd[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, + h->mb.pic.p_fdec[p], FDEC_STRIDE ); + + } + i_cost8 = (uint32_t)cost; + i_cost4 = (uint32_t)(cost >> 32); + } + else + { + for( int p = 0; p < plane_count; p++ ) + { + i_cost8 += h->pixf.sa8d[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, + h->mb.pic.p_fdec[p], FDEC_STRIDE ); + i_cost4 += h->pixf.satd[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, + h->mb.pic.p_fdec[p], FDEC_STRIDE ); + } + } + + h->mb.b_transform_8x8 = i_cost8 < i_cost4; + h->mb.b_skip_mc = 1; + } +} + +static inline void x264_mb_analyse_transform_rd( x264_t *h, x264_mb_analysis_t *a, int *i_satd, int *i_rd ) +{ + if( h->param.analyse.b_transform_8x8 && h->pps->b_transform_8x8_mode ) + { + uint32_t subpart_bak = M32( h->mb.i_sub_partition ); + /* Try switching the subpartitions to 8x8 so that we can use 8x8 transform mode */ + if( h->mb.i_type == P_8x8 ) + M32( h->mb.i_sub_partition ) = D_L0_8x8*0x01010101; + else if( !x264_transform_allowed[h->mb.i_type] ) + return; + + x264_analyse_update_cache( h, a ); + h->mb.b_transform_8x8 ^= 1; + /* FIXME only luma is needed for 4:2:0, but the score for comparison already includes chroma */ + int i_rd8 = x264_rd_cost_mb( h, a->i_lambda2 ); + + if( *i_rd >= i_rd8 ) + { + if( *i_rd > 0 ) + *i_satd = (int64_t)(*i_satd) * i_rd8 / *i_rd; + *i_rd = i_rd8; + } + else + { + h->mb.b_transform_8x8 ^= 1; + M32( h->mb.i_sub_partition ) = subpart_bak; + } + } +} + +/* Rate-distortion optimal QP selection. + * FIXME: More than half of the benefit of this function seems to be + * in the way it improves the coding of chroma DC (by decimating or + * finding a better way to code a single DC coefficient.) + * There must be a more efficient way to get that portion of the benefit + * without doing full QP-RD, but RD-decimation doesn't seem to do the + * trick. */ +static inline void x264_mb_analyse_qp_rd( x264_t *h, x264_mb_analysis_t *a ) +{ + int bcost, cost, failures, prevcost, origcost; + int orig_qp = h->mb.i_qp, bqp = h->mb.i_qp; + int last_qp_tried = 0; + origcost = bcost = x264_rd_cost_mb( h, a->i_lambda2 ); + int origcbp = h->mb.cbp[h->mb.i_mb_xy]; + + /* If CBP is already zero, don't raise the quantizer any higher. */ + for( int direction = origcbp ? 1 : -1; direction >= -1; direction-=2 ) + { + /* Without psy-RD, require monotonicity when moving quant away from previous + * macroblock's quant; allow 1 failure when moving quant towards previous quant. + * With psy-RD, allow 1 failure when moving quant away from previous quant, + * allow 2 failures when moving quant towards previous quant. + * Psy-RD generally seems to result in more chaotic RD score-vs-quantizer curves. */ + int threshold = (!!h->mb.i_psy_rd); + /* Raise the threshold for failures if we're moving towards the last QP. */ + if( ( h->mb.i_last_qp < orig_qp && direction == -1 ) || + ( h->mb.i_last_qp > orig_qp && direction == 1 ) ) + threshold++; + h->mb.i_qp = orig_qp; + failures = 0; + prevcost = origcost; + + /* If the current QP results in an empty CBP, it's highly likely that lower QPs + * (up to a point) will too. So, jump down to where the threshold will kick in + * and check the QP there. If the CBP is still empty, skip the main loop. + * If it isn't empty, we would have ended up having to check this QP anyways, + * so as long as we store it for later lookup, we lose nothing. */ + int already_checked_qp = -1; + int already_checked_cost = COST_MAX; + if( direction == -1 ) + { + if( !origcbp ) + { + h->mb.i_qp = X264_MAX( h->mb.i_qp - threshold - 1, SPEC_QP( h->param.rc.i_qp_min ) ); + h->mb.i_chroma_qp = h->chroma_qp_table[h->mb.i_qp]; + already_checked_cost = x264_rd_cost_mb( h, a->i_lambda2 ); + if( !h->mb.cbp[h->mb.i_mb_xy] ) + { + /* If our empty-CBP block is lower QP than the last QP, + * the last QP almost surely doesn't have a CBP either. */ + if( h->mb.i_last_qp > h->mb.i_qp ) + last_qp_tried = 1; + break; + } + already_checked_qp = h->mb.i_qp; + h->mb.i_qp = orig_qp; + } + } + + h->mb.i_qp += direction; + while( h->mb.i_qp >= h->param.rc.i_qp_min && h->mb.i_qp <= SPEC_QP( h->param.rc.i_qp_max ) ) + { + if( h->mb.i_last_qp == h->mb.i_qp ) + last_qp_tried = 1; + if( h->mb.i_qp == already_checked_qp ) + cost = already_checked_cost; + else + { + h->mb.i_chroma_qp = h->chroma_qp_table[h->mb.i_qp]; + cost = x264_rd_cost_mb( h, a->i_lambda2 ); + COPY2_IF_LT( bcost, cost, bqp, h->mb.i_qp ); + } + + /* We can't assume that the costs are monotonic over QPs. + * Tie case-as-failure seems to give better results. */ + if( cost < prevcost ) + failures = 0; + else + failures++; + prevcost = cost; + + if( failures > threshold ) + break; + if( direction == 1 && !h->mb.cbp[h->mb.i_mb_xy] ) + break; + h->mb.i_qp += direction; + } + } + + /* Always try the last block's QP. */ + if( !last_qp_tried ) + { + h->mb.i_qp = h->mb.i_last_qp; + h->mb.i_chroma_qp = h->chroma_qp_table[h->mb.i_qp]; + cost = x264_rd_cost_mb( h, a->i_lambda2 ); + COPY2_IF_LT( bcost, cost, bqp, h->mb.i_qp ); + } + + h->mb.i_qp = bqp; + h->mb.i_chroma_qp = h->chroma_qp_table[h->mb.i_qp]; + + /* Check transform again; decision from before may no longer be optimal. */ + if( h->mb.i_qp != orig_qp && h->param.analyse.b_transform_8x8 && + x264_mb_transform_8x8_allowed( h ) ) + { + h->mb.b_transform_8x8 ^= 1; + cost = x264_rd_cost_mb( h, a->i_lambda2 ); + if( cost > bcost ) + h->mb.b_transform_8x8 ^= 1; + } +} + +/***************************************************************************** + * x264_macroblock_analyse: + *****************************************************************************/ +void x264_macroblock_analyse( x264_t *h ) +{ + x264_mb_analysis_t analysis; + int i_cost = COST_MAX; + + h->mb.i_qp = x264_ratecontrol_mb_qp( h ); + /* If the QP of this MB is within 1 of the previous MB, code the same QP as the previous MB, + * to lower the bit cost of the qp_delta. Don't do this if QPRD is enabled. */ + if( h->param.rc.i_aq_mode && h->param.analyse.i_subpel_refine < 10 ) + h->mb.i_qp = abs(h->mb.i_qp - h->mb.i_last_qp) == 1 ? h->mb.i_last_qp : h->mb.i_qp; + + if( h->param.analyse.b_mb_info ) + h->fdec->effective_qp[h->mb.i_mb_xy] = h->mb.i_qp; /* Store the real analysis QP. */ + x264_mb_analyse_init( h, &analysis, h->mb.i_qp ); + + /*--------------------------- Do the analysis ---------------------------*/ + if( h->sh.i_type == SLICE_TYPE_I ) + { +intra_analysis: + if( analysis.i_mbrd ) + x264_mb_init_fenc_cache( h, analysis.i_mbrd >= 2 ); + x264_mb_analyse_intra( h, &analysis, COST_MAX ); + if( analysis.i_mbrd ) + x264_intra_rd( h, &analysis, COST_MAX ); + + i_cost = analysis.i_satd_i16x16; + h->mb.i_type = I_16x16; + COPY2_IF_LT( i_cost, analysis.i_satd_i4x4, h->mb.i_type, I_4x4 ); + COPY2_IF_LT( i_cost, analysis.i_satd_i8x8, h->mb.i_type, I_8x8 ); + if( analysis.i_satd_pcm < i_cost ) + h->mb.i_type = I_PCM; + + else if( analysis.i_mbrd >= 2 ) + x264_intra_rd_refine( h, &analysis ); + } + else if( h->sh.i_type == SLICE_TYPE_P ) + { + int b_skip = 0; + + h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 0 ); + + analysis.b_try_skip = 0; + if( analysis.b_force_intra ) + { + if( !h->param.analyse.b_psy ) + { + x264_mb_analyse_init_qp( h, &analysis, X264_MAX( h->mb.i_qp - h->mb.ip_offset, h->param.rc.i_qp_min ) ); + goto intra_analysis; + } + } + else + { + /* Special fast-skip logic using information from mb_info. */ + if( h->fdec->mb_info && (h->fdec->mb_info[h->mb.i_mb_xy]&X264_MBINFO_CONSTANT) ) + { + if( !SLICE_MBAFF && (h->fdec->i_frame - h->fref[0][0]->i_frame) == 1 && !h->sh.b_weighted_pred && + h->fref[0][0]->effective_qp[h->mb.i_mb_xy] <= h->mb.i_qp ) + { + h->mb.i_partition = D_16x16; + /* Use the P-SKIP MV if we can... */ + if( !M32(h->mb.cache.pskip_mv) ) + { + b_skip = 1; + h->mb.i_type = P_SKIP; + } + /* Otherwise, just force a 16x16 block. */ + else + { + h->mb.i_type = P_L0; + analysis.l0.me16x16.i_ref = 0; + M32( analysis.l0.me16x16.mv ) = 0; + } + goto skip_analysis; + } + /* Reset the information accordingly */ + else if( h->param.analyse.b_mb_info_update ) + h->fdec->mb_info[h->mb.i_mb_xy] &= ~X264_MBINFO_CONSTANT; + } + + int skip_invalid = h->i_thread_frames > 1 && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1]; + /* If the current macroblock is off the frame, just skip it. */ + if( HAVE_INTERLACED && !MB_INTERLACED && h->mb.i_mb_y * 16 >= h->param.i_height && !skip_invalid ) + b_skip = 1; + /* Fast P_SKIP detection */ + else if( h->param.analyse.b_fast_pskip ) + { + if( skip_invalid ) + // FIXME don't need to check this if the reference frame is done + {} + else if( h->param.analyse.i_subpel_refine >= 3 ) + analysis.b_try_skip = 1; + else if( h->mb.i_mb_type_left[0] == P_SKIP || + h->mb.i_mb_type_top == P_SKIP || + h->mb.i_mb_type_topleft == P_SKIP || + h->mb.i_mb_type_topright == P_SKIP ) + b_skip = x264_macroblock_probe_pskip( h ); + } + } + + h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 1 ); + + if( b_skip ) + { + h->mb.i_type = P_SKIP; + h->mb.i_partition = D_16x16; + assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->i_thread_frames == 1 ); +skip_analysis: + /* Set up MVs for future predictors */ + for( int i = 0; i < h->mb.pic.i_fref[0]; i++ ) + M32( h->mb.mvr[0][i][h->mb.i_mb_xy] ) = 0; + } + else + { + const unsigned int flags = h->param.analyse.inter; + int i_type; + int i_partition; + int i_satd_inter, i_satd_intra; + + x264_mb_analyse_load_costs( h, &analysis ); + + x264_mb_analyse_inter_p16x16( h, &analysis ); + + if( h->mb.i_type == P_SKIP ) + { + for( int i = 1; i < h->mb.pic.i_fref[0]; i++ ) + M32( h->mb.mvr[0][i][h->mb.i_mb_xy] ) = 0; + return; + } + + if( flags & X264_ANALYSE_PSUB16x16 ) + { + if( h->param.analyse.b_mixed_references ) + x264_mb_analyse_inter_p8x8_mixed_ref( h, &analysis ); + else + x264_mb_analyse_inter_p8x8( h, &analysis ); + } + + /* Select best inter mode */ + i_type = P_L0; + i_partition = D_16x16; + i_cost = analysis.l0.me16x16.cost; + + if( ( flags & X264_ANALYSE_PSUB16x16 ) && (!analysis.b_early_terminate || + analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost) ) + { + i_type = P_8x8; + i_partition = D_8x8; + i_cost = analysis.l0.i_cost8x8; + + /* Do sub 8x8 */ + if( flags & X264_ANALYSE_PSUB8x8 ) + { + for( int i = 0; i < 4; i++ ) + { + x264_mb_analyse_inter_p4x4( h, &analysis, i ); + int i_thresh8x4 = analysis.l0.me4x4[i][1].cost_mv + analysis.l0.me4x4[i][2].cost_mv; + if( !analysis.b_early_terminate || analysis.l0.i_cost4x4[i] < analysis.l0.me8x8[i].cost + i_thresh8x4 ) + { + int i_cost8x8 = analysis.l0.i_cost4x4[i]; + h->mb.i_sub_partition[i] = D_L0_4x4; + + x264_mb_analyse_inter_p8x4( h, &analysis, i ); + COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost8x4[i], + h->mb.i_sub_partition[i], D_L0_8x4 ); + + x264_mb_analyse_inter_p4x8( h, &analysis, i ); + COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost4x8[i], + h->mb.i_sub_partition[i], D_L0_4x8 ); + + i_cost += i_cost8x8 - analysis.l0.me8x8[i].cost; + } + x264_mb_cache_mv_p8x8( h, &analysis, i ); + } + analysis.l0.i_cost8x8 = i_cost; + } + } + + /* Now do 16x8/8x16 */ + int i_thresh16x8 = analysis.l0.me8x8[1].cost_mv + analysis.l0.me8x8[2].cost_mv; + if( ( flags & X264_ANALYSE_PSUB16x16 ) && (!analysis.b_early_terminate || + analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost + i_thresh16x8) ) + { + int i_avg_mv_ref_cost = (analysis.l0.me8x8[2].cost_mv + analysis.l0.me8x8[2].i_ref_cost + + analysis.l0.me8x8[3].cost_mv + analysis.l0.me8x8[3].i_ref_cost + 1) >> 1; + analysis.i_cost_est16x8[1] = analysis.i_satd8x8[0][2] + analysis.i_satd8x8[0][3] + i_avg_mv_ref_cost; + + x264_mb_analyse_inter_p16x8( h, &analysis, i_cost ); + COPY3_IF_LT( i_cost, analysis.l0.i_cost16x8, i_type, P_L0, i_partition, D_16x8 ); + + i_avg_mv_ref_cost = (analysis.l0.me8x8[1].cost_mv + analysis.l0.me8x8[1].i_ref_cost + + analysis.l0.me8x8[3].cost_mv + analysis.l0.me8x8[3].i_ref_cost + 1) >> 1; + analysis.i_cost_est8x16[1] = analysis.i_satd8x8[0][1] + analysis.i_satd8x8[0][3] + i_avg_mv_ref_cost; + + x264_mb_analyse_inter_p8x16( h, &analysis, i_cost ); + COPY3_IF_LT( i_cost, analysis.l0.i_cost8x16, i_type, P_L0, i_partition, D_8x16 ); + } + + h->mb.i_partition = i_partition; + + /* refine qpel */ + //FIXME mb_type costs? + if( analysis.i_mbrd || !h->mb.i_subpel_refine ) + { + /* refine later */ + } + else if( i_partition == D_16x16 ) + { + x264_me_refine_qpel( h, &analysis.l0.me16x16 ); + i_cost = analysis.l0.me16x16.cost; + } + else if( i_partition == D_16x8 ) + { + x264_me_refine_qpel( h, &analysis.l0.me16x8[0] ); + x264_me_refine_qpel( h, &analysis.l0.me16x8[1] ); + i_cost = analysis.l0.me16x8[0].cost + analysis.l0.me16x8[1].cost; + } + else if( i_partition == D_8x16 ) + { + x264_me_refine_qpel( h, &analysis.l0.me8x16[0] ); + x264_me_refine_qpel( h, &analysis.l0.me8x16[1] ); + i_cost = analysis.l0.me8x16[0].cost + analysis.l0.me8x16[1].cost; + } + else if( i_partition == D_8x8 ) + { + i_cost = 0; + for( int i8x8 = 0; i8x8 < 4; i8x8++ ) + { + switch( h->mb.i_sub_partition[i8x8] ) + { + case D_L0_8x8: + x264_me_refine_qpel( h, &analysis.l0.me8x8[i8x8] ); + i_cost += analysis.l0.me8x8[i8x8].cost; + break; + case D_L0_8x4: + x264_me_refine_qpel( h, &analysis.l0.me8x4[i8x8][0] ); + x264_me_refine_qpel( h, &analysis.l0.me8x4[i8x8][1] ); + i_cost += analysis.l0.me8x4[i8x8][0].cost + + analysis.l0.me8x4[i8x8][1].cost; + break; + case D_L0_4x8: + x264_me_refine_qpel( h, &analysis.l0.me4x8[i8x8][0] ); + x264_me_refine_qpel( h, &analysis.l0.me4x8[i8x8][1] ); + i_cost += analysis.l0.me4x8[i8x8][0].cost + + analysis.l0.me4x8[i8x8][1].cost; + break; + + case D_L0_4x4: + x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][0] ); + x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][1] ); + x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][2] ); + x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][3] ); + i_cost += analysis.l0.me4x4[i8x8][0].cost + + analysis.l0.me4x4[i8x8][1].cost + + analysis.l0.me4x4[i8x8][2].cost + + analysis.l0.me4x4[i8x8][3].cost; + break; + default: + x264_log( h, X264_LOG_ERROR, "internal error (!8x8 && !4x4)\n" ); + break; + } + } + } + + if( h->mb.b_chroma_me ) + { + if( CHROMA444 ) + { + x264_mb_analyse_intra( h, &analysis, i_cost ); + x264_mb_analyse_intra_chroma( h, &analysis ); + } + else + { + x264_mb_analyse_intra_chroma( h, &analysis ); + x264_mb_analyse_intra( h, &analysis, i_cost - analysis.i_satd_chroma ); + } + analysis.i_satd_i16x16 += analysis.i_satd_chroma; + analysis.i_satd_i8x8 += analysis.i_satd_chroma; + analysis.i_satd_i4x4 += analysis.i_satd_chroma; + } + else + x264_mb_analyse_intra( h, &analysis, i_cost ); + + i_satd_inter = i_cost; + i_satd_intra = X264_MIN3( analysis.i_satd_i16x16, + analysis.i_satd_i8x8, + analysis.i_satd_i4x4 ); + + if( analysis.i_mbrd ) + { + x264_mb_analyse_p_rd( h, &analysis, X264_MIN(i_satd_inter, i_satd_intra) ); + i_type = P_L0; + i_partition = D_16x16; + i_cost = analysis.l0.i_rd16x16; + COPY2_IF_LT( i_cost, analysis.l0.i_cost16x8, i_partition, D_16x8 ); + COPY2_IF_LT( i_cost, analysis.l0.i_cost8x16, i_partition, D_8x16 ); + COPY3_IF_LT( i_cost, analysis.l0.i_cost8x8, i_partition, D_8x8, i_type, P_8x8 ); + h->mb.i_type = i_type; + h->mb.i_partition = i_partition; + if( i_cost < COST_MAX ) + x264_mb_analyse_transform_rd( h, &analysis, &i_satd_inter, &i_cost ); + x264_intra_rd( h, &analysis, i_satd_inter * 5/4 + 1 ); + } + + COPY2_IF_LT( i_cost, analysis.i_satd_i16x16, i_type, I_16x16 ); + COPY2_IF_LT( i_cost, analysis.i_satd_i8x8, i_type, I_8x8 ); + COPY2_IF_LT( i_cost, analysis.i_satd_i4x4, i_type, I_4x4 ); + COPY2_IF_LT( i_cost, analysis.i_satd_pcm, i_type, I_PCM ); + + h->mb.i_type = i_type; + + if( analysis.b_force_intra && !IS_INTRA(i_type) ) + { + /* Intra masking: copy fdec to fenc and re-encode the block as intra in order to make it appear as if + * it was an inter block. */ + x264_analyse_update_cache( h, &analysis ); + x264_macroblock_encode( h ); + for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ ) + h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, h->mb.pic.p_fdec[p], FDEC_STRIDE, 16 ); + if( !CHROMA444 ) + { + int height = 16 >> CHROMA_V_SHIFT; + h->mc.copy[PIXEL_8x8] ( h->mb.pic.p_fenc[1], FENC_STRIDE, h->mb.pic.p_fdec[1], FDEC_STRIDE, height ); + h->mc.copy[PIXEL_8x8] ( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE, height ); + } + x264_mb_analyse_init_qp( h, &analysis, X264_MAX( h->mb.i_qp - h->mb.ip_offset, h->param.rc.i_qp_min ) ); + goto intra_analysis; + } + + if( analysis.i_mbrd >= 2 && h->mb.i_type != I_PCM ) + { + if( IS_INTRA( h->mb.i_type ) ) + { + x264_intra_rd_refine( h, &analysis ); + } + else if( i_partition == D_16x16 ) + { + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, analysis.l0.me16x16.i_ref ); + analysis.l0.me16x16.cost = i_cost; + x264_me_refine_qpel_rd( h, &analysis.l0.me16x16, analysis.i_lambda2, 0, 0 ); + } + else if( i_partition == D_16x8 ) + { + M32( h->mb.i_sub_partition ) = D_L0_8x8 * 0x01010101; + x264_macroblock_cache_ref( h, 0, 0, 4, 2, 0, analysis.l0.me16x8[0].i_ref ); + x264_macroblock_cache_ref( h, 0, 2, 4, 2, 0, analysis.l0.me16x8[1].i_ref ); + x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[0], analysis.i_lambda2, 0, 0 ); + x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[1], analysis.i_lambda2, 8, 0 ); + } + else if( i_partition == D_8x16 ) + { + M32( h->mb.i_sub_partition ) = D_L0_8x8 * 0x01010101; + x264_macroblock_cache_ref( h, 0, 0, 2, 4, 0, analysis.l0.me8x16[0].i_ref ); + x264_macroblock_cache_ref( h, 2, 0, 2, 4, 0, analysis.l0.me8x16[1].i_ref ); + x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[0], analysis.i_lambda2, 0, 0 ); + x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[1], analysis.i_lambda2, 4, 0 ); + } + else if( i_partition == D_8x8 ) + { + x264_analyse_update_cache( h, &analysis ); + for( int i8x8 = 0; i8x8 < 4; i8x8++ ) + { + if( h->mb.i_sub_partition[i8x8] == D_L0_8x8 ) + { + x264_me_refine_qpel_rd( h, &analysis.l0.me8x8[i8x8], analysis.i_lambda2, i8x8*4, 0 ); + } + else if( h->mb.i_sub_partition[i8x8] == D_L0_8x4 ) + { + x264_me_refine_qpel_rd( h, &analysis.l0.me8x4[i8x8][0], analysis.i_lambda2, i8x8*4+0, 0 ); + x264_me_refine_qpel_rd( h, &analysis.l0.me8x4[i8x8][1], analysis.i_lambda2, i8x8*4+2, 0 ); + } + else if( h->mb.i_sub_partition[i8x8] == D_L0_4x8 ) + { + x264_me_refine_qpel_rd( h, &analysis.l0.me4x8[i8x8][0], analysis.i_lambda2, i8x8*4+0, 0 ); + x264_me_refine_qpel_rd( h, &analysis.l0.me4x8[i8x8][1], analysis.i_lambda2, i8x8*4+1, 0 ); + } + else if( h->mb.i_sub_partition[i8x8] == D_L0_4x4 ) + { + x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x8][0], analysis.i_lambda2, i8x8*4+0, 0 ); + x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x8][1], analysis.i_lambda2, i8x8*4+1, 0 ); + x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x8][2], analysis.i_lambda2, i8x8*4+2, 0 ); + x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x8][3], analysis.i_lambda2, i8x8*4+3, 0 ); + } + } + } + } + } + } + else if( h->sh.i_type == SLICE_TYPE_B ) + { + int i_bskip_cost = COST_MAX; + int b_skip = 0; + + if( analysis.i_mbrd ) + x264_mb_init_fenc_cache( h, analysis.i_mbrd >= 2 ); + + h->mb.i_type = B_SKIP; + if( h->mb.b_direct_auto_write ) + { + /* direct=auto heuristic: prefer whichever mode allows more Skip macroblocks */ + for( int i = 0; i < 2; i++ ) + { + int b_changed = 1; + h->sh.b_direct_spatial_mv_pred ^= 1; + analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h, i && analysis.b_direct_available ? &b_changed : NULL ); + if( analysis.b_direct_available ) + { + if( b_changed ) + { + x264_mb_mc( h ); + b_skip = x264_macroblock_probe_bskip( h ); + } + h->stat.frame.i_direct_score[ h->sh.b_direct_spatial_mv_pred ] += b_skip; + } + else + b_skip = 0; + } + } + else + analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h, NULL ); + + analysis.b_try_skip = 0; + if( analysis.b_direct_available ) + { + if( !h->mb.b_direct_auto_write ) + x264_mb_mc( h ); + /* If the current macroblock is off the frame, just skip it. */ + if( HAVE_INTERLACED && !MB_INTERLACED && h->mb.i_mb_y * 16 >= h->param.i_height ) + b_skip = 1; + else if( analysis.i_mbrd ) + { + i_bskip_cost = ssd_mb( h ); + /* 6 = minimum cavlc cost of a non-skipped MB */ + b_skip = h->mb.b_skip_mc = i_bskip_cost <= ((6 * analysis.i_lambda2 + 128) >> 8); + } + else if( !h->mb.b_direct_auto_write ) + { + /* Conditioning the probe on neighboring block types + * doesn't seem to help speed or quality. */ + analysis.b_try_skip = x264_macroblock_probe_bskip( h ); + if( h->param.analyse.i_subpel_refine < 3 ) + b_skip = analysis.b_try_skip; + } + /* Set up MVs for future predictors */ + if( b_skip ) + { + for( int i = 0; i < h->mb.pic.i_fref[0]; i++ ) + M32( h->mb.mvr[0][i][h->mb.i_mb_xy] ) = 0; + for( int i = 0; i < h->mb.pic.i_fref[1]; i++ ) + M32( h->mb.mvr[1][i][h->mb.i_mb_xy] ) = 0; + } + } + + if( !b_skip ) + { + const unsigned int flags = h->param.analyse.inter; + int i_type; + int i_partition; + int i_satd_inter; + h->mb.b_skip_mc = 0; + h->mb.i_type = B_DIRECT; + + x264_mb_analyse_load_costs( h, &analysis ); + + /* select best inter mode */ + /* direct must be first */ + if( analysis.b_direct_available ) + x264_mb_analyse_inter_direct( h, &analysis ); + + x264_mb_analyse_inter_b16x16( h, &analysis ); + + if( h->mb.i_type == B_SKIP ) + { + for( int i = 1; i < h->mb.pic.i_fref[0]; i++ ) + M32( h->mb.mvr[0][i][h->mb.i_mb_xy] ) = 0; + for( int i = 1; i < h->mb.pic.i_fref[1]; i++ ) + M32( h->mb.mvr[1][i][h->mb.i_mb_xy] ) = 0; + return; + } + + i_type = B_L0_L0; + i_partition = D_16x16; + i_cost = analysis.l0.me16x16.cost; + COPY2_IF_LT( i_cost, analysis.l1.me16x16.cost, i_type, B_L1_L1 ); + COPY2_IF_LT( i_cost, analysis.i_cost16x16bi, i_type, B_BI_BI ); + COPY2_IF_LT( i_cost, analysis.i_cost16x16direct, i_type, B_DIRECT ); + + if( analysis.i_mbrd && analysis.b_early_terminate && analysis.i_cost16x16direct <= i_cost * 33/32 ) + { + x264_mb_analyse_b_rd( h, &analysis, i_cost ); + if( i_bskip_cost < analysis.i_rd16x16direct && + i_bskip_cost < analysis.i_rd16x16bi && + i_bskip_cost < analysis.l0.i_rd16x16 && + i_bskip_cost < analysis.l1.i_rd16x16 ) + { + h->mb.i_type = B_SKIP; + x264_analyse_update_cache( h, &analysis ); + return; + } + } + + if( flags & X264_ANALYSE_BSUB16x16 ) + { + if( h->param.analyse.b_mixed_references ) + x264_mb_analyse_inter_b8x8_mixed_ref( h, &analysis ); + else + x264_mb_analyse_inter_b8x8( h, &analysis ); + + COPY3_IF_LT( i_cost, analysis.i_cost8x8bi, i_type, B_8x8, i_partition, D_8x8 ); + + /* Try to estimate the cost of b16x8/b8x16 based on the satd scores of the b8x8 modes */ + int i_cost_est16x8bi_total = 0, i_cost_est8x16bi_total = 0; + int i_mb_type, i_partition16x8[2], i_partition8x16[2]; + for( int i = 0; i < 2; i++ ) + { + int avg_l0_mv_ref_cost, avg_l1_mv_ref_cost; + int i_l0_satd, i_l1_satd, i_bi_satd, i_best_cost; + // 16x8 + i_best_cost = COST_MAX; + i_l0_satd = analysis.i_satd8x8[0][i*2] + analysis.i_satd8x8[0][i*2+1]; + i_l1_satd = analysis.i_satd8x8[1][i*2] + analysis.i_satd8x8[1][i*2+1]; + i_bi_satd = analysis.i_satd8x8[2][i*2] + analysis.i_satd8x8[2][i*2+1]; + avg_l0_mv_ref_cost = ( analysis.l0.me8x8[i*2].cost_mv + analysis.l0.me8x8[i*2].i_ref_cost + + analysis.l0.me8x8[i*2+1].cost_mv + analysis.l0.me8x8[i*2+1].i_ref_cost + 1 ) >> 1; + avg_l1_mv_ref_cost = ( analysis.l1.me8x8[i*2].cost_mv + analysis.l1.me8x8[i*2].i_ref_cost + + analysis.l1.me8x8[i*2+1].cost_mv + analysis.l1.me8x8[i*2+1].i_ref_cost + 1 ) >> 1; + COPY2_IF_LT( i_best_cost, i_l0_satd + avg_l0_mv_ref_cost, i_partition16x8[i], D_L0_8x8 ); + COPY2_IF_LT( i_best_cost, i_l1_satd + avg_l1_mv_ref_cost, i_partition16x8[i], D_L1_8x8 ); + COPY2_IF_LT( i_best_cost, i_bi_satd + avg_l0_mv_ref_cost + avg_l1_mv_ref_cost, i_partition16x8[i], D_BI_8x8 ); + analysis.i_cost_est16x8[i] = i_best_cost; + + // 8x16 + i_best_cost = COST_MAX; + i_l0_satd = analysis.i_satd8x8[0][i] + analysis.i_satd8x8[0][i+2]; + i_l1_satd = analysis.i_satd8x8[1][i] + analysis.i_satd8x8[1][i+2]; + i_bi_satd = analysis.i_satd8x8[2][i] + analysis.i_satd8x8[2][i+2]; + avg_l0_mv_ref_cost = ( analysis.l0.me8x8[i].cost_mv + analysis.l0.me8x8[i].i_ref_cost + + analysis.l0.me8x8[i+2].cost_mv + analysis.l0.me8x8[i+2].i_ref_cost + 1 ) >> 1; + avg_l1_mv_ref_cost = ( analysis.l1.me8x8[i].cost_mv + analysis.l1.me8x8[i].i_ref_cost + + analysis.l1.me8x8[i+2].cost_mv + analysis.l1.me8x8[i+2].i_ref_cost + 1 ) >> 1; + COPY2_IF_LT( i_best_cost, i_l0_satd + avg_l0_mv_ref_cost, i_partition8x16[i], D_L0_8x8 ); + COPY2_IF_LT( i_best_cost, i_l1_satd + avg_l1_mv_ref_cost, i_partition8x16[i], D_L1_8x8 ); + COPY2_IF_LT( i_best_cost, i_bi_satd + avg_l0_mv_ref_cost + avg_l1_mv_ref_cost, i_partition8x16[i], D_BI_8x8 ); + analysis.i_cost_est8x16[i] = i_best_cost; + } + i_mb_type = B_L0_L0 + (i_partition16x8[0]>>2) * 3 + (i_partition16x8[1]>>2); + analysis.i_cost_est16x8[1] += analysis.i_lambda * i_mb_b16x8_cost_table[i_mb_type]; + i_cost_est16x8bi_total = analysis.i_cost_est16x8[0] + analysis.i_cost_est16x8[1]; + i_mb_type = B_L0_L0 + (i_partition8x16[0]>>2) * 3 + (i_partition8x16[1]>>2); + analysis.i_cost_est8x16[1] += analysis.i_lambda * i_mb_b16x8_cost_table[i_mb_type]; + i_cost_est8x16bi_total = analysis.i_cost_est8x16[0] + analysis.i_cost_est8x16[1]; + + /* We can gain a little speed by checking the mode with the lowest estimated cost first */ + int try_16x8_first = i_cost_est16x8bi_total < i_cost_est8x16bi_total; + if( try_16x8_first && (!analysis.b_early_terminate || i_cost_est16x8bi_total < i_cost) ) + { + x264_mb_analyse_inter_b16x8( h, &analysis, i_cost ); + COPY3_IF_LT( i_cost, analysis.i_cost16x8bi, i_type, analysis.i_mb_type16x8, i_partition, D_16x8 ); + } + if( !analysis.b_early_terminate || i_cost_est8x16bi_total < i_cost ) + { + x264_mb_analyse_inter_b8x16( h, &analysis, i_cost ); + COPY3_IF_LT( i_cost, analysis.i_cost8x16bi, i_type, analysis.i_mb_type8x16, i_partition, D_8x16 ); + } + if( !try_16x8_first && (!analysis.b_early_terminate || i_cost_est16x8bi_total < i_cost) ) + { + x264_mb_analyse_inter_b16x8( h, &analysis, i_cost ); + COPY3_IF_LT( i_cost, analysis.i_cost16x8bi, i_type, analysis.i_mb_type16x8, i_partition, D_16x8 ); + } + } + + if( analysis.i_mbrd || !h->mb.i_subpel_refine ) + { + /* refine later */ + } + /* refine qpel */ + else if( i_partition == D_16x16 ) + { + analysis.l0.me16x16.cost -= analysis.i_lambda * i_mb_b_cost_table[B_L0_L0]; + analysis.l1.me16x16.cost -= analysis.i_lambda * i_mb_b_cost_table[B_L1_L1]; + if( i_type == B_L0_L0 ) + { + x264_me_refine_qpel( h, &analysis.l0.me16x16 ); + i_cost = analysis.l0.me16x16.cost + + analysis.i_lambda * i_mb_b_cost_table[B_L0_L0]; + } + else if( i_type == B_L1_L1 ) + { + x264_me_refine_qpel( h, &analysis.l1.me16x16 ); + i_cost = analysis.l1.me16x16.cost + + analysis.i_lambda * i_mb_b_cost_table[B_L1_L1]; + } + else if( i_type == B_BI_BI ) + { + x264_me_refine_qpel( h, &analysis.l0.bi16x16 ); + x264_me_refine_qpel( h, &analysis.l1.bi16x16 ); + } + } + else if( i_partition == D_16x8 ) + { + for( int i = 0; i < 2; i++ ) + { + if( analysis.i_mb_partition16x8[i] != D_L1_8x8 ) + x264_me_refine_qpel( h, &analysis.l0.me16x8[i] ); + if( analysis.i_mb_partition16x8[i] != D_L0_8x8 ) + x264_me_refine_qpel( h, &analysis.l1.me16x8[i] ); + } + } + else if( i_partition == D_8x16 ) + { + for( int i = 0; i < 2; i++ ) + { + if( analysis.i_mb_partition8x16[i] != D_L1_8x8 ) + x264_me_refine_qpel( h, &analysis.l0.me8x16[i] ); + if( analysis.i_mb_partition8x16[i] != D_L0_8x8 ) + x264_me_refine_qpel( h, &analysis.l1.me8x16[i] ); + } + } + else if( i_partition == D_8x8 ) + { + for( int i = 0; i < 4; i++ ) + { + x264_me_t *m; + int i_part_cost_old; + int i_type_cost; + int i_part_type = h->mb.i_sub_partition[i]; + int b_bidir = (i_part_type == D_BI_8x8); + + if( i_part_type == D_DIRECT_8x8 ) + continue; + if( x264_mb_partition_listX_table[0][i_part_type] ) + { + m = &analysis.l0.me8x8[i]; + i_part_cost_old = m->cost; + i_type_cost = analysis.i_lambda * i_sub_mb_b_cost_table[D_L0_8x8]; + m->cost -= i_type_cost; + x264_me_refine_qpel( h, m ); + if( !b_bidir ) + analysis.i_cost8x8bi += m->cost + i_type_cost - i_part_cost_old; + } + if( x264_mb_partition_listX_table[1][i_part_type] ) + { + m = &analysis.l1.me8x8[i]; + i_part_cost_old = m->cost; + i_type_cost = analysis.i_lambda * i_sub_mb_b_cost_table[D_L1_8x8]; + m->cost -= i_type_cost; + x264_me_refine_qpel( h, m ); + if( !b_bidir ) + analysis.i_cost8x8bi += m->cost + i_type_cost - i_part_cost_old; + } + /* TODO: update mvp? */ + } + } + + i_satd_inter = i_cost; + + if( analysis.i_mbrd ) + { + x264_mb_analyse_b_rd( h, &analysis, i_satd_inter ); + i_type = B_SKIP; + i_cost = i_bskip_cost; + i_partition = D_16x16; + COPY2_IF_LT( i_cost, analysis.l0.i_rd16x16, i_type, B_L0_L0 ); + COPY2_IF_LT( i_cost, analysis.l1.i_rd16x16, i_type, B_L1_L1 ); + COPY2_IF_LT( i_cost, analysis.i_rd16x16bi, i_type, B_BI_BI ); + COPY2_IF_LT( i_cost, analysis.i_rd16x16direct, i_type, B_DIRECT ); + COPY3_IF_LT( i_cost, analysis.i_rd16x8bi, i_type, analysis.i_mb_type16x8, i_partition, D_16x8 ); + COPY3_IF_LT( i_cost, analysis.i_rd8x16bi, i_type, analysis.i_mb_type8x16, i_partition, D_8x16 ); + COPY3_IF_LT( i_cost, analysis.i_rd8x8bi, i_type, B_8x8, i_partition, D_8x8 ); + + h->mb.i_type = i_type; + h->mb.i_partition = i_partition; + } + + if( h->mb.b_chroma_me ) + { + if( CHROMA444 ) + { + x264_mb_analyse_intra( h, &analysis, i_satd_inter ); + x264_mb_analyse_intra_chroma( h, &analysis ); + } + else + { + x264_mb_analyse_intra_chroma( h, &analysis ); + x264_mb_analyse_intra( h, &analysis, i_satd_inter - analysis.i_satd_chroma ); + } + analysis.i_satd_i16x16 += analysis.i_satd_chroma; + analysis.i_satd_i8x8 += analysis.i_satd_chroma; + analysis.i_satd_i4x4 += analysis.i_satd_chroma; + } + else + x264_mb_analyse_intra( h, &analysis, i_satd_inter ); + + if( analysis.i_mbrd ) + { + x264_mb_analyse_transform_rd( h, &analysis, &i_satd_inter, &i_cost ); + x264_intra_rd( h, &analysis, i_satd_inter * 17/16 + 1 ); + } + + COPY2_IF_LT( i_cost, analysis.i_satd_i16x16, i_type, I_16x16 ); + COPY2_IF_LT( i_cost, analysis.i_satd_i8x8, i_type, I_8x8 ); + COPY2_IF_LT( i_cost, analysis.i_satd_i4x4, i_type, I_4x4 ); + COPY2_IF_LT( i_cost, analysis.i_satd_pcm, i_type, I_PCM ); + + h->mb.i_type = i_type; + h->mb.i_partition = i_partition; + + if( analysis.i_mbrd >= 2 && IS_INTRA( i_type ) && i_type != I_PCM ) + x264_intra_rd_refine( h, &analysis ); + if( h->mb.i_subpel_refine >= 5 ) + x264_refine_bidir( h, &analysis ); + + if( analysis.i_mbrd >= 2 && i_type > B_DIRECT && i_type < B_SKIP ) + { + int i_biweight; + x264_analyse_update_cache( h, &analysis ); + + if( i_partition == D_16x16 ) + { + if( i_type == B_L0_L0 ) + { + analysis.l0.me16x16.cost = i_cost; + x264_me_refine_qpel_rd( h, &analysis.l0.me16x16, analysis.i_lambda2, 0, 0 ); + } + else if( i_type == B_L1_L1 ) + { + analysis.l1.me16x16.cost = i_cost; + x264_me_refine_qpel_rd( h, &analysis.l1.me16x16, analysis.i_lambda2, 0, 1 ); + } + else if( i_type == B_BI_BI ) + { + i_biweight = h->mb.bipred_weight[analysis.l0.bi16x16.i_ref][analysis.l1.bi16x16.i_ref]; + x264_me_refine_bidir_rd( h, &analysis.l0.bi16x16, &analysis.l1.bi16x16, i_biweight, 0, analysis.i_lambda2 ); + } + } + else if( i_partition == D_16x8 ) + { + for( int i = 0; i < 2; i++ ) + { + h->mb.i_sub_partition[i*2] = h->mb.i_sub_partition[i*2+1] = analysis.i_mb_partition16x8[i]; + if( analysis.i_mb_partition16x8[i] == D_L0_8x8 ) + x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[i], analysis.i_lambda2, i*8, 0 ); + else if( analysis.i_mb_partition16x8[i] == D_L1_8x8 ) + x264_me_refine_qpel_rd( h, &analysis.l1.me16x8[i], analysis.i_lambda2, i*8, 1 ); + else if( analysis.i_mb_partition16x8[i] == D_BI_8x8 ) + { + i_biweight = h->mb.bipred_weight[analysis.l0.me16x8[i].i_ref][analysis.l1.me16x8[i].i_ref]; + x264_me_refine_bidir_rd( h, &analysis.l0.me16x8[i], &analysis.l1.me16x8[i], i_biweight, i*2, analysis.i_lambda2 ); + } + } + } + else if( i_partition == D_8x16 ) + { + for( int i = 0; i < 2; i++ ) + { + h->mb.i_sub_partition[i] = h->mb.i_sub_partition[i+2] = analysis.i_mb_partition8x16[i]; + if( analysis.i_mb_partition8x16[i] == D_L0_8x8 ) + x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[i], analysis.i_lambda2, i*4, 0 ); + else if( analysis.i_mb_partition8x16[i] == D_L1_8x8 ) + x264_me_refine_qpel_rd( h, &analysis.l1.me8x16[i], analysis.i_lambda2, i*4, 1 ); + else if( analysis.i_mb_partition8x16[i] == D_BI_8x8 ) + { + i_biweight = h->mb.bipred_weight[analysis.l0.me8x16[i].i_ref][analysis.l1.me8x16[i].i_ref]; + x264_me_refine_bidir_rd( h, &analysis.l0.me8x16[i], &analysis.l1.me8x16[i], i_biweight, i, analysis.i_lambda2 ); + } + } + } + else if( i_partition == D_8x8 ) + { + for( int i = 0; i < 4; i++ ) + { + if( h->mb.i_sub_partition[i] == D_L0_8x8 ) + x264_me_refine_qpel_rd( h, &analysis.l0.me8x8[i], analysis.i_lambda2, i*4, 0 ); + else if( h->mb.i_sub_partition[i] == D_L1_8x8 ) + x264_me_refine_qpel_rd( h, &analysis.l1.me8x8[i], analysis.i_lambda2, i*4, 1 ); + else if( h->mb.i_sub_partition[i] == D_BI_8x8 ) + { + i_biweight = h->mb.bipred_weight[analysis.l0.me8x8[i].i_ref][analysis.l1.me8x8[i].i_ref]; + x264_me_refine_bidir_rd( h, &analysis.l0.me8x8[i], &analysis.l1.me8x8[i], i_biweight, i, analysis.i_lambda2 ); + } + } + } + } + } + } + + x264_analyse_update_cache( h, &analysis ); + + /* In rare cases we can end up qpel-RDing our way back to a larger partition size + * without realizing it. Check for this and account for it if necessary. */ + if( analysis.i_mbrd >= 2 ) + { + /* Don't bother with bipred or 8x8-and-below, the odds are incredibly low. */ + static const uint8_t check_mv_lists[X264_MBTYPE_MAX] = {[P_L0]=1, [B_L0_L0]=1, [B_L1_L1]=2}; + int list = check_mv_lists[h->mb.i_type] - 1; + if( list >= 0 && h->mb.i_partition != D_16x16 && + M32( &h->mb.cache.mv[list][x264_scan8[0]] ) == M32( &h->mb.cache.mv[list][x264_scan8[12]] ) && + h->mb.cache.ref[list][x264_scan8[0]] == h->mb.cache.ref[list][x264_scan8[12]] ) + h->mb.i_partition = D_16x16; + } + + if( !analysis.i_mbrd ) + x264_mb_analyse_transform( h ); + + if( analysis.i_mbrd == 3 && !IS_SKIP(h->mb.i_type) ) + x264_mb_analyse_qp_rd( h, &analysis ); + + h->mb.b_trellis = h->param.analyse.i_trellis; + h->mb.b_noise_reduction = h->mb.b_noise_reduction || (!!h->param.analyse.i_noise_reduction && !IS_INTRA( h->mb.i_type )); + + if( !IS_SKIP(h->mb.i_type) && h->mb.i_psy_trellis && h->param.analyse.i_trellis == 1 ) + x264_psy_trellis_init( h, 0 ); + if( h->mb.b_trellis == 1 || h->mb.b_noise_reduction ) + h->mb.i_skip_intra = 0; +} + +/*-------------------- Update MB from the analysis ----------------------*/ +static void x264_analyse_update_cache( x264_t *h, x264_mb_analysis_t *a ) +{ + switch( h->mb.i_type ) + { + case I_4x4: + for( int i = 0; i < 16; i++ ) + h->mb.cache.intra4x4_pred_mode[x264_scan8[i]] = a->i_predict4x4[i]; + + x264_mb_analyse_intra_chroma( h, a ); + break; + case I_8x8: + for( int i = 0; i < 4; i++ ) + x264_macroblock_cache_intra8x8_pred( h, 2*(i&1), 2*(i>>1), a->i_predict8x8[i] ); + + x264_mb_analyse_intra_chroma( h, a ); + break; + case I_16x16: + h->mb.i_intra16x16_pred_mode = a->i_predict16x16; + x264_mb_analyse_intra_chroma( h, a ); + break; + + case I_PCM: + break; + + case P_L0: + switch( h->mb.i_partition ) + { + case D_16x16: + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.me16x16.i_ref ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv ); + break; + + case D_16x8: + x264_macroblock_cache_ref( h, 0, 0, 4, 2, 0, a->l0.me16x8[0].i_ref ); + x264_macroblock_cache_ref( h, 0, 2, 4, 2, 0, a->l0.me16x8[1].i_ref ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 2, 0, a->l0.me16x8[0].mv ); + x264_macroblock_cache_mv_ptr( h, 0, 2, 4, 2, 0, a->l0.me16x8[1].mv ); + break; + + case D_8x16: + x264_macroblock_cache_ref( h, 0, 0, 2, 4, 0, a->l0.me8x16[0].i_ref ); + x264_macroblock_cache_ref( h, 2, 0, 2, 4, 0, a->l0.me8x16[1].i_ref ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 2, 4, 0, a->l0.me8x16[0].mv ); + x264_macroblock_cache_mv_ptr( h, 2, 0, 2, 4, 0, a->l0.me8x16[1].mv ); + break; + + default: + x264_log( h, X264_LOG_ERROR, "internal error P_L0 and partition=%d\n", h->mb.i_partition ); + break; + } + break; + + case P_8x8: + x264_macroblock_cache_ref( h, 0, 0, 2, 2, 0, a->l0.me8x8[0].i_ref ); + x264_macroblock_cache_ref( h, 2, 0, 2, 2, 0, a->l0.me8x8[1].i_ref ); + x264_macroblock_cache_ref( h, 0, 2, 2, 2, 0, a->l0.me8x8[2].i_ref ); + x264_macroblock_cache_ref( h, 2, 2, 2, 2, 0, a->l0.me8x8[3].i_ref ); + for( int i = 0; i < 4; i++ ) + x264_mb_cache_mv_p8x8( h, a, i ); + break; + + case P_SKIP: + { + h->mb.i_partition = D_16x16; + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, 0 ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, h->mb.cache.pskip_mv ); + break; + } + + case B_SKIP: + case B_DIRECT: + h->mb.i_partition = h->mb.cache.direct_partition; + x264_mb_load_mv_direct8x8( h, 0 ); + x264_mb_load_mv_direct8x8( h, 1 ); + x264_mb_load_mv_direct8x8( h, 2 ); + x264_mb_load_mv_direct8x8( h, 3 ); + break; + + case B_8x8: + /* optimize: cache might not need to be rewritten */ + for( int i = 0; i < 4; i++ ) + x264_mb_cache_mv_b8x8( h, a, i, 1 ); + break; + + default: /* the rest of the B types */ + switch( h->mb.i_partition ) + { + case D_16x16: + switch( h->mb.i_type ) + { + case B_L0_L0: + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.me16x16.i_ref ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv ); + + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, -1 ); + x264_macroblock_cache_mv ( h, 0, 0, 4, 4, 1, 0 ); + x264_macroblock_cache_mvd( h, 0, 0, 4, 4, 1, 0 ); + break; + case B_L1_L1: + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, -1 ); + x264_macroblock_cache_mv ( h, 0, 0, 4, 4, 0, 0 ); + x264_macroblock_cache_mvd( h, 0, 0, 4, 4, 0, 0 ); + + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, a->l1.me16x16.i_ref ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 1, a->l1.me16x16.mv ); + break; + case B_BI_BI: + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.bi16x16.i_ref ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.bi16x16.mv ); + + x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, a->l1.bi16x16.i_ref ); + x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 1, a->l1.bi16x16.mv ); + break; + } + break; + case D_16x8: + x264_mb_cache_mv_b16x8( h, a, 0, 1 ); + x264_mb_cache_mv_b16x8( h, a, 1, 1 ); + break; + case D_8x16: + x264_mb_cache_mv_b8x16( h, a, 0, 1 ); + x264_mb_cache_mv_b8x16( h, a, 1, 1 ); + break; + default: + x264_log( h, X264_LOG_ERROR, "internal error (invalid MB type)\n" ); + break; + } + } + +#ifndef NDEBUG + if( h->i_thread_frames > 1 && !IS_INTRA(h->mb.i_type) ) + { + for( int l = 0; l <= (h->sh.i_type == SLICE_TYPE_B); l++ ) + { + int completed; + int ref = h->mb.cache.ref[l][x264_scan8[0]]; + if( ref < 0 ) + continue; + completed = h->fref[l][ ref >> MB_INTERLACED ]->orig->i_lines_completed; + if( (h->mb.cache.mv[l][x264_scan8[15]][1] >> (2 - MB_INTERLACED)) + h->mb.i_mb_y*16 > completed ) + { + x264_log( h, X264_LOG_WARNING, "internal error (MV out of thread range)\n"); + x264_log( h, X264_LOG_DEBUG, "mb type: %d \n", h->mb.i_type); + x264_log( h, X264_LOG_DEBUG, "mv: l%dr%d (%d,%d) \n", l, ref, + h->mb.cache.mv[l][x264_scan8[15]][0], + h->mb.cache.mv[l][x264_scan8[15]][1] ); + x264_log( h, X264_LOG_DEBUG, "limit: %d \n", h->mb.mv_max_spel[1]); + x264_log( h, X264_LOG_DEBUG, "mb_xy: %d,%d \n", h->mb.i_mb_x, h->mb.i_mb_y); + x264_log( h, X264_LOG_DEBUG, "completed: %d \n", completed ); + x264_log( h, X264_LOG_WARNING, "recovering by using intra mode\n"); + x264_mb_analyse_intra( h, a, COST_MAX ); + h->mb.i_type = I_16x16; + h->mb.i_intra16x16_pred_mode = a->i_predict16x16; + x264_mb_analyse_intra_chroma( h, a ); + } + } + } +#endif +} + +#include "slicetype.c" + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/analyse.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/analyse.h new file mode 100644 index 00000000..05e3afb9 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/analyse.h @@ -0,0 +1,44 @@ +/***************************************************************************** + * analyse.h: macroblock analysis + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ANALYSE_H +#define X264_ANALYSE_H + +int x264_analyse_init_costs( x264_t *h ); +void x264_analyse_free_costs( x264_t *h ); +void x264_analyse_weight_frame( x264_t *h, int end ); +void x264_macroblock_analyse( x264_t *h ); +void x264_slicetype_decide( x264_t *h ); + +void x264_slicetype_analyse( x264_t *h, int intra_minigop ); + +int x264_lookahead_init( x264_t *h, int i_slicetype_length ); +int x264_lookahead_is_empty( x264_t *h ); +void x264_lookahead_put_frame( x264_t *h, x264_frame_t *frame ); +void x264_lookahead_get_frames( x264_t *h ); +void x264_lookahead_delete( x264_t *h ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/cabac.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/cabac.c new file mode 100644 index 00000000..9debd1ec --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/cabac.c @@ -0,0 +1,1284 @@ +/***************************************************************************** + * cabac.c: cabac bitstream writing + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "macroblock.h" + +#ifndef RDO_SKIP_BS +#define RDO_SKIP_BS 0 +#endif + +static inline void x264_cabac_mb_type_intra( x264_t *h, x264_cabac_t *cb, int i_mb_type, + int ctx0, int ctx1, int ctx2, int ctx3, int ctx4, int ctx5 ) +{ + if( i_mb_type == I_4x4 || i_mb_type == I_8x8 ) + { + x264_cabac_encode_decision_noup( cb, ctx0, 0 ); + } +#if !RDO_SKIP_BS + else if( i_mb_type == I_PCM ) + { + x264_cabac_encode_decision_noup( cb, ctx0, 1 ); + x264_cabac_encode_flush( h, cb ); + } +#endif + else + { + int i_pred = x264_mb_pred_mode16x16_fix[h->mb.i_intra16x16_pred_mode]; + + x264_cabac_encode_decision_noup( cb, ctx0, 1 ); + x264_cabac_encode_terminal( cb ); + + x264_cabac_encode_decision_noup( cb, ctx1, !!h->mb.i_cbp_luma ); + if( h->mb.i_cbp_chroma == 0 ) + x264_cabac_encode_decision_noup( cb, ctx2, 0 ); + else + { + x264_cabac_encode_decision( cb, ctx2, 1 ); + x264_cabac_encode_decision_noup( cb, ctx3, h->mb.i_cbp_chroma>>1 ); + } + x264_cabac_encode_decision( cb, ctx4, i_pred>>1 ); + x264_cabac_encode_decision_noup( cb, ctx5, i_pred&1 ); + } +} + +#if !RDO_SKIP_BS +static void x264_cabac_field_decoding_flag( x264_t *h, x264_cabac_t *cb ) +{ + int ctx = 0; + ctx += h->mb.field_decoding_flag & !!h->mb.i_mb_x; + ctx += (h->mb.i_mb_top_mbpair_xy >= 0 + && h->mb.slice_table[h->mb.i_mb_top_mbpair_xy] == h->sh.i_first_mb + && h->mb.field[h->mb.i_mb_top_mbpair_xy]); + + x264_cabac_encode_decision_noup( cb, 70 + ctx, MB_INTERLACED ); + h->mb.field_decoding_flag = MB_INTERLACED; +} +#endif + +static void x264_cabac_intra4x4_pred_mode( x264_cabac_t *cb, int i_pred, int i_mode ) +{ + if( i_pred == i_mode ) + x264_cabac_encode_decision( cb, 68, 1 ); + else + { + x264_cabac_encode_decision( cb, 68, 0 ); + if( i_mode > i_pred ) + i_mode--; + x264_cabac_encode_decision( cb, 69, (i_mode )&0x01 ); + x264_cabac_encode_decision( cb, 69, (i_mode >> 1)&0x01 ); + x264_cabac_encode_decision( cb, 69, (i_mode >> 2) ); + } +} + +static void x264_cabac_intra_chroma_pred_mode( x264_t *h, x264_cabac_t *cb ) +{ + int i_mode = x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode]; + int ctx = 0; + + /* No need to test for I4x4 or I_16x16 as cache_save handle that */ + if( (h->mb.i_neighbour & MB_LEFT) && h->mb.chroma_pred_mode[h->mb.i_mb_left_xy[0]] != 0 ) + ctx++; + if( (h->mb.i_neighbour & MB_TOP) && h->mb.chroma_pred_mode[h->mb.i_mb_top_xy] != 0 ) + ctx++; + + x264_cabac_encode_decision_noup( cb, 64 + ctx, i_mode > 0 ); + if( i_mode > 0 ) + { + x264_cabac_encode_decision( cb, 64 + 3, i_mode > 1 ); + if( i_mode > 1 ) + x264_cabac_encode_decision_noup( cb, 64 + 3, i_mode > 2 ); + } +} + +static void x264_cabac_cbp_luma( x264_t *h, x264_cabac_t *cb ) +{ + int cbp = h->mb.i_cbp_luma; + int cbp_l = h->mb.cache.i_cbp_left; + int cbp_t = h->mb.cache.i_cbp_top; + x264_cabac_encode_decision ( cb, 76 - ((cbp_l >> 1) & 1) - ((cbp_t >> 1) & 2), (cbp >> 0) & 1 ); + x264_cabac_encode_decision ( cb, 76 - ((cbp >> 0) & 1) - ((cbp_t >> 2) & 2), (cbp >> 1) & 1 ); + x264_cabac_encode_decision ( cb, 76 - ((cbp_l >> 3) & 1) - ((cbp << 1) & 2), (cbp >> 2) & 1 ); + x264_cabac_encode_decision_noup( cb, 76 - ((cbp >> 2) & 1) - ((cbp >> 0) & 2), (cbp >> 3) & 1 ); +} + +static void x264_cabac_cbp_chroma( x264_t *h, x264_cabac_t *cb ) +{ + int cbp_a = h->mb.cache.i_cbp_left & 0x30; + int cbp_b = h->mb.cache.i_cbp_top & 0x30; + int ctx = 0; + + if( cbp_a && h->mb.cache.i_cbp_left != -1 ) ctx++; + if( cbp_b && h->mb.cache.i_cbp_top != -1 ) ctx+=2; + if( h->mb.i_cbp_chroma == 0 ) + x264_cabac_encode_decision_noup( cb, 77 + ctx, 0 ); + else + { + x264_cabac_encode_decision_noup( cb, 77 + ctx, 1 ); + + ctx = 4; + if( cbp_a == 0x20 ) ctx++; + if( cbp_b == 0x20 ) ctx += 2; + x264_cabac_encode_decision_noup( cb, 77 + ctx, h->mb.i_cbp_chroma >> 1 ); + } +} + +static void x264_cabac_qp_delta( x264_t *h, x264_cabac_t *cb ) +{ + int i_dqp = h->mb.i_qp - h->mb.i_last_qp; + int ctx; + + /* Avoid writing a delta quant if we have an empty i16x16 block, e.g. in a completely + * flat background area. Don't do this if it would raise the quantizer, since that could + * cause unexpected deblocking artifacts. */ + if( h->mb.i_type == I_16x16 && !h->mb.cbp[h->mb.i_mb_xy] && h->mb.i_qp > h->mb.i_last_qp ) + { +#if !RDO_SKIP_BS + h->mb.i_qp = h->mb.i_last_qp; +#endif + i_dqp = 0; + } + + ctx = h->mb.i_last_dqp && (h->mb.type[h->mb.i_mb_prev_xy] == I_16x16 || (h->mb.cbp[h->mb.i_mb_prev_xy]&0x3f)); + + if( i_dqp != 0 ) + { + /* Faster than (i_dqp <= 0 ? (-2*i_dqp) : (2*i_dqp-1)). + * If you so much as sneeze on these lines, gcc will compile this suboptimally. */ + i_dqp *= 2; + int val = 1 - i_dqp; + if( val < 0 ) val = i_dqp; + val--; + /* dqp is interpreted modulo (QP_MAX_SPEC+1) */ + if( val >= QP_MAX_SPEC && val != QP_MAX_SPEC+1 ) + val = 2*QP_MAX_SPEC+1 - val; + do + { + x264_cabac_encode_decision( cb, 60 + ctx, 1 ); + ctx = 2+(ctx>>1); + } while( --val ); + } + x264_cabac_encode_decision_noup( cb, 60 + ctx, 0 ); +} + +#if !RDO_SKIP_BS +void x264_cabac_mb_skip( x264_t *h, int b_skip ) +{ + int ctx = h->mb.cache.i_neighbour_skip + 11; + if( h->sh.i_type != SLICE_TYPE_P ) + ctx += 13; + x264_cabac_encode_decision( &h->cabac, ctx, b_skip ); +} +#endif + +static inline void x264_cabac_subpartition_p( x264_cabac_t *cb, int i_sub ) +{ + if( i_sub == D_L0_8x8 ) + { + x264_cabac_encode_decision( cb, 21, 1 ); + return; + } + x264_cabac_encode_decision( cb, 21, 0 ); + if( i_sub == D_L0_8x4 ) + x264_cabac_encode_decision( cb, 22, 0 ); + else + { + x264_cabac_encode_decision( cb, 22, 1 ); + x264_cabac_encode_decision( cb, 23, i_sub == D_L0_4x8 ); + } +} + +static ALWAYS_INLINE void x264_cabac_subpartition_b( x264_cabac_t *cb, int i_sub ) +{ + if( i_sub == D_DIRECT_8x8 ) + { + x264_cabac_encode_decision( cb, 36, 0 ); + return; + } + x264_cabac_encode_decision( cb, 36, 1 ); + if( i_sub == D_BI_8x8 ) + { + x264_cabac_encode_decision( cb, 37, 1 ); + x264_cabac_encode_decision( cb, 38, 0 ); + x264_cabac_encode_decision( cb, 39, 0 ); + x264_cabac_encode_decision( cb, 39, 0 ); + return; + } + x264_cabac_encode_decision( cb, 37, 0 ); + x264_cabac_encode_decision( cb, 39, i_sub == D_L1_8x8 ); +} + +static ALWAYS_INLINE void x264_cabac_transform_size( x264_t *h, x264_cabac_t *cb ) +{ + int ctx = 399 + h->mb.cache.i_neighbour_transform_size; + x264_cabac_encode_decision_noup( cb, ctx, h->mb.b_transform_8x8 ); +} + +static ALWAYS_INLINE void x264_cabac_ref_internal( x264_t *h, x264_cabac_t *cb, int i_list, int idx, int bframe ) +{ + const int i8 = x264_scan8[idx]; + const int i_refa = h->mb.cache.ref[i_list][i8 - 1]; + const int i_refb = h->mb.cache.ref[i_list][i8 - 8]; + int ctx = 0; + + if( i_refa > 0 && (!bframe || !h->mb.cache.skip[i8 - 1]) ) + ctx++; + if( i_refb > 0 && (!bframe || !h->mb.cache.skip[i8 - 8]) ) + ctx += 2; + + for( int i_ref = h->mb.cache.ref[i_list][i8]; i_ref > 0; i_ref-- ) + { + x264_cabac_encode_decision( cb, 54 + ctx, 1 ); + ctx = (ctx>>2)+4; + } + x264_cabac_encode_decision( cb, 54 + ctx, 0 ); +} + +static NOINLINE void x264_cabac_ref_p( x264_t *h, x264_cabac_t *cb, int idx ) +{ + x264_cabac_ref_internal( h, cb, 0, idx, 0 ); +} +static NOINLINE void x264_cabac_ref_b( x264_t *h, x264_cabac_t *cb, int i_list, int idx ) +{ + x264_cabac_ref_internal( h, cb, i_list, idx, 1 ); +} + +static ALWAYS_INLINE int x264_cabac_mvd_cpn( x264_t *h, x264_cabac_t *cb, int i_list, int idx, int l, int mvd, int ctx ) +{ + int ctxbase = l ? 47 : 40; + + if( mvd == 0 ) + { + x264_cabac_encode_decision( cb, ctxbase + ctx, 0 ); + return 0; + } + + int i_abs = abs( mvd ); + x264_cabac_encode_decision( cb, ctxbase + ctx, 1 ); +#if RDO_SKIP_BS + if( i_abs <= 3 ) + { + for( int i = 1; i < i_abs; i++ ) + x264_cabac_encode_decision( cb, ctxbase + i + 2, 1 ); + x264_cabac_encode_decision( cb, ctxbase + i_abs + 2, 0 ); + x264_cabac_encode_bypass( cb, mvd >> 31 ); + } + else + { + x264_cabac_encode_decision( cb, ctxbase + 3, 1 ); + x264_cabac_encode_decision( cb, ctxbase + 4, 1 ); + x264_cabac_encode_decision( cb, ctxbase + 5, 1 ); + if( i_abs < 9 ) + { + cb->f8_bits_encoded += x264_cabac_size_unary[i_abs - 3][cb->state[ctxbase+6]]; + cb->state[ctxbase+6] = x264_cabac_transition_unary[i_abs - 3][cb->state[ctxbase+6]]; + } + else + { + cb->f8_bits_encoded += cabac_size_5ones[cb->state[ctxbase+6]]; + cb->state[ctxbase+6] = cabac_transition_5ones[cb->state[ctxbase+6]]; + x264_cabac_encode_ue_bypass( cb, 3, i_abs - 9 ); + } + } +#else + static const uint8_t ctxes[8] = { 3,4,5,6,6,6,6,6 }; + + if( i_abs < 9 ) + { + for( int i = 1; i < i_abs; i++ ) + x264_cabac_encode_decision( cb, ctxbase + ctxes[i-1], 1 ); + x264_cabac_encode_decision( cb, ctxbase + ctxes[i_abs-1], 0 ); + } + else + { + for( int i = 1; i < 9; i++ ) + x264_cabac_encode_decision( cb, ctxbase + ctxes[i-1], 1 ); + x264_cabac_encode_ue_bypass( cb, 3, i_abs - 9 ); + } + x264_cabac_encode_bypass( cb, mvd >> 31 ); +#endif + /* Since we don't need to keep track of MVDs larger than 66, just cap the value. + * This lets us store MVDs as 8-bit values instead of 16-bit. */ + return X264_MIN( i_abs, 66 ); +} + +static NOINLINE uint16_t x264_cabac_mvd( x264_t *h, x264_cabac_t *cb, int i_list, int idx, int width ) +{ + ALIGNED_4( int16_t mvp[2] ); + int mdx, mdy; + + /* Calculate mvd */ + x264_mb_predict_mv( h, i_list, idx, width, mvp ); + mdx = h->mb.cache.mv[i_list][x264_scan8[idx]][0] - mvp[0]; + mdy = h->mb.cache.mv[i_list][x264_scan8[idx]][1] - mvp[1]; + uint16_t amvd = x264_cabac_mvd_sum(h->mb.cache.mvd[i_list][x264_scan8[idx] - 1], + h->mb.cache.mvd[i_list][x264_scan8[idx] - 8]); + + /* encode */ + mdx = x264_cabac_mvd_cpn( h, cb, i_list, idx, 0, mdx, amvd&0xFF ); + mdy = x264_cabac_mvd_cpn( h, cb, i_list, idx, 1, mdy, amvd>>8 ); + + return pack8to16(mdx,mdy); +} + +#define x264_cabac_mvd(h,cb,i_list,idx,width,height)\ +do\ +{\ + uint16_t mvd = x264_cabac_mvd(h,cb,i_list,idx,width);\ + x264_macroblock_cache_mvd( h, block_idx_x[idx], block_idx_y[idx], width, height, i_list, mvd );\ +} while( 0 ) + +static inline void x264_cabac_8x8_mvd( x264_t *h, x264_cabac_t *cb, int i ) +{ + switch( h->mb.i_sub_partition[i] ) + { + case D_L0_8x8: + x264_cabac_mvd( h, cb, 0, 4*i, 2, 2 ); + break; + case D_L0_8x4: + x264_cabac_mvd( h, cb, 0, 4*i+0, 2, 1 ); + x264_cabac_mvd( h, cb, 0, 4*i+2, 2, 1 ); + break; + case D_L0_4x8: + x264_cabac_mvd( h, cb, 0, 4*i+0, 1, 2 ); + x264_cabac_mvd( h, cb, 0, 4*i+1, 1, 2 ); + break; + case D_L0_4x4: + x264_cabac_mvd( h, cb, 0, 4*i+0, 1, 1 ); + x264_cabac_mvd( h, cb, 0, 4*i+1, 1, 1 ); + x264_cabac_mvd( h, cb, 0, 4*i+2, 1, 1 ); + x264_cabac_mvd( h, cb, 0, 4*i+3, 1, 1 ); + break; + default: + assert(0); + } +} + +static ALWAYS_INLINE void x264_cabac_mb_header_i( x264_t *h, x264_cabac_t *cb, int i_mb_type, int slice_type, int chroma ) +{ + if( slice_type == SLICE_TYPE_I ) + { + int ctx = 0; + if( (h->mb.i_neighbour & MB_LEFT) && h->mb.i_mb_type_left[0] != I_4x4 ) + ctx++; + if( (h->mb.i_neighbour & MB_TOP) && h->mb.i_mb_type_top != I_4x4 ) + ctx++; + + x264_cabac_mb_type_intra( h, cb, i_mb_type, 3+ctx, 3+3, 3+4, 3+5, 3+6, 3+7 ); + } + else if( slice_type == SLICE_TYPE_P ) + { + /* prefix */ + x264_cabac_encode_decision_noup( cb, 14, 1 ); + + /* suffix */ + x264_cabac_mb_type_intra( h, cb, i_mb_type, 17+0, 17+1, 17+2, 17+2, 17+3, 17+3 ); + } + else if( slice_type == SLICE_TYPE_B ) + { + /* prefix */ + x264_cabac_encode_decision_noup( cb, 27+3, 1 ); + x264_cabac_encode_decision_noup( cb, 27+4, 1 ); + x264_cabac_encode_decision( cb, 27+5, 1 ); + x264_cabac_encode_decision( cb, 27+5, 0 ); + x264_cabac_encode_decision( cb, 27+5, 1 ); + + /* suffix */ + x264_cabac_mb_type_intra( h, cb, i_mb_type, 32+0, 32+1, 32+2, 32+2, 32+3, 32+3 ); + } + + if( i_mb_type == I_PCM ) + return; + + if( i_mb_type != I_16x16 ) + { + if( h->pps->b_transform_8x8_mode ) + x264_cabac_transform_size( h, cb ); + + int di = h->mb.b_transform_8x8 ? 4 : 1; + for( int i = 0; i < 16; i += di ) + { + const int i_pred = x264_mb_predict_intra4x4_mode( h, i ); + const int i_mode = x264_mb_pred_mode4x4_fix( h->mb.cache.intra4x4_pred_mode[x264_scan8[i]] ); + x264_cabac_intra4x4_pred_mode( cb, i_pred, i_mode ); + } + } + + if( chroma ) + x264_cabac_intra_chroma_pred_mode( h, cb ); +} + +static ALWAYS_INLINE void x264_cabac_mb_header_p( x264_t *h, x264_cabac_t *cb, int i_mb_type, int chroma ) +{ + if( i_mb_type == P_L0 ) + { + x264_cabac_encode_decision_noup( cb, 14, 0 ); + if( h->mb.i_partition == D_16x16 ) + { + x264_cabac_encode_decision_noup( cb, 15, 0 ); + x264_cabac_encode_decision_noup( cb, 16, 0 ); + if( h->mb.pic.i_fref[0] > 1 ) + x264_cabac_ref_p( h, cb, 0 ); + x264_cabac_mvd( h, cb, 0, 0, 4, 4 ); + } + else if( h->mb.i_partition == D_16x8 ) + { + x264_cabac_encode_decision_noup( cb, 15, 1 ); + x264_cabac_encode_decision_noup( cb, 17, 1 ); + if( h->mb.pic.i_fref[0] > 1 ) + { + x264_cabac_ref_p( h, cb, 0 ); + x264_cabac_ref_p( h, cb, 8 ); + } + x264_cabac_mvd( h, cb, 0, 0, 4, 2 ); + x264_cabac_mvd( h, cb, 0, 8, 4, 2 ); + } + else //if( h->mb.i_partition == D_8x16 ) + { + x264_cabac_encode_decision_noup( cb, 15, 1 ); + x264_cabac_encode_decision_noup( cb, 17, 0 ); + if( h->mb.pic.i_fref[0] > 1 ) + { + x264_cabac_ref_p( h, cb, 0 ); + x264_cabac_ref_p( h, cb, 4 ); + } + x264_cabac_mvd( h, cb, 0, 0, 2, 4 ); + x264_cabac_mvd( h, cb, 0, 4, 2, 4 ); + } + } + else if( i_mb_type == P_8x8 ) + { + x264_cabac_encode_decision_noup( cb, 14, 0 ); + x264_cabac_encode_decision_noup( cb, 15, 0 ); + x264_cabac_encode_decision_noup( cb, 16, 1 ); + + /* sub mb type */ + for( int i = 0; i < 4; i++ ) + x264_cabac_subpartition_p( cb, h->mb.i_sub_partition[i] ); + + /* ref 0 */ + if( h->mb.pic.i_fref[0] > 1 ) + { + x264_cabac_ref_p( h, cb, 0 ); + x264_cabac_ref_p( h, cb, 4 ); + x264_cabac_ref_p( h, cb, 8 ); + x264_cabac_ref_p( h, cb, 12 ); + } + + for( int i = 0; i < 4; i++ ) + x264_cabac_8x8_mvd( h, cb, i ); + } + else /* intra */ + x264_cabac_mb_header_i( h, cb, i_mb_type, SLICE_TYPE_P, chroma ); +} + +static ALWAYS_INLINE void x264_cabac_mb_header_b( x264_t *h, x264_cabac_t *cb, int i_mb_type, int chroma ) +{ + int ctx = 0; + if( (h->mb.i_neighbour & MB_LEFT) && h->mb.i_mb_type_left[0] != B_SKIP && h->mb.i_mb_type_left[0] != B_DIRECT ) + ctx++; + if( (h->mb.i_neighbour & MB_TOP) && h->mb.i_mb_type_top != B_SKIP && h->mb.i_mb_type_top != B_DIRECT ) + ctx++; + + if( i_mb_type == B_DIRECT ) + { + x264_cabac_encode_decision_noup( cb, 27+ctx, 0 ); + return; + } + x264_cabac_encode_decision_noup( cb, 27+ctx, 1 ); + + if( i_mb_type == B_8x8 ) + { + x264_cabac_encode_decision_noup( cb, 27+3, 1 ); + x264_cabac_encode_decision_noup( cb, 27+4, 1 ); + x264_cabac_encode_decision( cb, 27+5, 1 ); + x264_cabac_encode_decision( cb, 27+5, 1 ); + x264_cabac_encode_decision_noup( cb, 27+5, 1 ); + + /* sub mb type */ + for( int i = 0; i < 4; i++ ) + x264_cabac_subpartition_b( cb, h->mb.i_sub_partition[i] ); + + /* ref */ + if( h->mb.pic.i_fref[0] > 1 ) + for( int i = 0; i < 4; i++ ) + if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i] ] ) + x264_cabac_ref_b( h, cb, 0, 4*i ); + + if( h->mb.pic.i_fref[1] > 1 ) + for( int i = 0; i < 4; i++ ) + if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i] ] ) + x264_cabac_ref_b( h, cb, 1, 4*i ); + + for( int i = 0; i < 4; i++ ) + if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i] ] ) + x264_cabac_mvd( h, cb, 0, 4*i, 2, 2 ); + + for( int i = 0; i < 4; i++ ) + if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i] ] ) + x264_cabac_mvd( h, cb, 1, 4*i, 2, 2 ); + } + else if( i_mb_type >= B_L0_L0 && i_mb_type <= B_BI_BI ) + { + /* All B modes */ + static const uint8_t i_mb_bits[9*3] = + { + 0x31, 0x29, 0x4, /* L0 L0 */ + 0x35, 0x2d, 0, /* L0 L1 */ + 0x43, 0x63, 0, /* L0 BI */ + 0x3d, 0x2f, 0, /* L1 L0 */ + 0x39, 0x25, 0x6, /* L1 L1 */ + 0x53, 0x73, 0, /* L1 BI */ + 0x4b, 0x6b, 0, /* BI L0 */ + 0x5b, 0x7b, 0, /* BI L1 */ + 0x47, 0x67, 0x21 /* BI BI */ + }; + + const int idx = (i_mb_type - B_L0_L0) * 3 + (h->mb.i_partition - D_16x8); + int bits = i_mb_bits[idx]; + + x264_cabac_encode_decision_noup( cb, 27+3, bits&1 ); + x264_cabac_encode_decision( cb, 27+5-(bits&1), (bits>>1)&1 ); bits >>= 2; + if( bits != 1 ) + { + x264_cabac_encode_decision( cb, 27+5, bits&1 ); bits >>= 1; + x264_cabac_encode_decision( cb, 27+5, bits&1 ); bits >>= 1; + x264_cabac_encode_decision( cb, 27+5, bits&1 ); bits >>= 1; + if( bits != 1 ) + x264_cabac_encode_decision_noup( cb, 27+5, bits&1 ); + } + + const uint8_t (*b_list)[2] = x264_mb_type_list_table[i_mb_type]; + if( h->mb.pic.i_fref[0] > 1 ) + { + if( b_list[0][0] ) + x264_cabac_ref_b( h, cb, 0, 0 ); + if( b_list[0][1] && h->mb.i_partition != D_16x16 ) + x264_cabac_ref_b( h, cb, 0, 8 >> (h->mb.i_partition == D_8x16) ); + } + if( h->mb.pic.i_fref[1] > 1 ) + { + if( b_list[1][0] ) + x264_cabac_ref_b( h, cb, 1, 0 ); + if( b_list[1][1] && h->mb.i_partition != D_16x16 ) + x264_cabac_ref_b( h, cb, 1, 8 >> (h->mb.i_partition == D_8x16) ); + } + for( int i_list = 0; i_list < 2; i_list++ ) + { + if( h->mb.i_partition == D_16x16 ) + { + if( b_list[i_list][0] ) x264_cabac_mvd( h, cb, i_list, 0, 4, 4 ); + } + else if( h->mb.i_partition == D_16x8 ) + { + if( b_list[i_list][0] ) x264_cabac_mvd( h, cb, i_list, 0, 4, 2 ); + if( b_list[i_list][1] ) x264_cabac_mvd( h, cb, i_list, 8, 4, 2 ); + } + else //if( h->mb.i_partition == D_8x16 ) + { + if( b_list[i_list][0] ) x264_cabac_mvd( h, cb, i_list, 0, 2, 4 ); + if( b_list[i_list][1] ) x264_cabac_mvd( h, cb, i_list, 4, 2, 4 ); + } + } + } + else /* intra */ + x264_cabac_mb_header_i( h, cb, i_mb_type, SLICE_TYPE_B, chroma ); +} + +static int ALWAYS_INLINE x264_cabac_cbf_ctxidxinc( x264_t *h, int i_cat, int i_idx, int b_intra, int b_dc ) +{ + static const uint16_t base_ctx[14] = {85,89,93,97,101,1012,460,464,468,1016,472,476,480,1020}; + + if( b_dc ) + { + i_idx -= LUMA_DC; + if( i_cat == DCT_CHROMA_DC ) + { + int i_nza = h->mb.cache.i_cbp_left != -1 ? (h->mb.cache.i_cbp_left >> (8 + i_idx)) & 1 : b_intra; + int i_nzb = h->mb.cache.i_cbp_top != -1 ? (h->mb.cache.i_cbp_top >> (8 + i_idx)) & 1 : b_intra; + return base_ctx[i_cat] + 2*i_nzb + i_nza; + } + else + { + int i_nza = (h->mb.cache.i_cbp_left >> (8 + i_idx)) & 1; + int i_nzb = (h->mb.cache.i_cbp_top >> (8 + i_idx)) & 1; + return base_ctx[i_cat] + 2*i_nzb + i_nza; + } + } + else + { + int i_nza = h->mb.cache.non_zero_count[x264_scan8[i_idx] - 1]; + int i_nzb = h->mb.cache.non_zero_count[x264_scan8[i_idx] - 8]; + if( x264_constant_p(b_intra) && !b_intra ) + return base_ctx[i_cat] + ((2*i_nzb + i_nza)&0x7f); + else + { + i_nza &= 0x7f + (b_intra << 7); + i_nzb &= 0x7f + (b_intra << 7); + return base_ctx[i_cat] + 2*!!i_nzb + !!i_nza; + } + } +} + +#if !RDO_SKIP_BS +extern const uint8_t x264_significant_coeff_flag_offset_8x8[2][64]; +extern const uint8_t x264_last_coeff_flag_offset_8x8[63]; +extern const uint8_t x264_coeff_flag_offset_chroma_422_dc[7]; +extern const uint16_t x264_significant_coeff_flag_offset[2][16]; +extern const uint16_t x264_last_coeff_flag_offset[2][16]; +extern const uint16_t x264_coeff_abs_level_m1_offset[16]; +extern const uint8_t x264_count_cat_m1[14]; +#else +/* Padded to [64] for easier addressing */ +const uint8_t x264_significant_coeff_flag_offset_8x8[2][64] = +{{ + 0, 1, 2, 3, 4, 5, 5, 4, 4, 3, 3, 4, 4, 4, 5, 5, + 4, 4, 4, 4, 3, 3, 6, 7, 7, 7, 8, 9,10, 9, 8, 7, + 7, 6,11,12,13,11, 6, 7, 8, 9,14,10, 9, 8, 6,11, + 12,13,11, 6, 9,14,10, 9,11,12,13,11,14,10,12 +},{ + 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 7, 8, 4, 5, + 6, 9,10,10, 8,11,12,11, 9, 9,10,10, 8,11,12,11, + 9, 9,10,10, 8,11,12,11, 9, 9,10,10, 8,13,13, 9, + 9,10,10, 8,13,13, 9, 9,10,10,14,14,14,14,14 +}}; +const uint8_t x264_last_coeff_flag_offset_8x8[63] = +{ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8 +}; +const uint8_t x264_coeff_flag_offset_chroma_422_dc[7] = { 0, 0, 1, 1, 2, 2, 2 }; /* MIN( i/2, 2 ) */ +const uint16_t x264_significant_coeff_flag_offset[2][16] = +{ + { 105+0, 105+15, 105+29, 105+44, 105+47, 402, 484+0, 484+15, 484+29, 660, 528+0, 528+15, 528+29, 718, 0, 0 }, + { 277+0, 277+15, 277+29, 277+44, 277+47, 436, 776+0, 776+15, 776+29, 675, 820+0, 820+15, 820+29, 733, 0, 0 } +}; +const uint16_t x264_last_coeff_flag_offset[2][16] = +{ + { 166+0, 166+15, 166+29, 166+44, 166+47, 417, 572+0, 572+15, 572+29, 690, 616+0, 616+15, 616+29, 748, 0, 0 }, + { 338+0, 338+15, 338+29, 338+44, 338+47, 451, 864+0, 864+15, 864+29, 699, 908+0, 908+15, 908+29, 757, 0, 0 } +}; +const uint16_t x264_coeff_abs_level_m1_offset[16] = +{ + 227+0, 227+10, 227+20, 227+30, 227+39, 426, 952+0, 952+10, 952+20, 708, 982+0, 982+10, 982+20, 766 +}; +const uint8_t x264_count_cat_m1[14] = {15, 14, 15, 3, 14, 63, 15, 14, 15, 63, 15, 14, 15, 63}; +#endif + +// node ctx: 0..3: abslevel1 (with abslevelgt1 == 0). +// 4..7: abslevelgt1 + 3 (and abslevel1 doesn't matter). +/* map node ctx => cabac ctx for level=1 */ +static const uint8_t coeff_abs_level1_ctx[8] = { 1, 2, 3, 4, 0, 0, 0, 0 }; +/* map node ctx => cabac ctx for level>1 */ +static const uint8_t coeff_abs_levelgt1_ctx[8] = { 5, 5, 5, 5, 6, 7, 8, 9 }; +/* 4:2:2 chroma dc uses a slightly different state machine for some reason, also note that + * 4:2:0 chroma dc doesn't use the last state so it has identical output with both arrays. */ +static const uint8_t coeff_abs_levelgt1_ctx_chroma_dc[8] = { 5, 5, 5, 5, 6, 7, 8, 8 }; + +static const uint8_t coeff_abs_level_transition[2][8] = { +/* update node ctx after coding a level=1 */ + { 1, 2, 3, 3, 4, 5, 6, 7 }, +/* update node ctx after coding a level>1 */ + { 4, 4, 4, 4, 5, 6, 7, 7 } +}; + +#if !RDO_SKIP_BS +static ALWAYS_INLINE void x264_cabac_block_residual_internal( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l, int chroma422dc ) +{ + int ctx_sig = x264_significant_coeff_flag_offset[MB_INTERLACED][ctx_block_cat]; + int ctx_last = x264_last_coeff_flag_offset[MB_INTERLACED][ctx_block_cat]; + int ctx_level = x264_coeff_abs_level_m1_offset[ctx_block_cat]; + int coeff_idx = -1, node_ctx = 0; + int last = h->quantf.coeff_last[ctx_block_cat]( l ); + const uint8_t *levelgt1_ctx = chroma422dc ? coeff_abs_levelgt1_ctx_chroma_dc : coeff_abs_levelgt1_ctx; + dctcoef coeffs[64]; + +#define WRITE_SIGMAP( sig_off, last_off )\ +{\ + int i = 0;\ + while( 1 )\ + {\ + if( l[i] )\ + {\ + coeffs[++coeff_idx] = l[i];\ + x264_cabac_encode_decision( cb, ctx_sig + sig_off, 1 );\ + if( i == last )\ + {\ + x264_cabac_encode_decision( cb, ctx_last + last_off, 1 );\ + break;\ + }\ + else\ + x264_cabac_encode_decision( cb, ctx_last + last_off, 0 );\ + }\ + else\ + x264_cabac_encode_decision( cb, ctx_sig + sig_off, 0 );\ + if( ++i == count_m1 )\ + {\ + coeffs[++coeff_idx] = l[i];\ + break;\ + }\ + }\ +} + + if( chroma422dc ) + { + int count_m1 = 7; + WRITE_SIGMAP( x264_coeff_flag_offset_chroma_422_dc[i], x264_coeff_flag_offset_chroma_422_dc[i] ) + } + else + { + int count_m1 = x264_count_cat_m1[ctx_block_cat]; + if( count_m1 == 63 ) + { + const uint8_t *sig_offset = x264_significant_coeff_flag_offset_8x8[MB_INTERLACED]; + WRITE_SIGMAP( sig_offset[i], x264_last_coeff_flag_offset_8x8[i] ) + } + else + WRITE_SIGMAP( i, i ) + } + + do + { + /* write coeff_abs - 1 */ + int coeff = coeffs[coeff_idx]; + int abs_coeff = abs(coeff); + int coeff_sign = coeff >> 31; + int ctx = coeff_abs_level1_ctx[node_ctx] + ctx_level; + + if( abs_coeff > 1 ) + { + x264_cabac_encode_decision( cb, ctx, 1 ); + ctx = levelgt1_ctx[node_ctx] + ctx_level; + for( int i = X264_MIN( abs_coeff, 15 ) - 2; i > 0; i-- ) + x264_cabac_encode_decision( cb, ctx, 1 ); + if( abs_coeff < 15 ) + x264_cabac_encode_decision( cb, ctx, 0 ); + else + x264_cabac_encode_ue_bypass( cb, 0, abs_coeff - 15 ); + + node_ctx = coeff_abs_level_transition[1][node_ctx]; + } + else + { + x264_cabac_encode_decision( cb, ctx, 0 ); + node_ctx = coeff_abs_level_transition[0][node_ctx]; + } + + x264_cabac_encode_bypass( cb, coeff_sign ); + } while( --coeff_idx >= 0 ); +} + +void x264_cabac_block_residual_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) +{ + x264_cabac_block_residual_internal( h, cb, ctx_block_cat, l, 0 ); +} + +static void ALWAYS_INLINE x264_cabac_block_residual( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) +{ +#if ARCH_X86_64 && HAVE_MMX && !defined( __MACH__ ) + h->bsf.cabac_block_residual_internal( l, MB_INTERLACED, ctx_block_cat, cb ); +#else + x264_cabac_block_residual_c( h, cb, ctx_block_cat, l ); +#endif +} +static void x264_cabac_block_residual_422_dc( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) +{ + /* Template a version specifically for chroma 4:2:2 DC in order to avoid + * slowing down everything else due to the added complexity. */ + x264_cabac_block_residual_internal( h, cb, DCT_CHROMA_DC, l, 1 ); +} +#define x264_cabac_block_residual_8x8( h, cb, cat, l ) x264_cabac_block_residual( h, cb, cat, l ) +#else + +/* Faster RDO by merging sigmap and level coding. Note that for 8x8dct and chroma 4:2:2 dc this is + * slightly incorrect because the sigmap is not reversible (contexts are repeated). However, there + * is nearly no quality penalty for this (~0.001db) and the speed boost (~30%) is worth it. */ +static void ALWAYS_INLINE x264_cabac_block_residual_internal( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l, int b_8x8, int chroma422dc ) +{ + const uint8_t *sig_offset = x264_significant_coeff_flag_offset_8x8[MB_INTERLACED]; + int ctx_sig = x264_significant_coeff_flag_offset[MB_INTERLACED][ctx_block_cat]; + int ctx_last = x264_last_coeff_flag_offset[MB_INTERLACED][ctx_block_cat]; + int ctx_level = x264_coeff_abs_level_m1_offset[ctx_block_cat]; + int last = h->quantf.coeff_last[ctx_block_cat]( l ); + int coeff_abs = abs(l[last]); + int ctx = coeff_abs_level1_ctx[0] + ctx_level; + int node_ctx; + const uint8_t *levelgt1_ctx = chroma422dc ? coeff_abs_levelgt1_ctx_chroma_dc : coeff_abs_levelgt1_ctx; + + if( last != (b_8x8 ? 63 : chroma422dc ? 7 : x264_count_cat_m1[ctx_block_cat]) ) + { + x264_cabac_encode_decision( cb, ctx_sig + (b_8x8 ? sig_offset[last] : + chroma422dc ? x264_coeff_flag_offset_chroma_422_dc[last] : last), 1 ); + x264_cabac_encode_decision( cb, ctx_last + (b_8x8 ? x264_last_coeff_flag_offset_8x8[last] : + chroma422dc ? x264_coeff_flag_offset_chroma_422_dc[last] : last), 1 ); + } + + if( coeff_abs > 1 ) + { + x264_cabac_encode_decision( cb, ctx, 1 ); + ctx = levelgt1_ctx[0] + ctx_level; + if( coeff_abs < 15 ) + { + cb->f8_bits_encoded += x264_cabac_size_unary[coeff_abs-1][cb->state[ctx]]; + cb->state[ctx] = x264_cabac_transition_unary[coeff_abs-1][cb->state[ctx]]; + } + else + { + cb->f8_bits_encoded += x264_cabac_size_unary[14][cb->state[ctx]]; + cb->state[ctx] = x264_cabac_transition_unary[14][cb->state[ctx]]; + x264_cabac_encode_ue_bypass( cb, 0, coeff_abs - 15 ); + } + node_ctx = coeff_abs_level_transition[1][0]; + } + else + { + x264_cabac_encode_decision( cb, ctx, 0 ); + node_ctx = coeff_abs_level_transition[0][0]; + x264_cabac_encode_bypass( cb, 0 ); // sign + } + + for( int i = last-1; i >= 0; i-- ) + { + if( l[i] ) + { + coeff_abs = abs(l[i]); + x264_cabac_encode_decision( cb, ctx_sig + (b_8x8 ? sig_offset[i] : + chroma422dc ? x264_coeff_flag_offset_chroma_422_dc[i] : i), 1 ); + x264_cabac_encode_decision( cb, ctx_last + (b_8x8 ? x264_last_coeff_flag_offset_8x8[i] : + chroma422dc ? x264_coeff_flag_offset_chroma_422_dc[i] : i), 0 ); + ctx = coeff_abs_level1_ctx[node_ctx] + ctx_level; + + if( coeff_abs > 1 ) + { + x264_cabac_encode_decision( cb, ctx, 1 ); + ctx = levelgt1_ctx[node_ctx] + ctx_level; + if( coeff_abs < 15 ) + { + cb->f8_bits_encoded += x264_cabac_size_unary[coeff_abs-1][cb->state[ctx]]; + cb->state[ctx] = x264_cabac_transition_unary[coeff_abs-1][cb->state[ctx]]; + } + else + { + cb->f8_bits_encoded += x264_cabac_size_unary[14][cb->state[ctx]]; + cb->state[ctx] = x264_cabac_transition_unary[14][cb->state[ctx]]; + x264_cabac_encode_ue_bypass( cb, 0, coeff_abs - 15 ); + } + node_ctx = coeff_abs_level_transition[1][node_ctx]; + } + else + { + x264_cabac_encode_decision( cb, ctx, 0 ); + node_ctx = coeff_abs_level_transition[0][node_ctx]; + x264_cabac_encode_bypass( cb, 0 ); + } + } + else + x264_cabac_encode_decision( cb, ctx_sig + (b_8x8 ? sig_offset[i] : + chroma422dc ? x264_coeff_flag_offset_chroma_422_dc[i] : i), 0 ); + } +} + +void x264_cabac_block_residual_8x8_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) +{ + x264_cabac_block_residual_internal( h, cb, ctx_block_cat, l, 1, 0 ); +} +void x264_cabac_block_residual_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) +{ + x264_cabac_block_residual_internal( h, cb, ctx_block_cat, l, 0, 0 ); +} + +static ALWAYS_INLINE void x264_cabac_block_residual_8x8( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) +{ +#if ARCH_X86_64 && HAVE_MMX && !defined( __MACH__ ) + h->bsf.cabac_block_residual_8x8_rd_internal( l, MB_INTERLACED, ctx_block_cat, cb ); +#else + x264_cabac_block_residual_8x8_rd_c( h, cb, ctx_block_cat, l ); +#endif +} +static ALWAYS_INLINE void x264_cabac_block_residual( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) +{ +#if ARCH_X86_64 && HAVE_MMX && !defined( __MACH__ ) + h->bsf.cabac_block_residual_rd_internal( l, MB_INTERLACED, ctx_block_cat, cb ); +#else + x264_cabac_block_residual_rd_c( h, cb, ctx_block_cat, l ); +#endif +} + +static void x264_cabac_block_residual_422_dc( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ) +{ + x264_cabac_block_residual_internal( h, cb, DCT_CHROMA_DC, l, 0, 1 ); +} +#endif + +#define x264_cabac_block_residual_cbf_internal( h, cb, ctx_block_cat, i_idx, l, b_intra, b_dc, name )\ +do\ +{\ + int ctxidxinc = x264_cabac_cbf_ctxidxinc( h, ctx_block_cat, i_idx, b_intra, b_dc );\ + if( h->mb.cache.non_zero_count[x264_scan8[i_idx]] )\ + {\ + x264_cabac_encode_decision( cb, ctxidxinc, 1 );\ + x264_cabac_block_residual##name( h, cb, ctx_block_cat, l );\ + }\ + else\ + x264_cabac_encode_decision( cb, ctxidxinc, 0 );\ +} while( 0 ) + +#define x264_cabac_block_residual_dc_cbf( h, cb, ctx_block_cat, i_idx, l, b_intra )\ + x264_cabac_block_residual_cbf_internal( h, cb, ctx_block_cat, i_idx, l, b_intra, 1, ) + +#define x264_cabac_block_residual_cbf( h, cb, ctx_block_cat, i_idx, l, b_intra )\ + x264_cabac_block_residual_cbf_internal( h, cb, ctx_block_cat, i_idx, l, b_intra, 0, ) + +#define x264_cabac_block_residual_8x8_cbf( h, cb, ctx_block_cat, i_idx, l, b_intra )\ + x264_cabac_block_residual_cbf_internal( h, cb, ctx_block_cat, i_idx, l, b_intra, 0, _8x8 ) + +#define x264_cabac_block_residual_422_dc_cbf( h, cb, ch, b_intra )\ + x264_cabac_block_residual_cbf_internal( h, cb, DCT_CHROMA_DC, CHROMA_DC+(ch), h->dct.chroma_dc[ch], b_intra, 1, _422_dc ) + +static ALWAYS_INLINE void x264_macroblock_write_cabac_internal( x264_t *h, x264_cabac_t *cb, int plane_count, int chroma ) +{ + const int i_mb_type = h->mb.i_type; + +#if !RDO_SKIP_BS + const int i_mb_pos_start = x264_cabac_pos( cb ); + int i_mb_pos_tex; + + if( SLICE_MBAFF && + (!(h->mb.i_mb_y & 1) || IS_SKIP(h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride])) ) + { + x264_cabac_field_decoding_flag( h, cb ); + } +#endif + + if( h->sh.i_type == SLICE_TYPE_P ) + x264_cabac_mb_header_p( h, cb, i_mb_type, chroma ); + else if( h->sh.i_type == SLICE_TYPE_B ) + x264_cabac_mb_header_b( h, cb, i_mb_type, chroma ); + else //if( h->sh.i_type == SLICE_TYPE_I ) + x264_cabac_mb_header_i( h, cb, i_mb_type, SLICE_TYPE_I, chroma ); + +#if !RDO_SKIP_BS + i_mb_pos_tex = x264_cabac_pos( cb ); + h->stat.frame.i_mv_bits += i_mb_pos_tex - i_mb_pos_start; + + if( i_mb_type == I_PCM ) + { + bs_t s; + bs_init( &s, cb->p, cb->p_end - cb->p ); + + for( int p = 0; p < plane_count; p++ ) + for( int i = 0; i < 256; i++ ) + bs_write( &s, BIT_DEPTH, h->mb.pic.p_fenc[p][i] ); + if( chroma ) + for( int ch = 1; ch < 3; ch++ ) + for( int i = 0; i < 16>>CHROMA_V_SHIFT; i++ ) + for( int j = 0; j < 8; j++ ) + bs_write( &s, BIT_DEPTH, h->mb.pic.p_fenc[ch][i*FENC_STRIDE+j] ); + + bs_flush( &s ); + cb->p = s.p; + x264_cabac_encode_init_core( cb ); + + h->stat.frame.i_tex_bits += x264_cabac_pos( cb ) - i_mb_pos_tex; + return; + } +#endif + + if( i_mb_type != I_16x16 ) + { + x264_cabac_cbp_luma( h, cb ); + if( chroma ) + x264_cabac_cbp_chroma( h, cb ); + } + + if( x264_mb_transform_8x8_allowed( h ) && h->mb.i_cbp_luma ) + { + x264_cabac_transform_size( h, cb ); + } + + if( h->mb.i_cbp_luma || (chroma && h->mb.i_cbp_chroma) || i_mb_type == I_16x16 ) + { + const int b_intra = IS_INTRA( i_mb_type ); + x264_cabac_qp_delta( h, cb ); + + /* write residual */ + if( i_mb_type == I_16x16 ) + { + /* DC Luma */ + for( int p = 0; p < plane_count; p++ ) + { + x264_cabac_block_residual_dc_cbf( h, cb, ctx_cat_plane[DCT_LUMA_DC][p], LUMA_DC+p, h->dct.luma16x16_dc[p], 1 ); + + /* AC Luma */ + if( h->mb.i_cbp_luma ) + for( int i = p*16; i < p*16+16; i++ ) + x264_cabac_block_residual_cbf( h, cb, ctx_cat_plane[DCT_LUMA_AC][p], i, h->dct.luma4x4[i]+1, 1 ); + } + } + else if( h->mb.b_transform_8x8 ) + { + if( plane_count == 3 ) + { + ALIGNED_4( uint8_t nnzbak[3][8] ); + +/* Stupid nnz munging in the case that neighbors don't have + * 8x8 transform enabled. */ +#define BACKUP( dst, src, res )\ + dst = src;\ + src = res; + +#define RESTORE( dst, src, res )\ + src = dst; + +#define MUNGE_8x8_NNZ( MUNGE )\ +if( (h->mb.i_neighbour & MB_LEFT) && !h->mb.mb_transform_size[h->mb.i_mb_left_xy[0]] && !(h->mb.cbp[h->mb.i_mb_left_xy[0]] & 0x1000) )\ +{\ + MUNGE( nnzbak[0][0], h->mb.cache.non_zero_count[x264_scan8[16*0+ 0] - 1], 0x00 )\ + MUNGE( nnzbak[0][1], h->mb.cache.non_zero_count[x264_scan8[16*0+ 2] - 1], 0x00 )\ + MUNGE( nnzbak[1][0], h->mb.cache.non_zero_count[x264_scan8[16*1+ 0] - 1], 0x00 )\ + MUNGE( nnzbak[1][1], h->mb.cache.non_zero_count[x264_scan8[16*1+ 2] - 1], 0x00 )\ + MUNGE( nnzbak[2][0], h->mb.cache.non_zero_count[x264_scan8[16*2+ 0] - 1], 0x00 )\ + MUNGE( nnzbak[2][1], h->mb.cache.non_zero_count[x264_scan8[16*2+ 2] - 1], 0x00 )\ +}\ +if( (h->mb.i_neighbour & MB_LEFT) && !h->mb.mb_transform_size[h->mb.i_mb_left_xy[1]] && !(h->mb.cbp[h->mb.i_mb_left_xy[1]] & 0x1000) )\ +{\ + MUNGE( nnzbak[0][2], h->mb.cache.non_zero_count[x264_scan8[16*0+ 8] - 1], 0x00 )\ + MUNGE( nnzbak[0][3], h->mb.cache.non_zero_count[x264_scan8[16*0+10] - 1], 0x00 )\ + MUNGE( nnzbak[1][2], h->mb.cache.non_zero_count[x264_scan8[16*1+ 8] - 1], 0x00 )\ + MUNGE( nnzbak[1][3], h->mb.cache.non_zero_count[x264_scan8[16*1+10] - 1], 0x00 )\ + MUNGE( nnzbak[2][2], h->mb.cache.non_zero_count[x264_scan8[16*2+ 8] - 1], 0x00 )\ + MUNGE( nnzbak[2][3], h->mb.cache.non_zero_count[x264_scan8[16*2+10] - 1], 0x00 )\ +}\ +if( (h->mb.i_neighbour & MB_TOP) && !h->mb.mb_transform_size[h->mb.i_mb_top_xy] && !(h->mb.cbp[h->mb.i_mb_top_xy] & 0x1000) )\ +{\ + MUNGE( M32( &nnzbak[0][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*0] - 8] ), 0x00000000U )\ + MUNGE( M32( &nnzbak[1][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*1] - 8] ), 0x00000000U )\ + MUNGE( M32( &nnzbak[2][4] ), M32( &h->mb.cache.non_zero_count[x264_scan8[16*2] - 8] ), 0x00000000U )\ +} + + MUNGE_8x8_NNZ( BACKUP ) + + for( int p = 0; p < 3; p++ ) + FOREACH_BIT( i, 0, h->mb.i_cbp_luma ) + x264_cabac_block_residual_8x8_cbf( h, cb, ctx_cat_plane[DCT_LUMA_8x8][p], i*4+p*16, h->dct.luma8x8[i+p*4], b_intra ); + + MUNGE_8x8_NNZ( RESTORE ) + } + else + { + FOREACH_BIT( i, 0, h->mb.i_cbp_luma ) + x264_cabac_block_residual_8x8( h, cb, DCT_LUMA_8x8, h->dct.luma8x8[i] ); + } + } + else + { + for( int p = 0; p < plane_count; p++ ) + FOREACH_BIT( i8x8, 0, h->mb.i_cbp_luma ) + for( int i = 0; i < 4; i++ ) + x264_cabac_block_residual_cbf( h, cb, ctx_cat_plane[DCT_LUMA_4x4][p], i+i8x8*4+p*16, h->dct.luma4x4[i+i8x8*4+p*16], b_intra ); + } + + if( chroma && h->mb.i_cbp_chroma ) /* Chroma DC residual present */ + { + if( CHROMA_FORMAT == CHROMA_422 ) + { + x264_cabac_block_residual_422_dc_cbf( h, cb, 0, b_intra ); + x264_cabac_block_residual_422_dc_cbf( h, cb, 1, b_intra ); + } + else + { + x264_cabac_block_residual_dc_cbf( h, cb, DCT_CHROMA_DC, CHROMA_DC+0, h->dct.chroma_dc[0], b_intra ); + x264_cabac_block_residual_dc_cbf( h, cb, DCT_CHROMA_DC, CHROMA_DC+1, h->dct.chroma_dc[1], b_intra ); + } + + if( h->mb.i_cbp_chroma == 2 ) /* Chroma AC residual present */ + { + int step = 8 << CHROMA_V_SHIFT; + for( int i = 16; i < 3*16; i += step ) + for( int j = i; j < i+4; j++ ) + x264_cabac_block_residual_cbf( h, cb, DCT_CHROMA_AC, j, h->dct.luma4x4[j]+1, b_intra ); + } + } + } + +#if !RDO_SKIP_BS + h->stat.frame.i_tex_bits += x264_cabac_pos( cb ) - i_mb_pos_tex; +#endif +} + +void x264_macroblock_write_cabac( x264_t *h, x264_cabac_t *cb ) +{ + if( CHROMA444 ) + x264_macroblock_write_cabac_internal( h, cb, 3, 0 ); + else + x264_macroblock_write_cabac_internal( h, cb, 1, 1 ); +} + +#if RDO_SKIP_BS +/***************************************************************************** + * RD only; doesn't generate a valid bitstream + * doesn't write cbp or chroma dc (I don't know how much this matters) + * doesn't write ref (never varies between calls, so no point in doing so) + * only writes subpartition for p8x8, needed for sub-8x8 mode decision RDO + * works on all partition sizes except 16x16 + *****************************************************************************/ +static void x264_partition_size_cabac( x264_t *h, x264_cabac_t *cb, int i8, int i_pixel ) +{ + const int i_mb_type = h->mb.i_type; + int b_8x16 = h->mb.i_partition == D_8x16; + int plane_count = CHROMA444 ? 3 : 1; + + if( i_mb_type == P_8x8 ) + { + x264_cabac_8x8_mvd( h, cb, i8 ); + x264_cabac_subpartition_p( cb, h->mb.i_sub_partition[i8] ); + } + else if( i_mb_type == P_L0 ) + x264_cabac_mvd( h, cb, 0, 4*i8, 4>>b_8x16, 2< B_DIRECT && i_mb_type < B_8x8 ) + { + if( x264_mb_type_list_table[ i_mb_type ][0][!!i8] ) x264_cabac_mvd( h, cb, 0, 4*i8, 4>>b_8x16, 2<>b_8x16, 2<mb.i_sub_partition[i8] ] ) + x264_cabac_mvd( h, cb, 0, 4*i8, 2, 2 ); + if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i8] ] ) + x264_cabac_mvd( h, cb, 1, 4*i8, 2, 2 ); + } + + for( int j = (i_pixel < PIXEL_8x8); j >= 0; j-- ) + { + if( h->mb.i_cbp_luma & (1 << i8) ) + { + if( h->mb.b_transform_8x8 ) + { + if( CHROMA444 ) + for( int p = 0; p < 3; p++ ) + x264_cabac_block_residual_8x8_cbf( h, cb, ctx_cat_plane[DCT_LUMA_8x8][p], i8*4+p*16, h->dct.luma8x8[i8+p*4], 0 ); + else + x264_cabac_block_residual_8x8( h, cb, DCT_LUMA_8x8, h->dct.luma8x8[i8] ); + } + else + for( int p = 0; p < plane_count; p++ ) + for( int i4 = 0; i4 < 4; i4++ ) + x264_cabac_block_residual_cbf( h, cb, ctx_cat_plane[DCT_LUMA_4x4][p], i4+i8*4+p*16, h->dct.luma4x4[i4+i8*4+p*16], 0 ); + } + + if( h->mb.i_cbp_chroma ) + { + if( CHROMA_FORMAT == CHROMA_422 ) + { + int offset = (5*i8) & 0x09; + x264_cabac_block_residual_cbf( h, cb, DCT_CHROMA_AC, 16+offset, h->dct.luma4x4[16+offset]+1, 0 ); + x264_cabac_block_residual_cbf( h, cb, DCT_CHROMA_AC, 18+offset, h->dct.luma4x4[18+offset]+1, 0 ); + x264_cabac_block_residual_cbf( h, cb, DCT_CHROMA_AC, 32+offset, h->dct.luma4x4[32+offset]+1, 0 ); + x264_cabac_block_residual_cbf( h, cb, DCT_CHROMA_AC, 34+offset, h->dct.luma4x4[34+offset]+1, 0 ); + } + else + { + x264_cabac_block_residual_cbf( h, cb, DCT_CHROMA_AC, 16+i8, h->dct.luma4x4[16+i8]+1, 0 ); + x264_cabac_block_residual_cbf( h, cb, DCT_CHROMA_AC, 32+i8, h->dct.luma4x4[32+i8]+1, 0 ); + } + } + + i8 += x264_pixel_size[i_pixel].h >> 3; + } +} + +static void x264_subpartition_size_cabac( x264_t *h, x264_cabac_t *cb, int i4, int i_pixel ) +{ + int b_8x4 = i_pixel == PIXEL_8x4; + int plane_count = CHROMA444 ? 3 : 1; + if( i_pixel == PIXEL_4x4 ) + x264_cabac_mvd( h, cb, 0, i4, 1, 1 ); + else + x264_cabac_mvd( h, cb, 0, i4, 1+b_8x4, 2-b_8x4 ); + for( int p = 0; p < plane_count; p++ ) + { + x264_cabac_block_residual_cbf( h, cb, ctx_cat_plane[DCT_LUMA_4x4][p], p*16+i4, h->dct.luma4x4[p*16+i4], 0 ); + if( i_pixel != PIXEL_4x4 ) + x264_cabac_block_residual_cbf( h, cb, ctx_cat_plane[DCT_LUMA_4x4][p], p*16+i4+2-b_8x4, h->dct.luma4x4[p*16+i4+2-b_8x4], 0 ); + } +} + +static void x264_partition_i8x8_size_cabac( x264_t *h, x264_cabac_t *cb, int i8, int i_mode ) +{ + const int i_pred = x264_mb_predict_intra4x4_mode( h, 4*i8 ); + i_mode = x264_mb_pred_mode4x4_fix( i_mode ); + x264_cabac_intra4x4_pred_mode( cb, i_pred, i_mode ); + x264_cabac_cbp_luma( h, cb ); + if( h->mb.i_cbp_luma & (1 << i8) ) + { + if( CHROMA444 ) + for( int p = 0; p < 3; p++ ) + x264_cabac_block_residual_8x8_cbf( h, cb, ctx_cat_plane[DCT_LUMA_8x8][p], i8*4+p*16, h->dct.luma8x8[i8+p*4], 1 ); + else + x264_cabac_block_residual_8x8( h, cb, DCT_LUMA_8x8, h->dct.luma8x8[i8] ); + } +} + +static void x264_partition_i4x4_size_cabac( x264_t *h, x264_cabac_t *cb, int i4, int i_mode ) +{ + const int i_pred = x264_mb_predict_intra4x4_mode( h, i4 ); + int plane_count = CHROMA444 ? 3 : 1; + i_mode = x264_mb_pred_mode4x4_fix( i_mode ); + x264_cabac_intra4x4_pred_mode( cb, i_pred, i_mode ); + for( int p = 0; p < plane_count; p++ ) + x264_cabac_block_residual_cbf( h, cb, ctx_cat_plane[DCT_LUMA_4x4][p], i4+p*16, h->dct.luma4x4[i4+p*16], 1 ); +} + +static void x264_chroma_size_cabac( x264_t *h, x264_cabac_t *cb ) +{ + x264_cabac_intra_chroma_pred_mode( h, cb ); + x264_cabac_cbp_chroma( h, cb ); + if( h->mb.i_cbp_chroma ) + { + if( CHROMA_FORMAT == CHROMA_422 ) + { + x264_cabac_block_residual_422_dc_cbf( h, cb, 0, 1 ); + x264_cabac_block_residual_422_dc_cbf( h, cb, 1, 1 ); + } + else + { + x264_cabac_block_residual_dc_cbf( h, cb, DCT_CHROMA_DC, CHROMA_DC+0, h->dct.chroma_dc[0], 1 ); + x264_cabac_block_residual_dc_cbf( h, cb, DCT_CHROMA_DC, CHROMA_DC+1, h->dct.chroma_dc[1], 1 ); + } + + if( h->mb.i_cbp_chroma == 2 ) + { + int step = 8 << CHROMA_V_SHIFT; + for( int i = 16; i < 3*16; i += step ) + for( int j = i; j < i+4; j++ ) + x264_cabac_block_residual_cbf( h, cb, DCT_CHROMA_AC, j, h->dct.luma4x4[j]+1, 1 ); + } + } +} +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/cavlc.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/cavlc.c new file mode 100644 index 00000000..0150b246 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/cavlc.c @@ -0,0 +1,722 @@ +/***************************************************************************** + * cavlc.c: cavlc bitstream writing + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "macroblock.h" + +#ifndef RDO_SKIP_BS +#define RDO_SKIP_BS 0 +#endif + +/* [400,420][inter,intra] */ +static const uint8_t cbp_to_golomb[2][2][48] = +{ + {{ 0, 1, 2, 5, 3, 6, 14, 10, 4, 15, 7, 11, 8, 12, 13, 9 }, + { 1, 10, 11, 6, 12, 7, 14, 2, 13, 15, 8, 3, 9, 4, 5, 0 }}, + {{ 0, 2, 3, 7, 4, 8, 17, 13, 5, 18, 9, 14, 10, 15, 16, 11, + 1, 32, 33, 36, 34, 37, 44, 40, 35, 45, 38, 41, 39, 42, 43, 19, + 6, 24, 25, 20, 26, 21, 46, 28, 27, 47, 22, 29, 23, 30, 31, 12 }, + { 3, 29, 30, 17, 31, 18, 37, 8, 32, 38, 19, 9, 20, 10, 11, 2, + 16, 33, 34, 21, 35, 22, 39, 4, 36, 40, 23, 5, 24, 6, 7, 1, + 41, 42, 43, 25, 44, 26, 46, 12, 45, 47, 27, 13, 28, 14, 15, 0 }} +}; + +static const uint8_t mb_type_b_to_golomb[3][9]= +{ + { 4, 8, 12, 10, 6, 14, 16, 18, 20 }, /* D_16x8 */ + { 5, 9, 13, 11, 7, 15, 17, 19, 21 }, /* D_8x16 */ + { 1, -1, -1, -1, 2, -1, -1, -1, 3 } /* D_16x16 */ +}; + +static const uint8_t subpartition_p_to_golomb[4]= +{ + 3, 1, 2, 0 +}; + +static const uint8_t subpartition_b_to_golomb[13]= +{ + 10, 4, 5, 1, 11, 6, 7, 2, 12, 8, 9, 3, 0 +}; + +#define bs_write_vlc(s,v) bs_write( s, (v).i_size, (v).i_bits ) + +/**************************************************************************** + * x264_cavlc_block_residual: + ****************************************************************************/ +static inline int x264_cavlc_block_residual_escape( x264_t *h, int i_suffix_length, int level ) +{ + bs_t *s = &h->out.bs; + static const uint16_t next_suffix[7] = { 0, 3, 6, 12, 24, 48, 0xffff }; + int i_level_prefix = 15; + int mask = level >> 31; + int abs_level = (level^mask)-mask; + int i_level_code = abs_level*2-mask-2; + if( ( i_level_code >> i_suffix_length ) < 15 ) + { + bs_write( s, (i_level_code >> i_suffix_length) + 1 + i_suffix_length, + (1<= 1<<12 ) + { + if( h->sps->i_profile_idc >= PROFILE_HIGH ) + { + while( i_level_code > 1<<(i_level_prefix-3) ) + { + i_level_code -= 1<<(i_level_prefix-3); + i_level_prefix++; + } + } + else + { +#if RDO_SKIP_BS + /* Weight highly against overflows. */ + s->i_bits_encoded += 2000; +#else + /* We've had an overflow; note it down and re-encode the MB later. */ + h->mb.b_overflow = 1; +#endif + } + } + bs_write( s, i_level_prefix + 1, 1 ); + bs_write( s, i_level_prefix - 3, i_level_code & ((1<<(i_level_prefix-3))-1) ); + } + if( i_suffix_length == 0 ) + i_suffix_length++; + if( abs_level > next_suffix[i_suffix_length] ) + i_suffix_length++; + return i_suffix_length; +} + +static int x264_cavlc_block_residual_internal( x264_t *h, int ctx_block_cat, dctcoef *l, int nC ) +{ + bs_t *s = &h->out.bs; + static const uint8_t ctz_index[8] = {3,0,1,0,2,0,1,0}; + static const uint8_t count_cat[14] = {16, 15, 16, 0, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64}; + x264_run_level_t runlevel; + int i_total, i_trailing, i_total_zero, i_suffix_length; + unsigned int i_sign; + + /* level and run and total */ + i_total = h->quantf.coeff_level_run[ctx_block_cat]( l, &runlevel ); + x264_prefetch( &x264_run_before[runlevel.mask] ); + i_total_zero = runlevel.last + 1 - i_total; + + /* branchless i_trailing calculation */ + runlevel.level[i_total+0] = 2; + runlevel.level[i_total+1] = 2; + i_trailing = ((((runlevel.level[0]+1) | (1-runlevel.level[0])) >> 31) & 1) // abs(runlevel.level[0])>1 + | ((((runlevel.level[1]+1) | (1-runlevel.level[1])) >> 31) & 2) + | ((((runlevel.level[2]+1) | (1-runlevel.level[2])) >> 31) & 4); + i_trailing = ctz_index[i_trailing]; + i_sign = ((runlevel.level[2] >> 31) & 1) + | ((runlevel.level[1] >> 31) & 2) + | ((runlevel.level[0] >> 31) & 4); + i_sign >>= 3-i_trailing; + + /* total/trailing */ + bs_write_vlc( s, x264_coeff_token[nC][i_total-1][i_trailing] ); + + i_suffix_length = i_total > 10 && i_trailing < 3; + bs_write( s, i_trailing, i_sign ); + + if( i_trailing < i_total ) + { + int val = runlevel.level[i_trailing]; + int val_original = runlevel.level[i_trailing]+LEVEL_TABLE_SIZE/2; + val -= ((val>>31)|1) & -(i_trailing < 3); /* as runlevel.level[i] can't be 1 for the first one if i_trailing < 3 */ + val += LEVEL_TABLE_SIZE/2; + + if( (unsigned)val_original < LEVEL_TABLE_SIZE ) + { + bs_write_vlc( s, x264_level_token[i_suffix_length][val] ); + i_suffix_length = x264_level_token[i_suffix_length][val_original].i_next; + } + else + i_suffix_length = x264_cavlc_block_residual_escape( h, i_suffix_length, val-LEVEL_TABLE_SIZE/2 ); + for( int i = i_trailing+1; i < i_total; i++ ) + { + val = runlevel.level[i] + LEVEL_TABLE_SIZE/2; + if( (unsigned)val < LEVEL_TABLE_SIZE ) + { + bs_write_vlc( s, x264_level_token[i_suffix_length][val] ); + i_suffix_length = x264_level_token[i_suffix_length][val].i_next; + } + else + i_suffix_length = x264_cavlc_block_residual_escape( h, i_suffix_length, val-LEVEL_TABLE_SIZE/2 ); + } + } + + if( ctx_block_cat == DCT_CHROMA_DC ) + { + if( i_total < 8>>CHROMA_V_SHIFT ) + { + vlc_t total_zeros = CHROMA_FORMAT == CHROMA_420 ? x264_total_zeros_2x2_dc[i_total-1][i_total_zero] + : x264_total_zeros_2x4_dc[i_total-1][i_total_zero]; + bs_write_vlc( s, total_zeros ); + } + } + else if( (uint8_t)i_total < count_cat[ctx_block_cat] ) + bs_write_vlc( s, x264_total_zeros[i_total-1][i_total_zero] ); + + int zero_run_code = x264_run_before[runlevel.mask]; + bs_write( s, zero_run_code&0x1f, zero_run_code>>5 ); + + return i_total; +} + +static const uint8_t ct_index[17] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,3}; + +#define x264_cavlc_block_residual(h,cat,idx,l)\ +{\ + int nC = cat == DCT_CHROMA_DC ? 5 - CHROMA_V_SHIFT\ + : ct_index[x264_mb_predict_non_zero_code( h, cat == DCT_LUMA_DC ? (idx - LUMA_DC)*16 : idx )];\ + uint8_t *nnz = &h->mb.cache.non_zero_count[x264_scan8[idx]];\ + if( !*nnz )\ + bs_write_vlc( &h->out.bs, x264_coeff0_token[nC] );\ + else\ + *nnz = x264_cavlc_block_residual_internal(h,cat,l,nC);\ +} + +static void x264_cavlc_qp_delta( x264_t *h ) +{ + bs_t *s = &h->out.bs; + int i_dqp = h->mb.i_qp - h->mb.i_last_qp; + + /* Avoid writing a delta quant if we have an empty i16x16 block, e.g. in a completely + * flat background area. Don't do this if it would raise the quantizer, since that could + * cause unexpected deblocking artifacts. */ + if( h->mb.i_type == I_16x16 && !(h->mb.i_cbp_luma | h->mb.i_cbp_chroma) + && !h->mb.cache.non_zero_count[x264_scan8[LUMA_DC]] + && !h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]] + && !h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]] + && h->mb.i_qp > h->mb.i_last_qp ) + { +#if !RDO_SKIP_BS + h->mb.i_qp = h->mb.i_last_qp; +#endif + i_dqp = 0; + } + + if( i_dqp ) + { + if( i_dqp < -(QP_MAX_SPEC+1)/2 ) + i_dqp += QP_MAX_SPEC+1; + else if( i_dqp > QP_MAX_SPEC/2 ) + i_dqp -= QP_MAX_SPEC+1; + } + bs_write_se( s, i_dqp ); +} + +static void x264_cavlc_mvd( x264_t *h, int i_list, int idx, int width ) +{ + bs_t *s = &h->out.bs; + ALIGNED_4( int16_t mvp[2] ); + x264_mb_predict_mv( h, i_list, idx, width, mvp ); + bs_write_se( s, h->mb.cache.mv[i_list][x264_scan8[idx]][0] - mvp[0] ); + bs_write_se( s, h->mb.cache.mv[i_list][x264_scan8[idx]][1] - mvp[1] ); +} + +static inline void x264_cavlc_8x8_mvd( x264_t *h, int i ) +{ + switch( h->mb.i_sub_partition[i] ) + { + case D_L0_8x8: + x264_cavlc_mvd( h, 0, 4*i, 2 ); + break; + case D_L0_8x4: + x264_cavlc_mvd( h, 0, 4*i+0, 2 ); + x264_cavlc_mvd( h, 0, 4*i+2, 2 ); + break; + case D_L0_4x8: + x264_cavlc_mvd( h, 0, 4*i+0, 1 ); + x264_cavlc_mvd( h, 0, 4*i+1, 1 ); + break; + case D_L0_4x4: + x264_cavlc_mvd( h, 0, 4*i+0, 1 ); + x264_cavlc_mvd( h, 0, 4*i+1, 1 ); + x264_cavlc_mvd( h, 0, 4*i+2, 1 ); + x264_cavlc_mvd( h, 0, 4*i+3, 1 ); + break; + } +} + +static ALWAYS_INLINE void x264_cavlc_macroblock_luma_residual( x264_t *h, int plane_count ) +{ + if( h->mb.b_transform_8x8 ) + { + /* shuffle 8x8 dct coeffs into 4x4 lists */ + for( int p = 0; p < plane_count; p++ ) + for( int i8 = 0; i8 < 4; i8++ ) + if( h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4]] ) + h->zigzagf.interleave_8x8_cavlc( h->dct.luma4x4[p*16+i8*4], h->dct.luma8x8[p*4+i8], + &h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4]] ); + } + + for( int p = 0; p < plane_count; p++ ) + FOREACH_BIT( i8, 0, h->mb.i_cbp_luma ) + for( int i4 = 0; i4 < 4; i4++ ) + x264_cavlc_block_residual( h, DCT_LUMA_4x4, i4+i8*4+p*16, h->dct.luma4x4[i4+i8*4+p*16] ); +} + +#if RDO_SKIP_BS +static ALWAYS_INLINE void x264_cavlc_partition_luma_residual( x264_t *h, int i8, int p ) +{ + if( h->mb.b_transform_8x8 && h->mb.cache.non_zero_count[x264_scan8[i8*4]] ) + h->zigzagf.interleave_8x8_cavlc( h->dct.luma4x4[i8*4+p*16], h->dct.luma8x8[i8+p*4], + &h->mb.cache.non_zero_count[x264_scan8[i8*4+p*16]] ); + + if( h->mb.i_cbp_luma & (1 << i8) ) + for( int i4 = 0; i4 < 4; i4++ ) + x264_cavlc_block_residual( h, DCT_LUMA_4x4, i4+i8*4+p*16, h->dct.luma4x4[i4+i8*4+p*16] ); +} +#endif + +static void x264_cavlc_mb_header_i( x264_t *h, int i_mb_type, int i_mb_i_offset, int chroma ) +{ + bs_t *s = &h->out.bs; + if( i_mb_type == I_16x16 ) + { + bs_write_ue( s, i_mb_i_offset + 1 + x264_mb_pred_mode16x16_fix[h->mb.i_intra16x16_pred_mode] + + h->mb.i_cbp_chroma * 4 + ( h->mb.i_cbp_luma == 0 ? 0 : 12 ) ); + } + else //if( i_mb_type == I_4x4 || i_mb_type == I_8x8 ) + { + int di = i_mb_type == I_8x8 ? 4 : 1; + bs_write_ue( s, i_mb_i_offset + 0 ); + if( h->pps->b_transform_8x8_mode ) + bs_write1( s, h->mb.b_transform_8x8 ); + + /* Prediction: Luma */ + for( int i = 0; i < 16; i += di ) + { + int i_pred = x264_mb_predict_intra4x4_mode( h, i ); + int i_mode = x264_mb_pred_mode4x4_fix( h->mb.cache.intra4x4_pred_mode[x264_scan8[i]] ); + + if( i_pred == i_mode ) + bs_write1( s, 1 ); /* b_prev_intra4x4_pred_mode */ + else + bs_write( s, 4, i_mode - (i_mode > i_pred) ); + } + + } + if( chroma ) + bs_write_ue( s, x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode] ); +} + +static ALWAYS_INLINE void x264_cavlc_mb_header_p( x264_t *h, int i_mb_type, int chroma ) +{ + bs_t *s = &h->out.bs; + if( i_mb_type == P_L0 ) + { + if( h->mb.i_partition == D_16x16 ) + { + bs_write1( s, 1 ); + + if( h->mb.pic.i_fref[0] > 1 ) + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[0]] ); + x264_cavlc_mvd( h, 0, 0, 4 ); + } + else if( h->mb.i_partition == D_16x8 ) + { + bs_write_ue( s, 1 ); + if( h->mb.pic.i_fref[0] > 1 ) + { + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[0]] ); + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[8]] ); + } + x264_cavlc_mvd( h, 0, 0, 4 ); + x264_cavlc_mvd( h, 0, 8, 4 ); + } + else if( h->mb.i_partition == D_8x16 ) + { + bs_write_ue( s, 2 ); + if( h->mb.pic.i_fref[0] > 1 ) + { + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[0]] ); + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[4]] ); + } + x264_cavlc_mvd( h, 0, 0, 2 ); + x264_cavlc_mvd( h, 0, 4, 2 ); + } + } + else if( i_mb_type == P_8x8 ) + { + int b_sub_ref; + if( (h->mb.cache.ref[0][x264_scan8[0]] | h->mb.cache.ref[0][x264_scan8[ 4]] | + h->mb.cache.ref[0][x264_scan8[8]] | h->mb.cache.ref[0][x264_scan8[12]]) == 0 ) + { + bs_write_ue( s, 4 ); + b_sub_ref = 0; + } + else + { + bs_write_ue( s, 3 ); + b_sub_ref = 1; + } + + /* sub mb type */ + if( h->param.analyse.inter & X264_ANALYSE_PSUB8x8 ) + for( int i = 0; i < 4; i++ ) + bs_write_ue( s, subpartition_p_to_golomb[ h->mb.i_sub_partition[i] ] ); + else + bs_write( s, 4, 0xf ); + + /* ref0 */ + if( b_sub_ref ) + { + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[0]] ); + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[4]] ); + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[8]] ); + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[12]] ); + } + + for( int i = 0; i < 4; i++ ) + x264_cavlc_8x8_mvd( h, i ); + } + else //if( IS_INTRA( i_mb_type ) ) + x264_cavlc_mb_header_i( h, i_mb_type, 5, chroma ); +} + +static ALWAYS_INLINE void x264_cavlc_mb_header_b( x264_t *h, int i_mb_type, int chroma ) +{ + bs_t *s = &h->out.bs; + if( i_mb_type == B_8x8 ) + { + bs_write_ue( s, 22 ); + + /* sub mb type */ + for( int i = 0; i < 4; i++ ) + bs_write_ue( s, subpartition_b_to_golomb[ h->mb.i_sub_partition[i] ] ); + + /* ref */ + if( h->mb.pic.i_fref[0] > 1 ) + for( int i = 0; i < 4; i++ ) + if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i] ] ) + bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[i*4]] ); + if( h->mb.pic.i_fref[1] > 1 ) + for( int i = 0; i < 4; i++ ) + if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i] ] ) + bs_write_te( s, h->mb.pic.i_fref[1] - 1, h->mb.cache.ref[1][x264_scan8[i*4]] ); + + /* mvd */ + for( int i = 0; i < 4; i++ ) + if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i] ] ) + x264_cavlc_mvd( h, 0, 4*i, 2 ); + for( int i = 0; i < 4; i++ ) + if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i] ] ) + x264_cavlc_mvd( h, 1, 4*i, 2 ); + } + else if( i_mb_type >= B_L0_L0 && i_mb_type <= B_BI_BI ) + { + /* All B mode */ + /* Motion Vector */ + const uint8_t (*b_list)[2] = x264_mb_type_list_table[i_mb_type]; + const int i_ref0_max = h->mb.pic.i_fref[0] - 1; + const int i_ref1_max = h->mb.pic.i_fref[1] - 1; + + bs_write_ue( s, mb_type_b_to_golomb[ h->mb.i_partition - D_16x8 ][ i_mb_type - B_L0_L0 ] ); + if( h->mb.i_partition == D_16x16 ) + { + if( i_ref0_max && b_list[0][0] ) bs_write_te( s, i_ref0_max, h->mb.cache.ref[0][x264_scan8[0]] ); + if( i_ref1_max && b_list[1][0] ) bs_write_te( s, i_ref1_max, h->mb.cache.ref[1][x264_scan8[0]] ); + if( b_list[0][0] ) x264_cavlc_mvd( h, 0, 0, 4 ); + if( b_list[1][0] ) x264_cavlc_mvd( h, 1, 0, 4 ); + } + else + { + if( i_ref0_max && b_list[0][0] ) bs_write_te( s, i_ref0_max, h->mb.cache.ref[0][x264_scan8[ 0]] ); + if( i_ref0_max && b_list[0][1] ) bs_write_te( s, i_ref0_max, h->mb.cache.ref[0][x264_scan8[12]] ); + if( i_ref1_max && b_list[1][0] ) bs_write_te( s, i_ref1_max, h->mb.cache.ref[1][x264_scan8[ 0]] ); + if( i_ref1_max && b_list[1][1] ) bs_write_te( s, i_ref1_max, h->mb.cache.ref[1][x264_scan8[12]] ); + if( h->mb.i_partition == D_16x8 ) + { + if( b_list[0][0] ) x264_cavlc_mvd( h, 0, 0, 4 ); + if( b_list[0][1] ) x264_cavlc_mvd( h, 0, 8, 4 ); + if( b_list[1][0] ) x264_cavlc_mvd( h, 1, 0, 4 ); + if( b_list[1][1] ) x264_cavlc_mvd( h, 1, 8, 4 ); + } + else //if( h->mb.i_partition == D_8x16 ) + { + if( b_list[0][0] ) x264_cavlc_mvd( h, 0, 0, 2 ); + if( b_list[0][1] ) x264_cavlc_mvd( h, 0, 4, 2 ); + if( b_list[1][0] ) x264_cavlc_mvd( h, 1, 0, 2 ); + if( b_list[1][1] ) x264_cavlc_mvd( h, 1, 4, 2 ); + } + } + } + else if( i_mb_type == B_DIRECT ) + bs_write1( s, 1 ); + else //if( IS_INTRA( i_mb_type ) ) + x264_cavlc_mb_header_i( h, i_mb_type, 23, chroma ); +} + +/***************************************************************************** + * x264_macroblock_write: + *****************************************************************************/ +void x264_macroblock_write_cavlc( x264_t *h ) +{ + bs_t *s = &h->out.bs; + const int i_mb_type = h->mb.i_type; + int plane_count = CHROMA444 ? 3 : 1; + int chroma = !CHROMA444; + +#if RDO_SKIP_BS + s->i_bits_encoded = 0; +#else + const int i_mb_pos_start = bs_pos( s ); + int i_mb_pos_tex; +#endif + + if( SLICE_MBAFF + && (!(h->mb.i_mb_y & 1) || IS_SKIP(h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride])) ) + { + bs_write1( s, MB_INTERLACED ); +#if !RDO_SKIP_BS + h->mb.field_decoding_flag = MB_INTERLACED; +#endif + } + +#if !RDO_SKIP_BS + if( i_mb_type == I_PCM ) + { + static const uint8_t i_offsets[3] = {5,23,0}; + uint8_t *p_start = s->p_start; + bs_write_ue( s, i_offsets[h->sh.i_type] + 25 ); + i_mb_pos_tex = bs_pos( s ); + h->stat.frame.i_mv_bits += i_mb_pos_tex - i_mb_pos_start; + + bs_align_0( s ); + + for( int p = 0; p < plane_count; p++ ) + for( int i = 0; i < 256; i++ ) + bs_write( s, BIT_DEPTH, h->mb.pic.p_fenc[p][i] ); + if( chroma ) + for( int ch = 1; ch < 3; ch++ ) + for( int i = 0; i < 16>>CHROMA_V_SHIFT; i++ ) + for( int j = 0; j < 8; j++ ) + bs_write( s, BIT_DEPTH, h->mb.pic.p_fenc[ch][i*FENC_STRIDE+j] ); + + bs_init( s, s->p, s->p_end - s->p ); + s->p_start = p_start; + + h->stat.frame.i_tex_bits += bs_pos(s) - i_mb_pos_tex; + return; + } +#endif + + if( h->sh.i_type == SLICE_TYPE_P ) + x264_cavlc_mb_header_p( h, i_mb_type, chroma ); + else if( h->sh.i_type == SLICE_TYPE_B ) + x264_cavlc_mb_header_b( h, i_mb_type, chroma ); + else //if( h->sh.i_type == SLICE_TYPE_I ) + x264_cavlc_mb_header_i( h, i_mb_type, 0, chroma ); + +#if !RDO_SKIP_BS + i_mb_pos_tex = bs_pos( s ); + h->stat.frame.i_mv_bits += i_mb_pos_tex - i_mb_pos_start; +#endif + + /* Coded block pattern */ + if( i_mb_type != I_16x16 ) + bs_write_ue( s, cbp_to_golomb[chroma][IS_INTRA(i_mb_type)][(h->mb.i_cbp_chroma << 4)|h->mb.i_cbp_luma] ); + + /* transform size 8x8 flag */ + if( x264_mb_transform_8x8_allowed( h ) && h->mb.i_cbp_luma ) + bs_write1( s, h->mb.b_transform_8x8 ); + + if( i_mb_type == I_16x16 ) + { + x264_cavlc_qp_delta( h ); + + /* DC Luma */ + for( int p = 0; p < plane_count; p++ ) + { + x264_cavlc_block_residual( h, DCT_LUMA_DC, LUMA_DC+p, h->dct.luma16x16_dc[p] ); + + /* AC Luma */ + if( h->mb.i_cbp_luma ) + for( int i = p*16; i < p*16+16; i++ ) + x264_cavlc_block_residual( h, DCT_LUMA_AC, i, h->dct.luma4x4[i]+1 ); + } + } + else if( h->mb.i_cbp_luma | h->mb.i_cbp_chroma ) + { + x264_cavlc_qp_delta( h ); + x264_cavlc_macroblock_luma_residual( h, plane_count ); + } + if( h->mb.i_cbp_chroma ) + { + /* Chroma DC residual present */ + x264_cavlc_block_residual( h, DCT_CHROMA_DC, CHROMA_DC+0, h->dct.chroma_dc[0] ); + x264_cavlc_block_residual( h, DCT_CHROMA_DC, CHROMA_DC+1, h->dct.chroma_dc[1] ); + if( h->mb.i_cbp_chroma == 2 ) /* Chroma AC residual present */ + { + int step = 8 << CHROMA_V_SHIFT; + for( int i = 16; i < 3*16; i += step ) + for( int j = i; j < i+4; j++ ) + x264_cavlc_block_residual( h, DCT_CHROMA_AC, j, h->dct.luma4x4[j]+1 ); + } + } + +#if !RDO_SKIP_BS + h->stat.frame.i_tex_bits += bs_pos(s) - i_mb_pos_tex; +#endif +} + +#if RDO_SKIP_BS +/***************************************************************************** + * RD only; doesn't generate a valid bitstream + * doesn't write cbp or chroma dc (I don't know how much this matters) + * doesn't write ref (never varies between calls, so no point in doing so) + * only writes subpartition for p8x8, needed for sub-8x8 mode decision RDO + * works on all partition sizes except 16x16 + *****************************************************************************/ +static int x264_partition_size_cavlc( x264_t *h, int i8, int i_pixel ) +{ + bs_t *s = &h->out.bs; + const int i_mb_type = h->mb.i_type; + int b_8x16 = h->mb.i_partition == D_8x16; + int plane_count = CHROMA444 ? 3 : 1; + int j; + + h->out.bs.i_bits_encoded = 0; + + if( i_mb_type == P_8x8 ) + { + x264_cavlc_8x8_mvd( h, i8 ); + bs_write_ue( s, subpartition_p_to_golomb[ h->mb.i_sub_partition[i8] ] ); + } + else if( i_mb_type == P_L0 ) + x264_cavlc_mvd( h, 0, 4*i8, 4>>b_8x16 ); + else if( i_mb_type > B_DIRECT && i_mb_type < B_8x8 ) + { + if( x264_mb_type_list_table[ i_mb_type ][0][!!i8] ) x264_cavlc_mvd( h, 0, 4*i8, 4>>b_8x16 ); + if( x264_mb_type_list_table[ i_mb_type ][1][!!i8] ) x264_cavlc_mvd( h, 1, 4*i8, 4>>b_8x16 ); + } + else //if( i_mb_type == B_8x8 ) + { + if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i8] ] ) + x264_cavlc_mvd( h, 0, 4*i8, 2 ); + if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i8] ] ) + x264_cavlc_mvd( h, 1, 4*i8, 2 ); + } + + for( j = (i_pixel < PIXEL_8x8); j >= 0; j-- ) + { + for( int p = 0; p < plane_count; p++ ) + x264_cavlc_partition_luma_residual( h, i8, p ); + if( h->mb.i_cbp_chroma ) + { + if( CHROMA_FORMAT == CHROMA_422 ) + { + int offset = (5*i8) & 0x09; + x264_cavlc_block_residual( h, DCT_CHROMA_AC, 16+offset, h->dct.luma4x4[16+offset]+1 ); + x264_cavlc_block_residual( h, DCT_CHROMA_AC, 18+offset, h->dct.luma4x4[18+offset]+1 ); + x264_cavlc_block_residual( h, DCT_CHROMA_AC, 32+offset, h->dct.luma4x4[32+offset]+1 ); + x264_cavlc_block_residual( h, DCT_CHROMA_AC, 34+offset, h->dct.luma4x4[34+offset]+1 ); + } + else + { + x264_cavlc_block_residual( h, DCT_CHROMA_AC, 16+i8, h->dct.luma4x4[16+i8]+1 ); + x264_cavlc_block_residual( h, DCT_CHROMA_AC, 32+i8, h->dct.luma4x4[32+i8]+1 ); + } + } + i8 += x264_pixel_size[i_pixel].h >> 3; + } + + return h->out.bs.i_bits_encoded; +} + +static int x264_subpartition_size_cavlc( x264_t *h, int i4, int i_pixel ) +{ + int plane_count = CHROMA444 ? 3 : 1; + int b_8x4 = i_pixel == PIXEL_8x4; + h->out.bs.i_bits_encoded = 0; + x264_cavlc_mvd( h, 0, i4, 1+b_8x4 ); + for( int p = 0; p < plane_count; p++ ) + { + x264_cavlc_block_residual( h, DCT_LUMA_4x4, p*16+i4, h->dct.luma4x4[p*16+i4] ); + if( i_pixel != PIXEL_4x4 ) + x264_cavlc_block_residual( h, DCT_LUMA_4x4, p*16+i4+2-b_8x4, h->dct.luma4x4[p*16+i4+2-b_8x4] ); + } + + return h->out.bs.i_bits_encoded; +} + +static int x264_cavlc_intra4x4_pred_size( x264_t *h, int i4, int i_mode ) +{ + if( x264_mb_predict_intra4x4_mode( h, i4 ) == x264_mb_pred_mode4x4_fix( i_mode ) ) + return 1; + else + return 4; +} + +static int x264_partition_i8x8_size_cavlc( x264_t *h, int i8, int i_mode ) +{ + int plane_count = CHROMA444 ? 3 : 1; + h->out.bs.i_bits_encoded = x264_cavlc_intra4x4_pred_size( h, 4*i8, i_mode ); + bs_write_ue( &h->out.bs, cbp_to_golomb[!CHROMA444][1][(h->mb.i_cbp_chroma << 4)|h->mb.i_cbp_luma] ); + for( int p = 0; p < plane_count; p++ ) + x264_cavlc_partition_luma_residual( h, i8, p ); + return h->out.bs.i_bits_encoded; +} + +static int x264_partition_i4x4_size_cavlc( x264_t *h, int i4, int i_mode ) +{ + int plane_count = CHROMA444 ? 3 : 1; + h->out.bs.i_bits_encoded = x264_cavlc_intra4x4_pred_size( h, i4, i_mode ); + for( int p = 0; p < plane_count; p++ ) + x264_cavlc_block_residual( h, DCT_LUMA_4x4, p*16+i4, h->dct.luma4x4[p*16+i4] ); + return h->out.bs.i_bits_encoded; +} + +static int x264_chroma_size_cavlc( x264_t *h ) +{ + h->out.bs.i_bits_encoded = bs_size_ue( x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode] ); + if( h->mb.i_cbp_chroma ) + { + x264_cavlc_block_residual( h, DCT_CHROMA_DC, CHROMA_DC+0, h->dct.chroma_dc[0] ); + x264_cavlc_block_residual( h, DCT_CHROMA_DC, CHROMA_DC+1, h->dct.chroma_dc[1] ); + + if( h->mb.i_cbp_chroma == 2 ) + { + int step = 8 << CHROMA_V_SHIFT; + for( int i = 16; i < 3*16; i += step ) + for( int j = i; j < i+4; j++ ) + x264_cavlc_block_residual( h, DCT_CHROMA_AC, j, h->dct.luma4x4[j]+1 ); + } + } + return h->out.bs.i_bits_encoded; +} +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/encoder.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/encoder.c new file mode 100644 index 00000000..d183460c --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/encoder.c @@ -0,0 +1,4429 @@ +/***************************************************************************** + * encoder.c: top-level encoder functions + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" + +#include "set.h" +#include "analyse.h" +#include "ratecontrol.h" +#include "macroblock.h" +#include "me.h" +#if HAVE_INTEL_DISPATCHER +#include "extras/intel_dispatcher.h" +#endif + +//#define DEBUG_MB_TYPE + +#define bs_write_ue bs_write_ue_big + +static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, + x264_nal_t **pp_nal, int *pi_nal, + x264_picture_t *pic_out ); + +/**************************************************************************** + * + ******************************* x264 libs ********************************** + * + ****************************************************************************/ +static double x264_psnr( double sqe, double size ) +{ + double mse = sqe / (PIXEL_MAX*PIXEL_MAX * size); + if( mse <= 0.0000000001 ) /* Max 100dB */ + return 100; + + return -10.0 * log10( mse ); +} + +static double x264_ssim( double ssim ) +{ + double inv_ssim = 1 - ssim; + if( inv_ssim <= 0.0000000001 ) /* Max 100dB */ + return 100; + + return -10.0 * log10( inv_ssim ); +} + +static int x264_threadpool_wait_all( x264_t *h ) +{ + for( int i = 0; i < h->param.i_threads; i++ ) + if( h->thread[i]->b_thread_active ) + { + h->thread[i]->b_thread_active = 0; + if( (intptr_t)x264_threadpool_wait( h->threadpool, h->thread[i] ) < 0 ) + return -1; + } + return 0; +} + +static void x264_frame_dump( x264_t *h ) +{ + FILE *f = x264_fopen( h->param.psz_dump_yuv, "r+b" ); + if( !f ) + return; + + /* Wait for the threads to finish deblocking */ + if( h->param.b_sliced_threads ) + x264_threadpool_wait_all( h ); + + /* Write the frame in display order */ + int frame_size = FRAME_SIZE( h->param.i_height * h->param.i_width * sizeof(pixel) ); + if( !fseek( f, (int64_t)h->fdec->i_frame * frame_size, SEEK_SET ) ) + { + for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ ) + for( int y = 0; y < h->param.i_height; y++ ) + fwrite( &h->fdec->plane[p][y*h->fdec->i_stride[p]], sizeof(pixel), h->param.i_width, f ); + if( !CHROMA444 ) + { + int cw = h->param.i_width>>1; + int ch = h->param.i_height>>CHROMA_V_SHIFT; + pixel *planeu = x264_malloc( 2 * (cw*ch*sizeof(pixel) + 32) ); + if( planeu ) + { + pixel *planev = planeu + cw*ch + 32/sizeof(pixel); + h->mc.plane_copy_deinterleave( planeu, cw, planev, cw, h->fdec->plane[1], h->fdec->i_stride[1], cw, ch ); + fwrite( planeu, 1, cw*ch*sizeof(pixel), f ); + fwrite( planev, 1, cw*ch*sizeof(pixel), f ); + x264_free( planeu ); + } + } + } + fclose( f ); +} + +/* Fill "default" values */ +static void x264_slice_header_init( x264_t *h, x264_slice_header_t *sh, + x264_sps_t *sps, x264_pps_t *pps, + int i_idr_pic_id, int i_frame, int i_qp ) +{ + x264_param_t *param = &h->param; + + /* First we fill all fields */ + sh->sps = sps; + sh->pps = pps; + + sh->i_first_mb = 0; + sh->i_last_mb = h->mb.i_mb_count - 1; + sh->i_pps_id = pps->i_id; + + sh->i_frame_num = i_frame; + + sh->b_mbaff = PARAM_INTERLACED; + sh->b_field_pic = 0; /* no field support for now */ + sh->b_bottom_field = 0; /* not yet used */ + + sh->i_idr_pic_id = i_idr_pic_id; + + /* poc stuff, fixed later */ + sh->i_poc = 0; + sh->i_delta_poc_bottom = 0; + sh->i_delta_poc[0] = 0; + sh->i_delta_poc[1] = 0; + + sh->i_redundant_pic_cnt = 0; + + h->mb.b_direct_auto_write = h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO + && h->param.i_bframe + && ( h->param.rc.b_stat_write || !h->param.rc.b_stat_read ); + + if( !h->mb.b_direct_auto_read && sh->i_type == SLICE_TYPE_B ) + { + if( h->fref[1][0]->i_poc_l0ref0 == h->fref[0][0]->i_poc ) + { + if( h->mb.b_direct_auto_write ) + sh->b_direct_spatial_mv_pred = ( h->stat.i_direct_score[1] > h->stat.i_direct_score[0] ); + else + sh->b_direct_spatial_mv_pred = ( param->analyse.i_direct_mv_pred == X264_DIRECT_PRED_SPATIAL ); + } + else + { + h->mb.b_direct_auto_write = 0; + sh->b_direct_spatial_mv_pred = 1; + } + } + /* else b_direct_spatial_mv_pred was read from the 2pass statsfile */ + + sh->b_num_ref_idx_override = 0; + sh->i_num_ref_idx_l0_active = 1; + sh->i_num_ref_idx_l1_active = 1; + + sh->b_ref_pic_list_reordering[0] = h->b_ref_reorder[0]; + sh->b_ref_pic_list_reordering[1] = h->b_ref_reorder[1]; + + /* If the ref list isn't in the default order, construct reordering header */ + for( int list = 0; list < 2; list++ ) + { + if( sh->b_ref_pic_list_reordering[list] ) + { + int pred_frame_num = i_frame; + for( int i = 0; i < h->i_ref[list]; i++ ) + { + int diff = h->fref[list][i]->i_frame_num - pred_frame_num; + sh->ref_pic_list_order[list][i].idc = ( diff > 0 ); + sh->ref_pic_list_order[list][i].arg = (abs(diff) - 1) & ((1 << sps->i_log2_max_frame_num) - 1); + pred_frame_num = h->fref[list][i]->i_frame_num; + } + } + } + + sh->i_cabac_init_idc = param->i_cabac_init_idc; + + sh->i_qp = SPEC_QP(i_qp); + sh->i_qp_delta = sh->i_qp - pps->i_pic_init_qp; + sh->b_sp_for_swidth = 0; + sh->i_qs_delta = 0; + + int deblock_thresh = i_qp + 2 * X264_MIN(param->i_deblocking_filter_alphac0, param->i_deblocking_filter_beta); + /* If effective qp <= 15, deblocking would have no effect anyway */ + if( param->b_deblocking_filter && (h->mb.b_variable_qp || 15 < deblock_thresh ) ) + sh->i_disable_deblocking_filter_idc = param->b_sliced_threads ? 2 : 0; + else + sh->i_disable_deblocking_filter_idc = 1; + sh->i_alpha_c0_offset = param->i_deblocking_filter_alphac0 << 1; + sh->i_beta_offset = param->i_deblocking_filter_beta << 1; +} + +static void x264_slice_header_write( bs_t *s, x264_slice_header_t *sh, int i_nal_ref_idc ) +{ + if( sh->b_mbaff ) + { + int first_x = sh->i_first_mb % sh->sps->i_mb_width; + int first_y = sh->i_first_mb / sh->sps->i_mb_width; + assert( (first_y&1) == 0 ); + bs_write_ue( s, (2*first_x + sh->sps->i_mb_width*(first_y&~1) + (first_y&1)) >> 1 ); + } + else + bs_write_ue( s, sh->i_first_mb ); + + bs_write_ue( s, sh->i_type + 5 ); /* same type things */ + bs_write_ue( s, sh->i_pps_id ); + bs_write( s, sh->sps->i_log2_max_frame_num, sh->i_frame_num & ((1<sps->i_log2_max_frame_num)-1) ); + + if( !sh->sps->b_frame_mbs_only ) + { + bs_write1( s, sh->b_field_pic ); + if( sh->b_field_pic ) + bs_write1( s, sh->b_bottom_field ); + } + + if( sh->i_idr_pic_id >= 0 ) /* NAL IDR */ + bs_write_ue( s, sh->i_idr_pic_id ); + + if( sh->sps->i_poc_type == 0 ) + { + bs_write( s, sh->sps->i_log2_max_poc_lsb, sh->i_poc & ((1<sps->i_log2_max_poc_lsb)-1) ); + if( sh->pps->b_pic_order && !sh->b_field_pic ) + bs_write_se( s, sh->i_delta_poc_bottom ); + } + + if( sh->pps->b_redundant_pic_cnt ) + bs_write_ue( s, sh->i_redundant_pic_cnt ); + + if( sh->i_type == SLICE_TYPE_B ) + bs_write1( s, sh->b_direct_spatial_mv_pred ); + + if( sh->i_type == SLICE_TYPE_P || sh->i_type == SLICE_TYPE_B ) + { + bs_write1( s, sh->b_num_ref_idx_override ); + if( sh->b_num_ref_idx_override ) + { + bs_write_ue( s, sh->i_num_ref_idx_l0_active - 1 ); + if( sh->i_type == SLICE_TYPE_B ) + bs_write_ue( s, sh->i_num_ref_idx_l1_active - 1 ); + } + } + + /* ref pic list reordering */ + if( sh->i_type != SLICE_TYPE_I ) + { + bs_write1( s, sh->b_ref_pic_list_reordering[0] ); + if( sh->b_ref_pic_list_reordering[0] ) + { + for( int i = 0; i < sh->i_num_ref_idx_l0_active; i++ ) + { + bs_write_ue( s, sh->ref_pic_list_order[0][i].idc ); + bs_write_ue( s, sh->ref_pic_list_order[0][i].arg ); + } + bs_write_ue( s, 3 ); + } + } + if( sh->i_type == SLICE_TYPE_B ) + { + bs_write1( s, sh->b_ref_pic_list_reordering[1] ); + if( sh->b_ref_pic_list_reordering[1] ) + { + for( int i = 0; i < sh->i_num_ref_idx_l1_active; i++ ) + { + bs_write_ue( s, sh->ref_pic_list_order[1][i].idc ); + bs_write_ue( s, sh->ref_pic_list_order[1][i].arg ); + } + bs_write_ue( s, 3 ); + } + } + + sh->b_weighted_pred = 0; + if( sh->pps->b_weighted_pred && sh->i_type == SLICE_TYPE_P ) + { + sh->b_weighted_pred = sh->weight[0][0].weightfn || sh->weight[0][1].weightfn || sh->weight[0][2].weightfn; + /* pred_weight_table() */ + bs_write_ue( s, sh->weight[0][0].i_denom ); + bs_write_ue( s, sh->weight[0][1].i_denom ); + for( int i = 0; i < sh->i_num_ref_idx_l0_active; i++ ) + { + int luma_weight_l0_flag = !!sh->weight[i][0].weightfn; + int chroma_weight_l0_flag = !!sh->weight[i][1].weightfn || !!sh->weight[i][2].weightfn; + bs_write1( s, luma_weight_l0_flag ); + if( luma_weight_l0_flag ) + { + bs_write_se( s, sh->weight[i][0].i_scale ); + bs_write_se( s, sh->weight[i][0].i_offset ); + } + bs_write1( s, chroma_weight_l0_flag ); + if( chroma_weight_l0_flag ) + { + for( int j = 1; j < 3; j++ ) + { + bs_write_se( s, sh->weight[i][j].i_scale ); + bs_write_se( s, sh->weight[i][j].i_offset ); + } + } + } + } + else if( sh->pps->b_weighted_bipred == 1 && sh->i_type == SLICE_TYPE_B ) + { + /* TODO */ + } + + if( i_nal_ref_idc != 0 ) + { + if( sh->i_idr_pic_id >= 0 ) + { + bs_write1( s, 0 ); /* no output of prior pics flag */ + bs_write1( s, 0 ); /* long term reference flag */ + } + else + { + bs_write1( s, sh->i_mmco_command_count > 0 ); /* adaptive_ref_pic_marking_mode_flag */ + if( sh->i_mmco_command_count > 0 ) + { + for( int i = 0; i < sh->i_mmco_command_count; i++ ) + { + bs_write_ue( s, 1 ); /* mark short term ref as unused */ + bs_write_ue( s, sh->mmco[i].i_difference_of_pic_nums - 1 ); + } + bs_write_ue( s, 0 ); /* end command list */ + } + } + } + + if( sh->pps->b_cabac && sh->i_type != SLICE_TYPE_I ) + bs_write_ue( s, sh->i_cabac_init_idc ); + + bs_write_se( s, sh->i_qp_delta ); /* slice qp delta */ + + if( sh->pps->b_deblocking_filter_control ) + { + bs_write_ue( s, sh->i_disable_deblocking_filter_idc ); + if( sh->i_disable_deblocking_filter_idc != 1 ) + { + bs_write_se( s, sh->i_alpha_c0_offset >> 1 ); + bs_write_se( s, sh->i_beta_offset >> 1 ); + } + } +} + +/* If we are within a reasonable distance of the end of the memory allocated for the bitstream, */ +/* reallocate, adding an arbitrary amount of space. */ +static int x264_bitstream_check_buffer_internal( x264_t *h, int size, int b_cabac, int i_nal ) +{ + if( (b_cabac && (h->cabac.p_end - h->cabac.p < size)) || + (h->out.bs.p_end - h->out.bs.p < size) ) + { + int buf_size = h->out.i_bitstream + size; + uint8_t *buf = x264_malloc( buf_size ); + if( !buf ) + return -1; + int aligned_size = h->out.i_bitstream & ~15; + h->mc.memcpy_aligned( buf, h->out.p_bitstream, aligned_size ); + memcpy( buf + aligned_size, h->out.p_bitstream + aligned_size, h->out.i_bitstream - aligned_size ); + + intptr_t delta = buf - h->out.p_bitstream; + + h->out.bs.p_start += delta; + h->out.bs.p += delta; + h->out.bs.p_end = buf + buf_size; + + h->cabac.p_start += delta; + h->cabac.p += delta; + h->cabac.p_end = buf + buf_size; + + for( int i = 0; i <= i_nal; i++ ) + h->out.nal[i].p_payload += delta; + + x264_free( h->out.p_bitstream ); + h->out.p_bitstream = buf; + h->out.i_bitstream = buf_size; + } + return 0; +} + +static int x264_bitstream_check_buffer( x264_t *h ) +{ + int max_row_size = (2500 << SLICE_MBAFF) * h->mb.i_mb_width; + return x264_bitstream_check_buffer_internal( h, max_row_size, h->param.b_cabac, h->out.i_nal ); +} + +static int x264_bitstream_check_buffer_filler( x264_t *h, int filler ) +{ + filler += 32; // add padding for safety + return x264_bitstream_check_buffer_internal( h, filler, 0, -1 ); +} + +#if HAVE_THREAD +static void x264_encoder_thread_init( x264_t *h ) +{ + if( h->param.i_sync_lookahead ) + x264_lower_thread_priority( 10 ); +} +#endif + +/**************************************************************************** + * + **************************************************************************** + ****************************** External API********************************* + **************************************************************************** + * + ****************************************************************************/ + +static int x264_validate_parameters( x264_t *h, int b_open ) +{ + if( !h->param.pf_log ) + { + x264_log( NULL, X264_LOG_ERROR, "pf_log not set! did you forget to call x264_param_default?\n" ); + return -1; + } + +#if HAVE_MMX + if( b_open ) + { + int cpuflags = x264_cpu_detect(); + int fail = 0; +#ifdef __SSE__ + if( !(cpuflags & X264_CPU_SSE) ) + { + x264_log( h, X264_LOG_ERROR, "your cpu does not support SSE1, but x264 was compiled with asm\n"); + fail = 1; + } +#else + if( !(cpuflags & X264_CPU_MMX2) ) + { + x264_log( h, X264_LOG_ERROR, "your cpu does not support MMXEXT, but x264 was compiled with asm\n"); + fail = 1; + } +#endif + if( fail ) + { + x264_log( h, X264_LOG_ERROR, "to run x264, recompile without asm (configure --disable-asm)\n"); + return -1; + } + } +#endif + +#if HAVE_INTERLACED + h->param.b_interlaced = !!PARAM_INTERLACED; +#else + if( h->param.b_interlaced ) + { + x264_log( h, X264_LOG_ERROR, "not compiled with interlaced support\n" ); + return -1; + } +#endif + + if( h->param.i_width <= 0 || h->param.i_height <= 0 ) + { + x264_log( h, X264_LOG_ERROR, "invalid width x height (%dx%d)\n", + h->param.i_width, h->param.i_height ); + return -1; + } + + int i_csp = h->param.i_csp & X264_CSP_MASK; +#if X264_CHROMA_FORMAT + if( CHROMA_FORMAT != CHROMA_420 && i_csp >= X264_CSP_I420 && i_csp < X264_CSP_I422 ) + { + x264_log( h, X264_LOG_ERROR, "not compiled with 4:2:0 support\n" ); + return -1; + } + else if( CHROMA_FORMAT != CHROMA_422 && i_csp >= X264_CSP_I422 && i_csp < X264_CSP_I444 ) + { + x264_log( h, X264_LOG_ERROR, "not compiled with 4:2:2 support\n" ); + return -1; + } + else if( CHROMA_FORMAT != CHROMA_444 && i_csp >= X264_CSP_I444 && i_csp <= X264_CSP_RGB ) + { + x264_log( h, X264_LOG_ERROR, "not compiled with 4:4:4 support\n" ); + return -1; + } +#endif + if( i_csp <= X264_CSP_NONE || i_csp >= X264_CSP_MAX ) + { + x264_log( h, X264_LOG_ERROR, "invalid CSP (only I420/YV12/NV12/NV21/I422/YV16/NV16/YUYV/UYVY/" + "I444/YV24/BGR/BGRA/RGB supported)\n" ); + return -1; + } + + int w_mod = i_csp < X264_CSP_I444 ? 2 : 1; + int h_mod = (i_csp < X264_CSP_I422 ? 2 : 1) << PARAM_INTERLACED; + if( h->param.i_width % w_mod ) + { + x264_log( h, X264_LOG_ERROR, "width not divisible by %d (%dx%d)\n", + w_mod, h->param.i_width, h->param.i_height ); + return -1; + } + if( h->param.i_height % h_mod ) + { + x264_log( h, X264_LOG_ERROR, "height not divisible by %d (%dx%d)\n", + h_mod, h->param.i_width, h->param.i_height ); + return -1; + } + + if( h->param.crop_rect.i_left >= h->param.i_width || + h->param.crop_rect.i_right >= h->param.i_width || + h->param.crop_rect.i_top >= h->param.i_height || + h->param.crop_rect.i_bottom >= h->param.i_height || + h->param.crop_rect.i_left + h->param.crop_rect.i_right >= h->param.i_width || + h->param.crop_rect.i_top + h->param.crop_rect.i_bottom >= h->param.i_height ) + { + x264_log( h, X264_LOG_ERROR, "invalid crop-rect %u,%u,%u,%u\n", h->param.crop_rect.i_left, + h->param.crop_rect.i_top, h->param.crop_rect.i_right, h->param.crop_rect.i_bottom ); + return -1; + } + if( h->param.crop_rect.i_left % w_mod || h->param.crop_rect.i_right % w_mod || + h->param.crop_rect.i_top % h_mod || h->param.crop_rect.i_bottom % h_mod ) + { + x264_log( h, X264_LOG_ERROR, "crop-rect %u,%u,%u,%u not divisible by %dx%d\n", h->param.crop_rect.i_left, + h->param.crop_rect.i_top, h->param.crop_rect.i_right, h->param.crop_rect.i_bottom, w_mod, h_mod ); + return -1; + } + + if( h->param.vui.i_sar_width <= 0 || h->param.vui.i_sar_height <= 0 ) + { + h->param.vui.i_sar_width = 0; + h->param.vui.i_sar_height = 0; + } + + if( h->param.i_threads == X264_THREADS_AUTO ) + { + h->param.i_threads = x264_cpu_num_processors() * (h->param.b_sliced_threads?2:3)/2; + /* Avoid too many threads as they don't improve performance and + * complicate VBV. Capped at an arbitrary 2 rows per thread. */ + int max_threads = X264_MAX( 1, (h->param.i_height+15)/16 / 2 ); + h->param.i_threads = X264_MIN( h->param.i_threads, max_threads ); + } + int max_sliced_threads = X264_MAX( 1, (h->param.i_height+15)/16 / 4 ); + if( h->param.i_threads > 1 ) + { +#if !HAVE_THREAD + x264_log( h, X264_LOG_WARNING, "not compiled with thread support!\n"); + h->param.i_threads = 1; +#endif + /* Avoid absurdly small thread slices as they can reduce performance + * and VBV compliance. Capped at an arbitrary 4 rows per thread. */ + if( h->param.b_sliced_threads ) + h->param.i_threads = X264_MIN( h->param.i_threads, max_sliced_threads ); + } + h->param.i_threads = x264_clip3( h->param.i_threads, 1, X264_THREAD_MAX ); + if( h->param.i_threads == 1 ) + { + h->param.b_sliced_threads = 0; + h->param.i_lookahead_threads = 1; + } + h->i_thread_frames = h->param.b_sliced_threads ? 1 : h->param.i_threads; + if( h->i_thread_frames > 1 ) + h->param.nalu_process = NULL; + + if( h->param.b_opencl ) + { +#if !HAVE_OPENCL + x264_log( h, X264_LOG_WARNING, "OpenCL: not compiled with OpenCL support, disabling\n" ); + h->param.b_opencl = 0; +#elif BIT_DEPTH > 8 + x264_log( h, X264_LOG_WARNING, "OpenCL lookahead does not support high bit depth, disabling opencl\n" ); + h->param.b_opencl = 0; +#else + if( h->param.i_width < 32 || h->param.i_height < 32 ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: frame size is too small, disabling opencl\n" ); + h->param.b_opencl = 0; + } +#endif + if( h->param.opencl_device_id && h->param.i_opencl_device ) + { + x264_log( h, X264_LOG_WARNING, "OpenCL: device id and device skip count configured; dropping skip\n" ); + h->param.i_opencl_device = 0; + } + } + + h->param.i_keyint_max = x264_clip3( h->param.i_keyint_max, 1, X264_KEYINT_MAX_INFINITE ); + if( h->param.i_keyint_max == 1 ) + { + h->param.b_intra_refresh = 0; + h->param.analyse.i_weighted_pred = 0; + h->param.i_frame_reference = 1; + h->param.i_dpb_size = 1; + } + + if( h->param.i_frame_packing < -1 || h->param.i_frame_packing > 7 ) + { + x264_log( h, X264_LOG_WARNING, "ignoring unknown frame packing value\n" ); + h->param.i_frame_packing = -1; + } + if( h->param.i_frame_packing == 7 && + ((h->param.i_width - h->param.crop_rect.i_left - h->param.crop_rect.i_right) % 3 || + (h->param.i_height - h->param.crop_rect.i_top - h->param.crop_rect.i_bottom) % 3) ) + { + x264_log( h, X264_LOG_ERROR, "cropped resolution %dx%d not compatible with tile format frame packing\n", + h->param.i_width - h->param.crop_rect.i_left - h->param.crop_rect.i_right, + h->param.i_height - h->param.crop_rect.i_top - h->param.crop_rect.i_bottom ); + return -1; + } + + /* Detect default ffmpeg settings and terminate with an error. */ + if( b_open ) + { + int score = 0; + score += h->param.analyse.i_me_range == 0; + score += h->param.rc.i_qp_step == 3; + score += h->param.i_keyint_max == 12; + score += h->param.rc.i_qp_min == 2; + score += h->param.rc.i_qp_max == 31; + score += h->param.rc.f_qcompress == 0.5; + score += fabs(h->param.rc.f_ip_factor - 1.25) < 0.01; + score += fabs(h->param.rc.f_pb_factor - 1.25) < 0.01; + score += h->param.analyse.inter == 0 && h->param.analyse.i_subpel_refine == 8; + if( score >= 5 ) + { + x264_log( h, X264_LOG_ERROR, "broken ffmpeg default settings detected\n" ); + x264_log( h, X264_LOG_ERROR, "use an encoding preset (e.g. -vpre medium)\n" ); + x264_log( h, X264_LOG_ERROR, "preset usage: -vpre -vpre \n" ); + x264_log( h, X264_LOG_ERROR, "speed presets are listed in x264 --help\n" ); + x264_log( h, X264_LOG_ERROR, "profile is optional; x264 defaults to high\n" ); + return -1; + } + } + + if( h->param.rc.i_rc_method < 0 || h->param.rc.i_rc_method > 2 ) + { + x264_log( h, X264_LOG_ERROR, "no ratecontrol method specified\n" ); + return -1; + } + + if( PARAM_INTERLACED ) + h->param.b_pic_struct = 1; + + if( h->param.i_avcintra_class ) + { + if( BIT_DEPTH != 10 ) + { + x264_log( h, X264_LOG_ERROR, "%2d-bit AVC-Intra is not widely compatible\n", BIT_DEPTH ); + x264_log( h, X264_LOG_ERROR, "10-bit x264 is required to encode AVC-Intra\n" ); + return -1; + } + + int type = h->param.i_avcintra_class == 200 ? 2 : + h->param.i_avcintra_class == 100 ? 1 : + h->param.i_avcintra_class == 50 ? 0 : -1; + if( type < 0 ) + { + x264_log( h, X264_LOG_ERROR, "Invalid AVC-Intra class\n" ); + return -1; + } + + /* [50/100/200][res][fps] */ + static const struct + { + uint16_t fps_num; + uint16_t fps_den; + uint8_t interlaced; + uint16_t frame_size; + const uint8_t *cqm_4ic; + const uint8_t *cqm_8iy; + } avcintra_lut[3][2][7] = + { + {{{ 60000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 50, 1, 0, 1100, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 30000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 25, 1, 0, 1100, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 24000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }}, + {{ 30000, 1001, 1, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_1080i_8iy }, + { 25, 1, 1, 2196, x264_cqm_avci50_4ic, x264_cqm_avci50_1080i_8iy }, + { 60000, 1001, 0, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 30000, 1001, 0, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 50, 1, 0, 2196, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 25, 1, 0, 2196, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 24000, 1001, 0, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }}}, + {{{ 60000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 50, 1, 0, 2224, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 30000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 25, 1, 0, 2224, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 24000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }}, + {{ 30000, 1001, 1, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy }, + { 25, 1, 1, 4444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy }, + { 60000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 30000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 50, 1, 0, 4444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 25, 1, 0, 4444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 24000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}}, + {{{ 60000, 1001, 0, 3724, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 50, 1, 0, 4472, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }}, + {{ 30000, 1001, 1, 7444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy }, + { 25, 1, 1, 8940, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy }, + { 60000, 1001, 0, 7444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 30000, 1001, 0, 7444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 50, 1, 0, 8940, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 25, 1, 0, 8940, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 24000, 1001, 0, 7444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}} + }; + + int res = -1; + if( i_csp >= X264_CSP_I420 && i_csp < X264_CSP_I422 && !type ) + { + if( h->param.i_width == 1440 && h->param.i_height == 1080 ) res = 1; + else if( h->param.i_width == 960 && h->param.i_height == 720 ) res = 0; + } + else if( i_csp >= X264_CSP_I422 && i_csp < X264_CSP_I444 && type ) + { + if( h->param.i_width == 1920 && h->param.i_height == 1080 ) res = 1; + else if( h->param.i_width == 1280 && h->param.i_height == 720 ) res = 0; + } + else + { + x264_log( h, X264_LOG_ERROR, "Invalid colorspace for AVC-Intra %d\n", h->param.i_avcintra_class ); + return -1; + } + + if( res < 0 ) + { + x264_log( h, X264_LOG_ERROR, "Resolution %dx%d invalid for AVC-Intra %d\n", + h->param.i_width, h->param.i_height, h->param.i_avcintra_class ); + return -1; + } + + if( h->param.nalu_process ) + { + x264_log( h, X264_LOG_ERROR, "nalu_process is not supported in AVC-Intra mode\n" ); + return -1; + } + + if( !h->param.b_repeat_headers ) + { + x264_log( h, X264_LOG_ERROR, "Separate headers not supported in AVC-Intra mode\n" ); + return -1; + } + + int i; + uint32_t fps_num = h->param.i_fps_num, fps_den = h->param.i_fps_den; + x264_reduce_fraction( &fps_num, &fps_den ); + for( i = 0; i < 7; i++ ) + { + if( avcintra_lut[type][res][i].fps_num == fps_num && + avcintra_lut[type][res][i].fps_den == fps_den && + avcintra_lut[type][res][i].interlaced == PARAM_INTERLACED ) + { + break; + } + } + if( i == 7 ) + { + x264_log( h, X264_LOG_ERROR, "FPS %d/%d%c not compatible with AVC-Intra\n", + h->param.i_fps_num, h->param.i_fps_den, PARAM_INTERLACED ? 'i' : 'p' ); + return -1; + } + + h->param.i_keyint_max = 1; + h->param.b_intra_refresh = 0; + h->param.analyse.i_weighted_pred = 0; + h->param.i_frame_reference = 1; + h->param.i_dpb_size = 1; + + h->param.b_bluray_compat = 0; + h->param.b_vfr_input = 0; + h->param.b_aud = 1; + h->param.vui.i_chroma_loc = 0; + h->param.i_nal_hrd = X264_NAL_HRD_NONE; + h->param.b_deblocking_filter = 0; + h->param.b_stitchable = 1; + h->param.b_pic_struct = 0; + h->param.analyse.b_transform_8x8 = 1; + h->param.analyse.intra = X264_ANALYSE_I8x8; + h->param.analyse.i_chroma_qp_offset = res && type ? 3 : 4; + h->param.b_cabac = !type; + h->param.rc.i_vbv_buffer_size = avcintra_lut[type][res][i].frame_size; + h->param.rc.i_vbv_max_bitrate = + h->param.rc.i_bitrate = h->param.rc.i_vbv_buffer_size * fps_num / fps_den; + h->param.rc.i_rc_method = X264_RC_ABR; + h->param.rc.f_vbv_buffer_init = 1.0; + h->param.rc.b_filler = 1; + h->param.i_cqm_preset = X264_CQM_CUSTOM; + memcpy( h->param.cqm_4iy, x264_cqm_jvt4i, sizeof(h->param.cqm_4iy) ); + memcpy( h->param.cqm_4ic, avcintra_lut[type][res][i].cqm_4ic, sizeof(h->param.cqm_4ic) ); + memcpy( h->param.cqm_8iy, avcintra_lut[type][res][i].cqm_8iy, sizeof(h->param.cqm_8iy) ); + + /* Need exactly 10 slices of equal MB count... why? $deity knows... */ + h->param.i_slice_max_mbs = ((h->param.i_width + 15) / 16) * ((h->param.i_height + 15) / 16) / 10; + h->param.i_slice_max_size = 0; + /* The slice structure only allows a maximum of 2 threads for 1080i/p + * and 1 or 5 threads for 720p */ + if( h->param.b_sliced_threads ) + { + if( res ) + h->param.i_threads = X264_MIN( 2, h->param.i_threads ); + else + { + h->param.i_threads = X264_MIN( 5, h->param.i_threads ); + if( h->param.i_threads < 5 ) + h->param.i_threads = 1; + } + } + + if( type ) + h->param.vui.i_sar_width = h->param.vui.i_sar_height = 1; + else + { + h->param.vui.i_sar_width = 4; + h->param.vui.i_sar_height = 3; + } + + /* Official encoder doesn't appear to go under 13 + * and Avid cannot handle negative QPs */ + h->param.rc.i_qp_min = X264_MAX( h->param.rc.i_qp_min, QP_BD_OFFSET + 1 ); + } + + h->param.rc.f_rf_constant = x264_clip3f( h->param.rc.f_rf_constant, -QP_BD_OFFSET, 51 ); + h->param.rc.f_rf_constant_max = x264_clip3f( h->param.rc.f_rf_constant_max, -QP_BD_OFFSET, 51 ); + h->param.rc.i_qp_constant = x264_clip3( h->param.rc.i_qp_constant, 0, QP_MAX ); + h->param.analyse.i_subpel_refine = x264_clip3( h->param.analyse.i_subpel_refine, 0, 11 ); + h->param.rc.f_ip_factor = X264_MAX( h->param.rc.f_ip_factor, 0.01f ); + h->param.rc.f_pb_factor = X264_MAX( h->param.rc.f_pb_factor, 0.01f ); + if( h->param.rc.i_rc_method == X264_RC_CRF ) + { + h->param.rc.i_qp_constant = h->param.rc.f_rf_constant + QP_BD_OFFSET; + h->param.rc.i_bitrate = 0; + } + if( b_open && (h->param.rc.i_rc_method == X264_RC_CQP || h->param.rc.i_rc_method == X264_RC_CRF) + && h->param.rc.i_qp_constant == 0 ) + { + h->mb.b_lossless = 1; + h->param.i_cqm_preset = X264_CQM_FLAT; + h->param.psz_cqm_file = NULL; + h->param.rc.i_rc_method = X264_RC_CQP; + h->param.rc.f_ip_factor = 1; + h->param.rc.f_pb_factor = 1; + h->param.analyse.b_psnr = 0; + h->param.analyse.b_ssim = 0; + h->param.analyse.i_chroma_qp_offset = 0; + h->param.analyse.i_trellis = 0; + h->param.analyse.b_fast_pskip = 0; + h->param.analyse.i_noise_reduction = 0; + h->param.analyse.b_psy = 0; + h->param.i_bframe = 0; + /* 8x8dct is not useful without RD in CAVLC lossless */ + if( !h->param.b_cabac && h->param.analyse.i_subpel_refine < 6 ) + h->param.analyse.b_transform_8x8 = 0; + h->param.analyse.inter &= ~X264_ANALYSE_I8x8; + h->param.analyse.intra &= ~X264_ANALYSE_I8x8; + } + if( i_csp >= X264_CSP_I444 && h->param.b_cabac ) + { + /* Disable 8x8dct during 4:4:4+CABAC encoding for compatibility with libavcodec */ + h->param.analyse.b_transform_8x8 = 0; + } + if( h->param.rc.i_rc_method == X264_RC_CQP ) + { + float qp_p = h->param.rc.i_qp_constant; + float qp_i = qp_p - 6*log2f( h->param.rc.f_ip_factor ); + float qp_b = qp_p + 6*log2f( h->param.rc.f_pb_factor ); + h->param.rc.i_qp_min = x264_clip3( (int)(X264_MIN3( qp_p, qp_i, qp_b )), 0, QP_MAX ); + h->param.rc.i_qp_max = x264_clip3( (int)(X264_MAX3( qp_p, qp_i, qp_b ) + .999), 0, QP_MAX ); + h->param.rc.i_aq_mode = 0; + h->param.rc.b_mb_tree = 0; + h->param.rc.i_bitrate = 0; + } + h->param.rc.i_qp_max = x264_clip3( h->param.rc.i_qp_max, 0, QP_MAX ); + h->param.rc.i_qp_min = x264_clip3( h->param.rc.i_qp_min, 0, h->param.rc.i_qp_max ); + h->param.rc.i_qp_step = x264_clip3( h->param.rc.i_qp_step, 2, QP_MAX ); + h->param.rc.i_bitrate = x264_clip3( h->param.rc.i_bitrate, 0, 2000000 ); + if( h->param.rc.i_rc_method == X264_RC_ABR && !h->param.rc.i_bitrate ) + { + x264_log( h, X264_LOG_ERROR, "bitrate not specified\n" ); + return -1; + } + h->param.rc.i_vbv_buffer_size = x264_clip3( h->param.rc.i_vbv_buffer_size, 0, 2000000 ); + h->param.rc.i_vbv_max_bitrate = x264_clip3( h->param.rc.i_vbv_max_bitrate, 0, 2000000 ); + h->param.rc.f_vbv_buffer_init = x264_clip3f( h->param.rc.f_vbv_buffer_init, 0, 2000000 ); + if( h->param.rc.i_vbv_buffer_size ) + { + if( h->param.rc.i_rc_method == X264_RC_CQP ) + { + x264_log( h, X264_LOG_WARNING, "VBV is incompatible with constant QP, ignored.\n" ); + h->param.rc.i_vbv_max_bitrate = 0; + h->param.rc.i_vbv_buffer_size = 0; + } + else if( h->param.rc.i_vbv_max_bitrate == 0 ) + { + if( h->param.rc.i_rc_method == X264_RC_ABR ) + { + x264_log( h, X264_LOG_WARNING, "VBV maxrate unspecified, assuming CBR\n" ); + h->param.rc.i_vbv_max_bitrate = h->param.rc.i_bitrate; + } + else + { + x264_log( h, X264_LOG_WARNING, "VBV bufsize set but maxrate unspecified, ignored\n" ); + h->param.rc.i_vbv_buffer_size = 0; + } + } + else if( h->param.rc.i_vbv_max_bitrate < h->param.rc.i_bitrate && + h->param.rc.i_rc_method == X264_RC_ABR ) + { + x264_log( h, X264_LOG_WARNING, "max bitrate less than average bitrate, assuming CBR\n" ); + h->param.rc.i_bitrate = h->param.rc.i_vbv_max_bitrate; + } + } + else if( h->param.rc.i_vbv_max_bitrate ) + { + x264_log( h, X264_LOG_WARNING, "VBV maxrate specified, but no bufsize, ignored\n" ); + h->param.rc.i_vbv_max_bitrate = 0; + } + + h->param.i_slice_max_size = X264_MAX( h->param.i_slice_max_size, 0 ); + h->param.i_slice_max_mbs = X264_MAX( h->param.i_slice_max_mbs, 0 ); + h->param.i_slice_min_mbs = X264_MAX( h->param.i_slice_min_mbs, 0 ); + if( h->param.i_slice_max_mbs ) + h->param.i_slice_min_mbs = X264_MIN( h->param.i_slice_min_mbs, h->param.i_slice_max_mbs/2 ); + else if( !h->param.i_slice_max_size ) + h->param.i_slice_min_mbs = 0; + if( PARAM_INTERLACED && h->param.i_slice_min_mbs ) + { + x264_log( h, X264_LOG_WARNING, "interlace + slice-min-mbs is not implemented\n" ); + h->param.i_slice_min_mbs = 0; + } + int mb_width = (h->param.i_width+15)/16; + if( h->param.i_slice_min_mbs > mb_width ) + { + x264_log( h, X264_LOG_WARNING, "slice-min-mbs > row mb size (%d) not implemented\n", mb_width ); + h->param.i_slice_min_mbs = mb_width; + } + + int max_slices = (h->param.i_height+((16<param.b_sliced_threads ) + h->param.i_slice_count = x264_clip3( h->param.i_threads, 0, max_slices ); + else + { + h->param.i_slice_count = x264_clip3( h->param.i_slice_count, 0, max_slices ); + if( h->param.i_slice_max_mbs || h->param.i_slice_max_size ) + h->param.i_slice_count = 0; + } + if( h->param.i_slice_count_max > 0 ) + h->param.i_slice_count_max = X264_MAX( h->param.i_slice_count, h->param.i_slice_count_max ); + + if( h->param.b_bluray_compat ) + { + h->param.i_bframe_pyramid = X264_MIN( X264_B_PYRAMID_STRICT, h->param.i_bframe_pyramid ); + h->param.i_bframe = X264_MIN( h->param.i_bframe, 3 ); + h->param.b_aud = 1; + h->param.i_nal_hrd = X264_MAX( h->param.i_nal_hrd, X264_NAL_HRD_VBR ); + h->param.i_slice_max_size = 0; + h->param.i_slice_max_mbs = 0; + h->param.b_intra_refresh = 0; + h->param.i_frame_reference = X264_MIN( h->param.i_frame_reference, 6 ); + h->param.i_dpb_size = X264_MIN( h->param.i_dpb_size, 6 ); + /* Don't use I-frames, because Blu-ray treats them the same as IDR. */ + h->param.i_keyint_min = 1; + /* Due to the proliferation of broken players that don't handle dupes properly. */ + h->param.analyse.i_weighted_pred = X264_MIN( h->param.analyse.i_weighted_pred, X264_WEIGHTP_SIMPLE ); + if( h->param.b_fake_interlaced ) + h->param.b_pic_struct = 1; + } + + h->param.i_frame_reference = x264_clip3( h->param.i_frame_reference, 1, X264_REF_MAX ); + h->param.i_dpb_size = x264_clip3( h->param.i_dpb_size, 1, X264_REF_MAX ); + if( h->param.i_scenecut_threshold < 0 ) + h->param.i_scenecut_threshold = 0; + h->param.analyse.i_direct_mv_pred = x264_clip3( h->param.analyse.i_direct_mv_pred, X264_DIRECT_PRED_NONE, X264_DIRECT_PRED_AUTO ); + if( !h->param.analyse.i_subpel_refine && h->param.analyse.i_direct_mv_pred > X264_DIRECT_PRED_SPATIAL ) + { + x264_log( h, X264_LOG_WARNING, "subme=0 + direct=temporal is not supported\n" ); + h->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; + } + h->param.i_bframe = x264_clip3( h->param.i_bframe, 0, X264_MIN( X264_BFRAME_MAX, h->param.i_keyint_max-1 ) ); + h->param.i_bframe_bias = x264_clip3( h->param.i_bframe_bias, -90, 100 ); + if( h->param.i_bframe <= 1 ) + h->param.i_bframe_pyramid = X264_B_PYRAMID_NONE; + h->param.i_bframe_pyramid = x264_clip3( h->param.i_bframe_pyramid, X264_B_PYRAMID_NONE, X264_B_PYRAMID_NORMAL ); + h->param.i_bframe_adaptive = x264_clip3( h->param.i_bframe_adaptive, X264_B_ADAPT_NONE, X264_B_ADAPT_TRELLIS ); + if( !h->param.i_bframe ) + { + h->param.i_bframe_adaptive = X264_B_ADAPT_NONE; + h->param.analyse.i_direct_mv_pred = 0; + h->param.analyse.b_weighted_bipred = 0; + h->param.b_open_gop = 0; + } + if( h->param.b_intra_refresh && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL ) + { + x264_log( h, X264_LOG_WARNING, "b-pyramid normal + intra-refresh is not supported\n" ); + h->param.i_bframe_pyramid = X264_B_PYRAMID_STRICT; + } + if( h->param.b_intra_refresh && (h->param.i_frame_reference > 1 || h->param.i_dpb_size > 1) ) + { + x264_log( h, X264_LOG_WARNING, "ref > 1 + intra-refresh is not supported\n" ); + h->param.i_frame_reference = 1; + h->param.i_dpb_size = 1; + } + if( h->param.b_intra_refresh && h->param.b_open_gop ) + { + x264_log( h, X264_LOG_WARNING, "intra-refresh is not compatible with open-gop\n" ); + h->param.b_open_gop = 0; + } + if( !h->param.i_fps_num || !h->param.i_fps_den ) + { + h->param.i_fps_num = 25; + h->param.i_fps_den = 1; + } + float fps = (float)h->param.i_fps_num / h->param.i_fps_den; + if( h->param.i_keyint_min == X264_KEYINT_MIN_AUTO ) + h->param.i_keyint_min = X264_MIN( h->param.i_keyint_max / 10, (int)fps ); + h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 ); + h->param.rc.i_lookahead = x264_clip3( h->param.rc.i_lookahead, 0, X264_LOOKAHEAD_MAX ); + { + int maxrate = X264_MAX( h->param.rc.i_vbv_max_bitrate, h->param.rc.i_bitrate ); + float bufsize = maxrate ? (float)h->param.rc.i_vbv_buffer_size / maxrate : 0; + h->param.rc.i_lookahead = X264_MIN( h->param.rc.i_lookahead, X264_MAX( h->param.i_keyint_max, bufsize*fps ) ); + } + + if( !h->param.i_timebase_num || !h->param.i_timebase_den || !(h->param.b_vfr_input || h->param.b_pulldown) ) + { + h->param.i_timebase_num = h->param.i_fps_den; + h->param.i_timebase_den = h->param.i_fps_num; + } + + h->param.rc.f_qcompress = x264_clip3f( h->param.rc.f_qcompress, 0.0, 1.0 ); + if( h->param.i_keyint_max == 1 || h->param.rc.f_qcompress == 1 ) + h->param.rc.b_mb_tree = 0; + if( (!h->param.b_intra_refresh && h->param.i_keyint_max != X264_KEYINT_MAX_INFINITE) && + !h->param.rc.i_lookahead && h->param.rc.b_mb_tree ) + { + x264_log( h, X264_LOG_WARNING, "lookaheadless mb-tree requires intra refresh or infinite keyint\n" ); + h->param.rc.b_mb_tree = 0; + } + if( b_open && h->param.rc.b_stat_read ) + h->param.rc.i_lookahead = 0; +#if HAVE_THREAD + if( h->param.i_sync_lookahead < 0 ) + h->param.i_sync_lookahead = h->param.i_bframe + 1; + h->param.i_sync_lookahead = X264_MIN( h->param.i_sync_lookahead, X264_LOOKAHEAD_MAX ); + if( h->param.rc.b_stat_read || h->i_thread_frames == 1 ) + h->param.i_sync_lookahead = 0; +#else + h->param.i_sync_lookahead = 0; +#endif + + h->param.i_deblocking_filter_alphac0 = x264_clip3( h->param.i_deblocking_filter_alphac0, -6, 6 ); + h->param.i_deblocking_filter_beta = x264_clip3( h->param.i_deblocking_filter_beta, -6, 6 ); + h->param.analyse.i_luma_deadzone[0] = x264_clip3( h->param.analyse.i_luma_deadzone[0], 0, 32 ); + h->param.analyse.i_luma_deadzone[1] = x264_clip3( h->param.analyse.i_luma_deadzone[1], 0, 32 ); + + h->param.i_cabac_init_idc = x264_clip3( h->param.i_cabac_init_idc, 0, 2 ); + + if( h->param.i_cqm_preset < X264_CQM_FLAT || h->param.i_cqm_preset > X264_CQM_CUSTOM ) + h->param.i_cqm_preset = X264_CQM_FLAT; + + if( h->param.analyse.i_me_method < X264_ME_DIA || + h->param.analyse.i_me_method > X264_ME_TESA ) + h->param.analyse.i_me_method = X264_ME_HEX; + h->param.analyse.i_me_range = x264_clip3( h->param.analyse.i_me_range, 4, 1024 ); + if( h->param.analyse.i_me_range > 16 && h->param.analyse.i_me_method <= X264_ME_HEX ) + h->param.analyse.i_me_range = 16; + if( h->param.analyse.i_me_method == X264_ME_TESA && + (h->mb.b_lossless || h->param.analyse.i_subpel_refine <= 1) ) + h->param.analyse.i_me_method = X264_ME_ESA; + h->param.analyse.b_mixed_references = h->param.analyse.b_mixed_references && h->param.i_frame_reference > 1; + h->param.analyse.inter &= X264_ANALYSE_PSUB16x16|X264_ANALYSE_PSUB8x8|X264_ANALYSE_BSUB16x16| + X264_ANALYSE_I4x4|X264_ANALYSE_I8x8; + h->param.analyse.intra &= X264_ANALYSE_I4x4|X264_ANALYSE_I8x8; + if( !(h->param.analyse.inter & X264_ANALYSE_PSUB16x16) ) + h->param.analyse.inter &= ~X264_ANALYSE_PSUB8x8; + if( !h->param.analyse.b_transform_8x8 ) + { + h->param.analyse.inter &= ~X264_ANALYSE_I8x8; + h->param.analyse.intra &= ~X264_ANALYSE_I8x8; + } + h->param.analyse.i_trellis = x264_clip3( h->param.analyse.i_trellis, 0, 2 ); + h->param.rc.i_aq_mode = x264_clip3( h->param.rc.i_aq_mode, 0, 3 ); + h->param.rc.f_aq_strength = x264_clip3f( h->param.rc.f_aq_strength, 0, 3 ); + if( h->param.rc.f_aq_strength == 0 ) + h->param.rc.i_aq_mode = 0; + + if( h->param.i_log_level < X264_LOG_INFO ) + { + h->param.analyse.b_psnr = 0; + h->param.analyse.b_ssim = 0; + } + /* Warn users trying to measure PSNR/SSIM with psy opts on. */ + if( b_open && (h->param.analyse.b_psnr || h->param.analyse.b_ssim) ) + { + char *s = NULL; + + if( h->param.analyse.b_psy ) + { + s = h->param.analyse.b_psnr ? "psnr" : "ssim"; + x264_log( h, X264_LOG_WARNING, "--%s used with psy on: results will be invalid!\n", s ); + } + else if( !h->param.rc.i_aq_mode && h->param.analyse.b_ssim ) + { + x264_log( h, X264_LOG_WARNING, "--ssim used with AQ off: results will be invalid!\n" ); + s = "ssim"; + } + else if( h->param.rc.i_aq_mode && h->param.analyse.b_psnr ) + { + x264_log( h, X264_LOG_WARNING, "--psnr used with AQ on: results will be invalid!\n" ); + s = "psnr"; + } + if( s ) + x264_log( h, X264_LOG_WARNING, "--tune %s should be used if attempting to benchmark %s!\n", s, s ); + } + + if( !h->param.analyse.b_psy ) + { + h->param.analyse.f_psy_rd = 0; + h->param.analyse.f_psy_trellis = 0; + } + h->param.analyse.f_psy_rd = x264_clip3f( h->param.analyse.f_psy_rd, 0, 10 ); + h->param.analyse.f_psy_trellis = x264_clip3f( h->param.analyse.f_psy_trellis, 0, 10 ); + h->mb.i_psy_rd = h->param.analyse.i_subpel_refine >= 6 ? FIX8( h->param.analyse.f_psy_rd ) : 0; + h->mb.i_psy_trellis = h->param.analyse.i_trellis ? FIX8( h->param.analyse.f_psy_trellis / 4 ) : 0; + h->param.analyse.i_chroma_qp_offset = x264_clip3(h->param.analyse.i_chroma_qp_offset, -32, 32); + /* In 4:4:4 mode, chroma gets twice as much resolution, so we can halve its quality. */ + if( b_open && i_csp >= X264_CSP_I444 && i_csp < X264_CSP_BGR && h->param.analyse.b_psy ) + h->param.analyse.i_chroma_qp_offset += 6; + /* Psy RDO increases overall quantizers to improve the quality of luma--this indirectly hurts chroma quality */ + /* so we lower the chroma QP offset to compensate */ + if( b_open && h->mb.i_psy_rd && !h->param.i_avcintra_class ) + h->param.analyse.i_chroma_qp_offset -= h->param.analyse.f_psy_rd < 0.25 ? 1 : 2; + /* Psy trellis has a similar effect. */ + if( b_open && h->mb.i_psy_trellis && !h->param.i_avcintra_class ) + h->param.analyse.i_chroma_qp_offset -= h->param.analyse.f_psy_trellis < 0.25 ? 1 : 2; + h->param.analyse.i_chroma_qp_offset = x264_clip3(h->param.analyse.i_chroma_qp_offset, -12, 12); + /* MB-tree requires AQ to be on, even if the strength is zero. */ + if( !h->param.rc.i_aq_mode && h->param.rc.b_mb_tree ) + { + h->param.rc.i_aq_mode = 1; + h->param.rc.f_aq_strength = 0; + } + h->param.analyse.i_noise_reduction = x264_clip3( h->param.analyse.i_noise_reduction, 0, 1<<16 ); + if( h->param.analyse.i_subpel_refine >= 10 && (h->param.analyse.i_trellis != 2 || !h->param.rc.i_aq_mode) ) + h->param.analyse.i_subpel_refine = 9; + + if( b_open ) + { + const x264_level_t *l = x264_levels; + if( h->param.i_level_idc < 0 ) + { + int maxrate_bak = h->param.rc.i_vbv_max_bitrate; + if( h->param.rc.i_rc_method == X264_RC_ABR && h->param.rc.i_vbv_buffer_size <= 0 ) + h->param.rc.i_vbv_max_bitrate = h->param.rc.i_bitrate * 2; + x264_sps_init( h->sps, h->param.i_sps_id, &h->param ); + do h->param.i_level_idc = l->level_idc; + while( l[1].level_idc && x264_validate_levels( h, 0 ) && l++ ); + h->param.rc.i_vbv_max_bitrate = maxrate_bak; + } + else + { + while( l->level_idc && l->level_idc != h->param.i_level_idc ) + l++; + if( l->level_idc == 0 ) + { + x264_log( h, X264_LOG_ERROR, "invalid level_idc: %d\n", h->param.i_level_idc ); + return -1; + } + } + if( h->param.analyse.i_mv_range <= 0 ) + h->param.analyse.i_mv_range = l->mv_range >> PARAM_INTERLACED; + else + h->param.analyse.i_mv_range = x264_clip3(h->param.analyse.i_mv_range, 32, 8192 >> PARAM_INTERLACED); + } + + h->param.analyse.i_weighted_pred = x264_clip3( h->param.analyse.i_weighted_pred, X264_WEIGHTP_NONE, X264_WEIGHTP_SMART ); + + if( h->param.i_lookahead_threads == X264_THREADS_AUTO ) + { + if( h->param.b_sliced_threads ) + h->param.i_lookahead_threads = h->param.i_threads; + else + { + /* If we're using much slower lookahead settings than encoding settings, it helps a lot to use + * more lookahead threads. This typically happens in the first pass of a two-pass encode, so + * try to guess at this sort of case. + * + * Tuned by a little bit of real encoding with the various presets. */ + int badapt = h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS; + int subme = X264_MIN( h->param.analyse.i_subpel_refine / 3, 3 ) + (h->param.analyse.i_subpel_refine > 1); + int bframes = X264_MIN( (h->param.i_bframe - 1) / 3, 3 ); + + /* [b-adapt 0/1 vs 2][quantized subme][quantized bframes] */ + static const uint8_t lookahead_thread_div[2][5][4] = + {{{6,6,6,6}, {3,3,3,3}, {4,4,4,4}, {6,6,6,6}, {12,12,12,12}}, + {{3,2,1,1}, {2,1,1,1}, {4,3,2,1}, {6,4,3,2}, {12, 9, 6, 4}}}; + + h->param.i_lookahead_threads = h->param.i_threads / lookahead_thread_div[badapt][subme][bframes]; + /* Since too many lookahead threads significantly degrades lookahead accuracy, limit auto + * lookahead threads to about 8 macroblock rows high each at worst. This number is chosen + * pretty much arbitrarily. */ + h->param.i_lookahead_threads = X264_MIN( h->param.i_lookahead_threads, h->param.i_height / 128 ); + } + } + h->param.i_lookahead_threads = x264_clip3( h->param.i_lookahead_threads, 1, X264_MIN( max_sliced_threads, X264_LOOKAHEAD_THREAD_MAX ) ); + + if( PARAM_INTERLACED ) + { + if( h->param.analyse.i_me_method >= X264_ME_ESA ) + { + x264_log( h, X264_LOG_WARNING, "interlace + me=esa is not implemented\n" ); + h->param.analyse.i_me_method = X264_ME_UMH; + } + if( h->param.analyse.i_weighted_pred > 0 ) + { + x264_log( h, X264_LOG_WARNING, "interlace + weightp is not implemented\n" ); + h->param.analyse.i_weighted_pred = X264_WEIGHTP_NONE; + } + } + + if( !h->param.analyse.i_weighted_pred && h->param.rc.b_mb_tree && h->param.analyse.b_psy ) + h->param.analyse.i_weighted_pred = X264_WEIGHTP_FAKE; + + if( h->i_thread_frames > 1 ) + { + int r = h->param.analyse.i_mv_range_thread; + int r2; + if( r <= 0 ) + { + // half of the available space is reserved and divided evenly among the threads, + // the rest is allocated to whichever thread is far enough ahead to use it. + // reserving more space increases quality for some videos, but costs more time + // in thread synchronization. + int max_range = (h->param.i_height + X264_THREAD_HEIGHT) / h->i_thread_frames - X264_THREAD_HEIGHT; + r = max_range / 2; + } + r = X264_MAX( r, h->param.analyse.i_me_range ); + r = X264_MIN( r, h->param.analyse.i_mv_range ); + // round up to use the whole mb row + r2 = (r & ~15) + ((-X264_THREAD_HEIGHT) & 15); + if( r2 < r ) + r2 += 16; + x264_log( h, X264_LOG_DEBUG, "using mv_range_thread = %d\n", r2 ); + h->param.analyse.i_mv_range_thread = r2; + } + + if( h->param.rc.f_rate_tolerance < 0 ) + h->param.rc.f_rate_tolerance = 0; + if( h->param.rc.f_qblur < 0 ) + h->param.rc.f_qblur = 0; + if( h->param.rc.f_complexity_blur < 0 ) + h->param.rc.f_complexity_blur = 0; + + h->param.i_sps_id &= 31; + + h->param.i_nal_hrd = x264_clip3( h->param.i_nal_hrd, X264_NAL_HRD_NONE, X264_NAL_HRD_CBR ); + + if( h->param.i_nal_hrd && !h->param.rc.i_vbv_buffer_size ) + { + x264_log( h, X264_LOG_WARNING, "NAL HRD parameters require VBV parameters\n" ); + h->param.i_nal_hrd = X264_NAL_HRD_NONE; + } + + if( h->param.i_nal_hrd == X264_NAL_HRD_CBR && + (h->param.rc.i_bitrate != h->param.rc.i_vbv_max_bitrate || !h->param.rc.i_vbv_max_bitrate) ) + { + x264_log( h, X264_LOG_WARNING, "CBR HRD requires constant bitrate\n" ); + h->param.i_nal_hrd = X264_NAL_HRD_VBR; + } + + if( h->param.i_nal_hrd == X264_NAL_HRD_CBR ) + h->param.rc.b_filler = 1; + + /* ensure the booleans are 0 or 1 so they can be used in math */ +#define BOOLIFY(x) h->param.x = !!h->param.x + BOOLIFY( b_cabac ); + BOOLIFY( b_constrained_intra ); + BOOLIFY( b_deblocking_filter ); + BOOLIFY( b_deterministic ); + BOOLIFY( b_sliced_threads ); + BOOLIFY( b_interlaced ); + BOOLIFY( b_intra_refresh ); + BOOLIFY( b_aud ); + BOOLIFY( b_repeat_headers ); + BOOLIFY( b_annexb ); + BOOLIFY( b_vfr_input ); + BOOLIFY( b_pulldown ); + BOOLIFY( b_tff ); + BOOLIFY( b_pic_struct ); + BOOLIFY( b_fake_interlaced ); + BOOLIFY( b_open_gop ); + BOOLIFY( b_bluray_compat ); + BOOLIFY( b_stitchable ); + BOOLIFY( b_full_recon ); + BOOLIFY( b_opencl ); + BOOLIFY( analyse.b_transform_8x8 ); + BOOLIFY( analyse.b_weighted_bipred ); + BOOLIFY( analyse.b_chroma_me ); + BOOLIFY( analyse.b_mixed_references ); + BOOLIFY( analyse.b_fast_pskip ); + BOOLIFY( analyse.b_dct_decimate ); + BOOLIFY( analyse.b_psy ); + BOOLIFY( analyse.b_psnr ); + BOOLIFY( analyse.b_ssim ); + BOOLIFY( rc.b_stat_write ); + BOOLIFY( rc.b_stat_read ); + BOOLIFY( rc.b_mb_tree ); + BOOLIFY( rc.b_filler ); +#undef BOOLIFY + + return 0; +} + +static void mbcmp_init( x264_t *h ) +{ + int satd = !h->mb.b_lossless && h->param.analyse.i_subpel_refine > 1; + memcpy( h->pixf.mbcmp, satd ? h->pixf.satd : h->pixf.sad_aligned, sizeof(h->pixf.mbcmp) ); + memcpy( h->pixf.mbcmp_unaligned, satd ? h->pixf.satd : h->pixf.sad, sizeof(h->pixf.mbcmp_unaligned) ); + h->pixf.intra_mbcmp_x3_16x16 = satd ? h->pixf.intra_satd_x3_16x16 : h->pixf.intra_sad_x3_16x16; + h->pixf.intra_mbcmp_x3_8x16c = satd ? h->pixf.intra_satd_x3_8x16c : h->pixf.intra_sad_x3_8x16c; + h->pixf.intra_mbcmp_x3_8x8c = satd ? h->pixf.intra_satd_x3_8x8c : h->pixf.intra_sad_x3_8x8c; + h->pixf.intra_mbcmp_x3_8x8 = satd ? h->pixf.intra_sa8d_x3_8x8 : h->pixf.intra_sad_x3_8x8; + h->pixf.intra_mbcmp_x3_4x4 = satd ? h->pixf.intra_satd_x3_4x4 : h->pixf.intra_sad_x3_4x4; + h->pixf.intra_mbcmp_x9_4x4 = h->param.b_cpu_independent || h->mb.b_lossless ? NULL + : satd ? h->pixf.intra_satd_x9_4x4 : h->pixf.intra_sad_x9_4x4; + h->pixf.intra_mbcmp_x9_8x8 = h->param.b_cpu_independent || h->mb.b_lossless ? NULL + : satd ? h->pixf.intra_sa8d_x9_8x8 : h->pixf.intra_sad_x9_8x8; + satd &= h->param.analyse.i_me_method == X264_ME_TESA; + memcpy( h->pixf.fpelcmp, satd ? h->pixf.satd : h->pixf.sad, sizeof(h->pixf.fpelcmp) ); + memcpy( h->pixf.fpelcmp_x3, satd ? h->pixf.satd_x3 : h->pixf.sad_x3, sizeof(h->pixf.fpelcmp_x3) ); + memcpy( h->pixf.fpelcmp_x4, satd ? h->pixf.satd_x4 : h->pixf.sad_x4, sizeof(h->pixf.fpelcmp_x4) ); +} + +static void chroma_dsp_init( x264_t *h ) +{ + memcpy( h->luma2chroma_pixel, x264_luma2chroma_pixel[CHROMA_FORMAT], sizeof(h->luma2chroma_pixel) ); + + switch( CHROMA_FORMAT ) + { + case CHROMA_420: + memcpy( h->predict_chroma, h->predict_8x8c, sizeof(h->predict_chroma) ); + h->mc.prefetch_fenc = h->mc.prefetch_fenc_420; + h->loopf.deblock_chroma[0] = h->loopf.deblock_h_chroma_420; + h->loopf.deblock_chroma_intra[0] = h->loopf.deblock_h_chroma_420_intra; + h->loopf.deblock_chroma_mbaff = h->loopf.deblock_chroma_420_mbaff; + h->loopf.deblock_chroma_intra_mbaff = h->loopf.deblock_chroma_420_intra_mbaff; + h->pixf.intra_mbcmp_x3_chroma = h->pixf.intra_mbcmp_x3_8x8c; + h->quantf.coeff_last[DCT_CHROMA_DC] = h->quantf.coeff_last4; + h->quantf.coeff_level_run[DCT_CHROMA_DC] = h->quantf.coeff_level_run4; + break; + case CHROMA_422: + memcpy( h->predict_chroma, h->predict_8x16c, sizeof(h->predict_chroma) ); + h->mc.prefetch_fenc = h->mc.prefetch_fenc_422; + h->loopf.deblock_chroma[0] = h->loopf.deblock_h_chroma_422; + h->loopf.deblock_chroma_intra[0] = h->loopf.deblock_h_chroma_422_intra; + h->loopf.deblock_chroma_mbaff = h->loopf.deblock_chroma_422_mbaff; + h->loopf.deblock_chroma_intra_mbaff = h->loopf.deblock_chroma_422_intra_mbaff; + h->pixf.intra_mbcmp_x3_chroma = h->pixf.intra_mbcmp_x3_8x16c; + h->quantf.coeff_last[DCT_CHROMA_DC] = h->quantf.coeff_last8; + h->quantf.coeff_level_run[DCT_CHROMA_DC] = h->quantf.coeff_level_run8; + break; + case CHROMA_444: + h->mc.prefetch_fenc = h->mc.prefetch_fenc_422; /* FIXME: doesn't cover V plane */ + h->loopf.deblock_chroma_mbaff = h->loopf.deblock_luma_mbaff; + h->loopf.deblock_chroma_intra_mbaff = h->loopf.deblock_luma_intra_mbaff; + break; + } +} + +static void x264_set_aspect_ratio( x264_t *h, x264_param_t *param, int initial ) +{ + /* VUI */ + if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 ) + { + uint32_t i_w = param->vui.i_sar_width; + uint32_t i_h = param->vui.i_sar_height; + uint32_t old_w = h->param.vui.i_sar_width; + uint32_t old_h = h->param.vui.i_sar_height; + + x264_reduce_fraction( &i_w, &i_h ); + + while( i_w > 65535 || i_h > 65535 ) + { + i_w /= 2; + i_h /= 2; + } + + x264_reduce_fraction( &i_w, &i_h ); + + if( i_w != old_w || i_h != old_h || initial ) + { + h->param.vui.i_sar_width = 0; + h->param.vui.i_sar_height = 0; + if( i_w == 0 || i_h == 0 ) + x264_log( h, X264_LOG_WARNING, "cannot create valid sample aspect ratio\n" ); + else + { + x264_log( h, initial?X264_LOG_INFO:X264_LOG_DEBUG, "using SAR=%d/%d\n", i_w, i_h ); + h->param.vui.i_sar_width = i_w; + h->param.vui.i_sar_height = i_h; + } + } + } +} + +/**************************************************************************** + * x264_encoder_open: + ****************************************************************************/ +x264_t *x264_encoder_open( x264_param_t *param ) +{ + x264_t *h; + char buf[1000], *p; + int i_slicetype_length; + + CHECKED_MALLOCZERO( h, sizeof(x264_t) ); + + /* Create a copy of param */ + memcpy( &h->param, param, sizeof(x264_param_t) ); + + if( param->param_free ) + param->param_free( param ); + +#if HAVE_INTEL_DISPATCHER + x264_intel_dispatcher_override(); +#endif + + if( x264_threading_init() ) + { + x264_log( h, X264_LOG_ERROR, "unable to initialize threading\n" ); + goto fail; + } + + if( x264_validate_parameters( h, 1 ) < 0 ) + goto fail; + + if( h->param.psz_cqm_file ) + if( x264_cqm_parse_file( h, h->param.psz_cqm_file ) < 0 ) + goto fail; + + if( h->param.rc.psz_stat_out ) + h->param.rc.psz_stat_out = strdup( h->param.rc.psz_stat_out ); + if( h->param.rc.psz_stat_in ) + h->param.rc.psz_stat_in = strdup( h->param.rc.psz_stat_in ); + + x264_reduce_fraction( &h->param.i_fps_num, &h->param.i_fps_den ); + x264_reduce_fraction( &h->param.i_timebase_num, &h->param.i_timebase_den ); + + /* Init x264_t */ + h->i_frame = -1; + h->i_frame_num = 0; + + if( h->param.i_avcintra_class ) + h->i_idr_pic_id = 5; + else + h->i_idr_pic_id = 0; + + if( (uint64_t)h->param.i_timebase_den * 2 > UINT32_MAX ) + { + x264_log( h, X264_LOG_ERROR, "Effective timebase denominator %u exceeds H.264 maximum\n", h->param.i_timebase_den ); + goto fail; + } + + x264_set_aspect_ratio( h, &h->param, 1 ); + + x264_sps_init( h->sps, h->param.i_sps_id, &h->param ); + x264_pps_init( h->pps, h->param.i_sps_id, &h->param, h->sps ); + + x264_validate_levels( h, 1 ); + + h->chroma_qp_table = i_chroma_qp_table + 12 + h->pps->i_chroma_qp_index_offset; + + if( x264_cqm_init( h ) < 0 ) + goto fail; + + h->mb.i_mb_width = h->sps->i_mb_width; + h->mb.i_mb_height = h->sps->i_mb_height; + h->mb.i_mb_count = h->mb.i_mb_width * h->mb.i_mb_height; + + h->mb.chroma_h_shift = CHROMA_FORMAT == CHROMA_420 || CHROMA_FORMAT == CHROMA_422; + h->mb.chroma_v_shift = CHROMA_FORMAT == CHROMA_420; + + /* Adaptive MBAFF and subme 0 are not supported as we require halving motion + * vectors during prediction, resulting in hpel mvs. + * The chosen solution is to make MBAFF non-adaptive in this case. */ + h->mb.b_adaptive_mbaff = PARAM_INTERLACED && h->param.analyse.i_subpel_refine; + + /* Init frames. */ + if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS && !h->param.rc.b_stat_read ) + h->frames.i_delay = X264_MAX(h->param.i_bframe,3)*4; + else + h->frames.i_delay = h->param.i_bframe; + if( h->param.rc.b_mb_tree || h->param.rc.i_vbv_buffer_size ) + h->frames.i_delay = X264_MAX( h->frames.i_delay, h->param.rc.i_lookahead ); + i_slicetype_length = h->frames.i_delay; + h->frames.i_delay += h->i_thread_frames - 1; + h->frames.i_delay += h->param.i_sync_lookahead; + h->frames.i_delay += h->param.b_vfr_input; + h->frames.i_bframe_delay = h->param.i_bframe ? (h->param.i_bframe_pyramid ? 2 : 1) : 0; + + h->frames.i_max_ref0 = h->param.i_frame_reference; + h->frames.i_max_ref1 = X264_MIN( h->sps->vui.i_num_reorder_frames, h->param.i_frame_reference ); + h->frames.i_max_dpb = h->sps->vui.i_max_dec_frame_buffering; + h->frames.b_have_lowres = !h->param.rc.b_stat_read + && ( h->param.rc.i_rc_method == X264_RC_ABR + || h->param.rc.i_rc_method == X264_RC_CRF + || h->param.i_bframe_adaptive + || h->param.i_scenecut_threshold + || h->param.rc.b_mb_tree + || h->param.analyse.i_weighted_pred ); + h->frames.b_have_lowres |= h->param.rc.b_stat_read && h->param.rc.i_vbv_buffer_size > 0; + h->frames.b_have_sub8x8_esa = !!(h->param.analyse.inter & X264_ANALYSE_PSUB8x8); + + h->frames.i_last_idr = + h->frames.i_last_keyframe = - h->param.i_keyint_max; + h->frames.i_input = 0; + h->frames.i_largest_pts = h->frames.i_second_largest_pts = -1; + h->frames.i_poc_last_open_gop = -1; + + CHECKED_MALLOCZERO( h->frames.unused[0], (h->frames.i_delay + 3) * sizeof(x264_frame_t *) ); + /* Allocate room for max refs plus a few extra just in case. */ + CHECKED_MALLOCZERO( h->frames.unused[1], (h->i_thread_frames + X264_REF_MAX + 4) * sizeof(x264_frame_t *) ); + CHECKED_MALLOCZERO( h->frames.current, (h->param.i_sync_lookahead + h->param.i_bframe + + h->i_thread_frames + 3) * sizeof(x264_frame_t *) ); + if( h->param.analyse.i_weighted_pred > 0 ) + CHECKED_MALLOCZERO( h->frames.blank_unused, h->i_thread_frames * 4 * sizeof(x264_frame_t *) ); + h->i_ref[0] = h->i_ref[1] = 0; + h->i_cpb_delay = h->i_coded_fields = h->i_disp_fields = 0; + h->i_prev_duration = ((uint64_t)h->param.i_fps_den * h->sps->vui.i_time_scale) / ((uint64_t)h->param.i_fps_num * h->sps->vui.i_num_units_in_tick); + h->i_disp_fields_last_frame = -1; + x264_rdo_init(); + + /* init CPU functions */ +#if (ARCH_X86 || ARCH_X86_64) && HIGH_BIT_DEPTH + /* FIXME: Only 8-bit has been optimized for AVX-512 so far. The few AVX-512 functions + * enabled in high bit-depth are insignificant and just causes potential issues with + * unnecessary thermal throttling and whatnot, so keep it disabled for now. */ + h->param.cpu &= ~X264_CPU_AVX512; +#endif + x264_predict_16x16_init( h->param.cpu, h->predict_16x16 ); + x264_predict_8x8c_init( h->param.cpu, h->predict_8x8c ); + x264_predict_8x16c_init( h->param.cpu, h->predict_8x16c ); + x264_predict_8x8_init( h->param.cpu, h->predict_8x8, &h->predict_8x8_filter ); + x264_predict_4x4_init( h->param.cpu, h->predict_4x4 ); + x264_pixel_init( h->param.cpu, &h->pixf ); + x264_dct_init( h->param.cpu, &h->dctf ); + x264_zigzag_init( h->param.cpu, &h->zigzagf_progressive, &h->zigzagf_interlaced ); + memcpy( &h->zigzagf, PARAM_INTERLACED ? &h->zigzagf_interlaced : &h->zigzagf_progressive, sizeof(h->zigzagf) ); + x264_mc_init( h->param.cpu, &h->mc, h->param.b_cpu_independent ); + x264_quant_init( h, h->param.cpu, &h->quantf ); + x264_deblock_init( h->param.cpu, &h->loopf, PARAM_INTERLACED ); + x264_bitstream_init( h->param.cpu, &h->bsf ); + if( h->param.b_cabac ) + x264_cabac_init( h ); + else + x264_stack_align( x264_cavlc_init, h ); + + mbcmp_init( h ); + chroma_dsp_init( h ); + + p = buf + sprintf( buf, "using cpu capabilities:" ); + for( int i = 0; x264_cpu_names[i].flags; i++ ) + { + if( !strcmp(x264_cpu_names[i].name, "SSE") + && h->param.cpu & (X264_CPU_SSE2) ) + continue; + if( !strcmp(x264_cpu_names[i].name, "SSE2") + && h->param.cpu & (X264_CPU_SSE2_IS_FAST|X264_CPU_SSE2_IS_SLOW) ) + continue; + if( !strcmp(x264_cpu_names[i].name, "SSE3") + && (h->param.cpu & X264_CPU_SSSE3 || !(h->param.cpu & X264_CPU_CACHELINE_64)) ) + continue; + if( !strcmp(x264_cpu_names[i].name, "SSE4.1") + && (h->param.cpu & X264_CPU_SSE42) ) + continue; + if( !strcmp(x264_cpu_names[i].name, "LZCNT") + && (h->param.cpu & X264_CPU_BMI1) ) + continue; + if( !strcmp(x264_cpu_names[i].name, "BMI1") + && (h->param.cpu & X264_CPU_BMI2) ) + continue; + if( !strcmp(x264_cpu_names[i].name, "FMA4") + && (h->param.cpu & X264_CPU_FMA3) ) + continue; + if( (h->param.cpu & x264_cpu_names[i].flags) == x264_cpu_names[i].flags + && (!i || x264_cpu_names[i].flags != x264_cpu_names[i-1].flags) ) + p += sprintf( p, " %s", x264_cpu_names[i].name ); + } + if( !h->param.cpu ) + p += sprintf( p, " none!" ); + x264_log( h, X264_LOG_INFO, "%s\n", buf ); + + if( x264_analyse_init_costs( h ) ) + goto fail; + + /* Must be volatile or else GCC will optimize it out. */ + volatile int temp = 392; + if( x264_clz( temp ) != 23 ) + { + x264_log( h, X264_LOG_ERROR, "CLZ test failed: x264 has been miscompiled!\n" ); +#if ARCH_X86 || ARCH_X86_64 + x264_log( h, X264_LOG_ERROR, "Are you attempting to run an SSE4a/LZCNT-targeted build on a CPU that\n" ); + x264_log( h, X264_LOG_ERROR, "doesn't support it?\n" ); +#endif + goto fail; + } + + h->out.i_nal = 0; + h->out.i_bitstream = X264_MAX( 1000000, h->param.i_width * h->param.i_height * 4 + * ( h->param.rc.i_rc_method == X264_RC_ABR ? pow( 0.95, h->param.rc.i_qp_min ) + : pow( 0.95, h->param.rc.i_qp_constant ) * X264_MAX( 1, h->param.rc.f_ip_factor ))); + + h->nal_buffer_size = h->out.i_bitstream * 3/2 + 4 + 64; /* +4 for startcode, +64 for nal_escape assembly padding */ + CHECKED_MALLOC( h->nal_buffer, h->nal_buffer_size ); + + CHECKED_MALLOC( h->reconfig_h, sizeof(x264_t) ); + + if( h->param.i_threads > 1 && + x264_threadpool_init( &h->threadpool, h->param.i_threads, (void*)x264_encoder_thread_init, h ) ) + goto fail; + if( h->param.i_lookahead_threads > 1 && + x264_threadpool_init( &h->lookaheadpool, h->param.i_lookahead_threads, NULL, NULL ) ) + goto fail; + +#if HAVE_OPENCL + if( h->param.b_opencl ) + { + h->opencl.ocl = x264_opencl_load_library(); + if( !h->opencl.ocl ) + { + x264_log( h, X264_LOG_WARNING, "failed to load OpenCL\n" ); + h->param.b_opencl = 0; + } + } +#endif + + h->thread[0] = h; + for( int i = 1; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) + CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); + if( h->param.i_lookahead_threads > 1 ) + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) + { + CHECKED_MALLOC( h->lookahead_thread[i], sizeof(x264_t) ); + *h->lookahead_thread[i] = *h; + } + *h->reconfig_h = *h; + + for( int i = 0; i < h->param.i_threads; i++ ) + { + int init_nal_count = h->param.i_slice_count + 3; + int allocate_threadlocal_data = !h->param.b_sliced_threads || !i; + if( i > 0 ) + *h->thread[i] = *h; + + if( x264_pthread_mutex_init( &h->thread[i]->mutex, NULL ) ) + goto fail; + if( x264_pthread_cond_init( &h->thread[i]->cv, NULL ) ) + goto fail; + + if( allocate_threadlocal_data ) + { + h->thread[i]->fdec = x264_frame_pop_unused( h, 1 ); + if( !h->thread[i]->fdec ) + goto fail; + } + else + h->thread[i]->fdec = h->thread[0]->fdec; + + CHECKED_MALLOC( h->thread[i]->out.p_bitstream, h->out.i_bitstream ); + /* Start each thread with room for init_nal_count NAL units; it'll realloc later if needed. */ + CHECKED_MALLOC( h->thread[i]->out.nal, init_nal_count*sizeof(x264_nal_t) ); + h->thread[i]->out.i_nals_allocated = init_nal_count; + + if( allocate_threadlocal_data && x264_macroblock_cache_allocate( h->thread[i] ) < 0 ) + goto fail; + } + +#if HAVE_OPENCL + if( h->param.b_opencl && x264_opencl_lookahead_init( h ) < 0 ) + h->param.b_opencl = 0; +#endif + + if( x264_lookahead_init( h, i_slicetype_length ) ) + goto fail; + + for( int i = 0; i < h->param.i_threads; i++ ) + if( x264_macroblock_thread_allocate( h->thread[i], 0 ) < 0 ) + goto fail; + + if( x264_ratecontrol_new( h ) < 0 ) + goto fail; + + if( h->param.i_nal_hrd ) + { + x264_log( h, X264_LOG_DEBUG, "HRD bitrate: %i bits/sec\n", h->sps->vui.hrd.i_bit_rate_unscaled ); + x264_log( h, X264_LOG_DEBUG, "CPB size: %i bits\n", h->sps->vui.hrd.i_cpb_size_unscaled ); + } + + if( h->param.psz_dump_yuv ) + { + /* create or truncate the reconstructed video file */ + FILE *f = x264_fopen( h->param.psz_dump_yuv, "w" ); + if( !f ) + { + x264_log( h, X264_LOG_ERROR, "dump_yuv: can't write to %s\n", h->param.psz_dump_yuv ); + goto fail; + } + else if( !x264_is_regular_file( f ) ) + { + x264_log( h, X264_LOG_ERROR, "dump_yuv: incompatible with non-regular file %s\n", h->param.psz_dump_yuv ); + fclose( f ); + goto fail; + } + fclose( f ); + } + + const char *profile = h->sps->i_profile_idc == PROFILE_BASELINE ? "Constrained Baseline" : + h->sps->i_profile_idc == PROFILE_MAIN ? "Main" : + h->sps->i_profile_idc == PROFILE_HIGH ? "High" : + h->sps->i_profile_idc == PROFILE_HIGH10 ? (h->sps->b_constraint_set3 == 1 ? "High 10 Intra" : "High 10") : + h->sps->i_profile_idc == PROFILE_HIGH422 ? (h->sps->b_constraint_set3 == 1 ? "High 4:2:2 Intra" : "High 4:2:2") : + h->sps->b_constraint_set3 == 1 ? "High 4:4:4 Intra" : "High 4:4:4 Predictive"; + char level[4]; + snprintf( level, sizeof(level), "%d.%d", h->sps->i_level_idc/10, h->sps->i_level_idc%10 ); + if( h->sps->i_level_idc == 9 || ( h->sps->i_level_idc == 11 && h->sps->b_constraint_set3 && + (h->sps->i_profile_idc == PROFILE_BASELINE || h->sps->i_profile_idc == PROFILE_MAIN) ) ) + strcpy( level, "1b" ); + + if( h->sps->i_profile_idc < PROFILE_HIGH10 ) + { + x264_log( h, X264_LOG_INFO, "profile %s, level %s\n", + profile, level ); + } + else + { + static const char * const subsampling[4] = { "4:0:0", "4:2:0", "4:2:2", "4:4:4" }; + x264_log( h, X264_LOG_INFO, "profile %s, level %s, %s %d-bit\n", + profile, level, subsampling[CHROMA_FORMAT], BIT_DEPTH ); + } + + return h; +fail: + x264_free( h ); + return NULL; +} + +/****************************************************************************/ +static int x264_encoder_try_reconfig( x264_t *h, x264_param_t *param, int *rc_reconfig ) +{ + *rc_reconfig = 0; + x264_set_aspect_ratio( h, param, 0 ); +#define COPY(var) h->param.var = param->var + COPY( i_frame_reference ); // but never uses more refs than initially specified + COPY( i_bframe_bias ); + if( h->param.i_scenecut_threshold ) + COPY( i_scenecut_threshold ); // can't turn it on or off, only vary the threshold + COPY( b_deblocking_filter ); + COPY( i_deblocking_filter_alphac0 ); + COPY( i_deblocking_filter_beta ); + COPY( i_frame_packing ); + COPY( analyse.inter ); + COPY( analyse.intra ); + COPY( analyse.i_direct_mv_pred ); + /* Scratch buffer prevents me_range from being increased for esa/tesa */ + if( h->param.analyse.i_me_method < X264_ME_ESA || param->analyse.i_me_range < h->param.analyse.i_me_range ) + COPY( analyse.i_me_range ); + COPY( analyse.i_noise_reduction ); + /* We can't switch out of subme=0 during encoding. */ + if( h->param.analyse.i_subpel_refine ) + COPY( analyse.i_subpel_refine ); + COPY( analyse.i_trellis ); + COPY( analyse.b_chroma_me ); + COPY( analyse.b_dct_decimate ); + COPY( analyse.b_fast_pskip ); + COPY( analyse.b_mixed_references ); + COPY( analyse.f_psy_rd ); + COPY( analyse.f_psy_trellis ); + COPY( crop_rect ); + // can only twiddle these if they were enabled to begin with: + if( h->param.analyse.i_me_method >= X264_ME_ESA || param->analyse.i_me_method < X264_ME_ESA ) + COPY( analyse.i_me_method ); + if( h->param.analyse.i_me_method >= X264_ME_ESA && !h->frames.b_have_sub8x8_esa ) + h->param.analyse.inter &= ~X264_ANALYSE_PSUB8x8; + if( h->pps->b_transform_8x8_mode ) + COPY( analyse.b_transform_8x8 ); + if( h->frames.i_max_ref1 > 1 ) + COPY( i_bframe_pyramid ); + COPY( i_slice_max_size ); + COPY( i_slice_max_mbs ); + COPY( i_slice_min_mbs ); + COPY( i_slice_count ); + COPY( i_slice_count_max ); + COPY( b_tff ); + + /* VBV can't be turned on if it wasn't on to begin with */ + if( h->param.rc.i_vbv_max_bitrate > 0 && h->param.rc.i_vbv_buffer_size > 0 && + param->rc.i_vbv_max_bitrate > 0 && param->rc.i_vbv_buffer_size > 0 ) + { + *rc_reconfig |= h->param.rc.i_vbv_max_bitrate != param->rc.i_vbv_max_bitrate; + *rc_reconfig |= h->param.rc.i_vbv_buffer_size != param->rc.i_vbv_buffer_size; + *rc_reconfig |= h->param.rc.i_bitrate != param->rc.i_bitrate; + COPY( rc.i_vbv_max_bitrate ); + COPY( rc.i_vbv_buffer_size ); + COPY( rc.i_bitrate ); + } + *rc_reconfig |= h->param.rc.f_rf_constant != param->rc.f_rf_constant; + *rc_reconfig |= h->param.rc.f_rf_constant_max != param->rc.f_rf_constant_max; + COPY( rc.f_rf_constant ); + COPY( rc.f_rf_constant_max ); +#undef COPY + + return x264_validate_parameters( h, 0 ); +} + +int x264_encoder_reconfig_apply( x264_t *h, x264_param_t *param ) +{ + int rc_reconfig; + int ret = x264_encoder_try_reconfig( h, param, &rc_reconfig ); + + mbcmp_init( h ); + if( !ret ) + x264_sps_init_reconfigurable( h->sps, &h->param ); + + /* Supported reconfiguration options (1-pass only): + * vbv-maxrate + * vbv-bufsize + * crf + * bitrate (CBR only) */ + if( !ret && rc_reconfig ) + x264_ratecontrol_init_reconfigurable( h, 0 ); + + return ret; +} + +/**************************************************************************** + * x264_encoder_reconfig: + ****************************************************************************/ +int x264_encoder_reconfig( x264_t *h, x264_param_t *param ) +{ + h = h->thread[h->thread[0]->i_thread_phase]; + x264_param_t param_save = h->reconfig_h->param; + h->reconfig_h->param = h->param; + + int rc_reconfig; + int ret = x264_encoder_try_reconfig( h->reconfig_h, param, &rc_reconfig ); + if( !ret ) + h->reconfig = 1; + else + h->reconfig_h->param = param_save; + + return ret; +} + +/**************************************************************************** + * x264_encoder_parameters: + ****************************************************************************/ +void x264_encoder_parameters( x264_t *h, x264_param_t *param ) +{ + memcpy( param, &h->thread[h->i_thread_phase]->param, sizeof(x264_param_t) ); +} + +/* internal usage */ +static void x264_nal_start( x264_t *h, int i_type, int i_ref_idc ) +{ + x264_nal_t *nal = &h->out.nal[h->out.i_nal]; + + nal->i_ref_idc = i_ref_idc; + nal->i_type = i_type; + nal->b_long_startcode = 1; + + nal->i_payload= 0; + nal->p_payload= &h->out.p_bitstream[bs_pos( &h->out.bs ) / 8]; + nal->i_padding= 0; +} + +/* if number of allocated nals is not enough, re-allocate a larger one. */ +static int x264_nal_check_buffer( x264_t *h ) +{ + if( h->out.i_nal >= h->out.i_nals_allocated ) + { + x264_nal_t *new_out = x264_malloc( sizeof(x264_nal_t) * (h->out.i_nals_allocated*2) ); + if( !new_out ) + return -1; + memcpy( new_out, h->out.nal, sizeof(x264_nal_t) * (h->out.i_nals_allocated) ); + x264_free( h->out.nal ); + h->out.nal = new_out; + h->out.i_nals_allocated *= 2; + } + return 0; +} + +static int x264_nal_end( x264_t *h ) +{ + x264_nal_t *nal = &h->out.nal[h->out.i_nal]; + uint8_t *end = &h->out.p_bitstream[bs_pos( &h->out.bs ) / 8]; + nal->i_payload = end - nal->p_payload; + /* Assembly implementation of nal_escape reads past the end of the input. + * While undefined padding wouldn't actually affect the output, it makes valgrind unhappy. */ + memset( end, 0xff, 64 ); + if( h->param.nalu_process ) + h->param.nalu_process( h, nal, h->fenc->opaque ); + h->out.i_nal++; + + return x264_nal_check_buffer( h ); +} + +static int x264_check_encapsulated_buffer( x264_t *h, x264_t *h0, int start, + int previous_nal_size, int necessary_size ) +{ + if( h0->nal_buffer_size < necessary_size ) + { + necessary_size *= 2; + uint8_t *buf = x264_malloc( necessary_size ); + if( !buf ) + return -1; + if( previous_nal_size ) + memcpy( buf, h0->nal_buffer, previous_nal_size ); + + intptr_t delta = buf - h0->nal_buffer; + for( int i = 0; i < start; i++ ) + h->out.nal[i].p_payload += delta; + + x264_free( h0->nal_buffer ); + h0->nal_buffer = buf; + h0->nal_buffer_size = necessary_size; + } + + return 0; +} + +static int x264_encoder_encapsulate_nals( x264_t *h, int start ) +{ + x264_t *h0 = h->thread[0]; + int nal_size = 0, previous_nal_size = 0; + + if( h->param.nalu_process ) + { + for( int i = start; i < h->out.i_nal; i++ ) + nal_size += h->out.nal[i].i_payload; + return nal_size; + } + + for( int i = 0; i < start; i++ ) + previous_nal_size += h->out.nal[i].i_payload; + + for( int i = start; i < h->out.i_nal; i++ ) + nal_size += h->out.nal[i].i_payload; + + /* Worst-case NAL unit escaping: reallocate the buffer if it's too small. */ + int necessary_size = previous_nal_size + nal_size * 3/2 + h->out.i_nal * 4 + 4 + 64; + for( int i = start; i < h->out.i_nal; i++ ) + necessary_size += h->out.nal[i].i_padding; + if( x264_check_encapsulated_buffer( h, h0, start, previous_nal_size, necessary_size ) ) + return -1; + + uint8_t *nal_buffer = h0->nal_buffer + previous_nal_size; + + for( int i = start; i < h->out.i_nal; i++ ) + { + h->out.nal[i].b_long_startcode = !i || h->out.nal[i].i_type == NAL_SPS || h->out.nal[i].i_type == NAL_PPS || + h->param.i_avcintra_class; + x264_nal_encode( h, nal_buffer, &h->out.nal[i] ); + nal_buffer += h->out.nal[i].i_payload; + } + + x264_emms(); + + return nal_buffer - (h0->nal_buffer + previous_nal_size); +} + +/**************************************************************************** + * x264_encoder_headers: + ****************************************************************************/ +int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal ) +{ + int frame_size = 0; + /* init bitstream context */ + h->out.i_nal = 0; + bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream ); + + /* Write SEI, SPS and PPS. */ + + /* generate sequence parameters */ + x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST ); + x264_sps_write( &h->out.bs, h->sps ); + if( x264_nal_end( h ) ) + return -1; + + /* generate picture parameters */ + x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); + x264_pps_write( &h->out.bs, h->sps, h->pps ); + if( x264_nal_end( h ) ) + return -1; + + /* identify ourselves */ + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + if( x264_sei_version_write( h, &h->out.bs ) ) + return -1; + if( x264_nal_end( h ) ) + return -1; + + frame_size = x264_encoder_encapsulate_nals( h, 0 ); + if( frame_size < 0 ) + return -1; + + /* now set output*/ + *pi_nal = h->out.i_nal; + *pp_nal = &h->out.nal[0]; + h->out.i_nal = 0; + + return frame_size; +} + +/* Check to see whether we have chosen a reference list ordering different + * from the standard's default. */ +static inline void x264_reference_check_reorder( x264_t *h ) +{ + /* The reorder check doesn't check for missing frames, so just + * force a reorder if one of the reference list is corrupt. */ + for( int i = 0; h->frames.reference[i]; i++ ) + if( h->frames.reference[i]->b_corrupt ) + { + h->b_ref_reorder[0] = 1; + return; + } + for( int list = 0; list <= (h->sh.i_type == SLICE_TYPE_B); list++ ) + for( int i = 0; i < h->i_ref[list] - 1; i++ ) + { + int framenum_diff = h->fref[list][i+1]->i_frame_num - h->fref[list][i]->i_frame_num; + int poc_diff = h->fref[list][i+1]->i_poc - h->fref[list][i]->i_poc; + /* P and B-frames use different default orders. */ + if( h->sh.i_type == SLICE_TYPE_P ? framenum_diff > 0 : list == 1 ? poc_diff < 0 : poc_diff > 0 ) + { + h->b_ref_reorder[list] = 1; + return; + } + } +} + +/* return -1 on failure, else return the index of the new reference frame */ +static int x264_weighted_reference_duplicate( x264_t *h, int i_ref, const x264_weight_t *w ) +{ + int i = h->i_ref[0]; + int j = 1; + x264_frame_t *newframe; + if( i <= 1 ) /* empty list, definitely can't duplicate frame */ + return -1; + + //Duplication is only used in X264_WEIGHTP_SMART + if( h->param.analyse.i_weighted_pred != X264_WEIGHTP_SMART ) + return -1; + + /* Duplication is a hack to compensate for crappy rounding in motion compensation. + * With high bit depth, it's not worth doing, so turn it off except in the case of + * unweighted dupes. */ + if( BIT_DEPTH > 8 && w != x264_weight_none ) + return -1; + + newframe = x264_frame_pop_blank_unused( h ); + if( !newframe ) + return -1; + + //FIXME: probably don't need to copy everything + *newframe = *h->fref[0][i_ref]; + newframe->i_reference_count = 1; + newframe->orig = h->fref[0][i_ref]; + newframe->b_duplicate = 1; + memcpy( h->fenc->weight[j], w, sizeof(h->fenc->weight[i]) ); + + /* shift the frames to make space for the dupe. */ + h->b_ref_reorder[0] = 1; + if( h->i_ref[0] < X264_REF_MAX ) + ++h->i_ref[0]; + h->fref[0][X264_REF_MAX-1] = NULL; + x264_frame_unshift( &h->fref[0][j], newframe ); + + return j; +} + +static void x264_weighted_pred_init( x264_t *h ) +{ + /* for now no analysis and set all weights to nothing */ + for( int i_ref = 0; i_ref < h->i_ref[0]; i_ref++ ) + h->fenc->weighted[i_ref] = h->fref[0][i_ref]->filtered[0][0]; + + // FIXME: This only supports weighting of one reference frame + // and duplicates of that frame. + h->fenc->i_lines_weighted = 0; + + for( int i_ref = 0; i_ref < (h->i_ref[0] << SLICE_MBAFF); i_ref++ ) + for( int i = 0; i < 3; i++ ) + h->sh.weight[i_ref][i].weightfn = NULL; + + + if( h->sh.i_type != SLICE_TYPE_P || h->param.analyse.i_weighted_pred <= 0 ) + return; + + int i_padv = PADV << PARAM_INTERLACED; + int denom = -1; + int weightplane[2] = { 0, 0 }; + int buffer_next = 0; + for( int i = 0; i < 3; i++ ) + { + for( int j = 0; j < h->i_ref[0]; j++ ) + { + if( h->fenc->weight[j][i].weightfn ) + { + h->sh.weight[j][i] = h->fenc->weight[j][i]; + // if weight is useless, don't write it to stream + if( h->sh.weight[j][i].i_scale == 1<sh.weight[j][i].i_denom && h->sh.weight[j][i].i_offset == 0 ) + h->sh.weight[j][i].weightfn = NULL; + else + { + if( !weightplane[!!i] ) + { + weightplane[!!i] = 1; + h->sh.weight[0][!!i].i_denom = denom = h->sh.weight[j][i].i_denom; + assert( x264_clip3( denom, 0, 7 ) == denom ); + } + + assert( h->sh.weight[j][i].i_denom == denom ); + if( !i ) + { + h->fenc->weighted[j] = h->mb.p_weight_buf[buffer_next++] + h->fenc->i_stride[0] * i_padv + PADH; + //scale full resolution frame + if( h->param.i_threads == 1 ) + { + pixel *src = h->fref[0][j]->filtered[0][0] - h->fref[0][j]->i_stride[0]*i_padv - PADH; + pixel *dst = h->fenc->weighted[j] - h->fenc->i_stride[0]*i_padv - PADH; + int stride = h->fenc->i_stride[0]; + int width = h->fenc->i_width[0] + PADH*2; + int height = h->fenc->i_lines[0] + i_padv*2; + x264_weight_scale_plane( h, dst, stride, src, stride, width, height, &h->sh.weight[j][0] ); + h->fenc->i_lines_weighted = height; + } + } + } + } + } + } + + if( weightplane[1] ) + for( int i = 0; i < h->i_ref[0]; i++ ) + { + if( h->sh.weight[i][1].weightfn && !h->sh.weight[i][2].weightfn ) + { + h->sh.weight[i][2].i_scale = 1 << h->sh.weight[0][1].i_denom; + h->sh.weight[i][2].i_offset = 0; + } + else if( h->sh.weight[i][2].weightfn && !h->sh.weight[i][1].weightfn ) + { + h->sh.weight[i][1].i_scale = 1 << h->sh.weight[0][1].i_denom; + h->sh.weight[i][1].i_offset = 0; + } + } + + if( !weightplane[0] ) + h->sh.weight[0][0].i_denom = 0; + if( !weightplane[1] ) + h->sh.weight[0][1].i_denom = 0; + h->sh.weight[0][2].i_denom = h->sh.weight[0][1].i_denom; +} + +static inline int x264_reference_distance( x264_t *h, x264_frame_t *frame ) +{ + if( h->param.i_frame_packing == 5 ) + return abs((h->fenc->i_frame&~1) - (frame->i_frame&~1)) + + ((h->fenc->i_frame&1) != (frame->i_frame&1)); + else + return abs(h->fenc->i_frame - frame->i_frame); +} + +static inline void x264_reference_build_list( x264_t *h, int i_poc ) +{ + int b_ok; + + /* build ref list 0/1 */ + h->mb.pic.i_fref[0] = h->i_ref[0] = 0; + h->mb.pic.i_fref[1] = h->i_ref[1] = 0; + if( h->sh.i_type == SLICE_TYPE_I ) + return; + + for( int i = 0; h->frames.reference[i]; i++ ) + { + if( h->frames.reference[i]->b_corrupt ) + continue; + if( h->frames.reference[i]->i_poc < i_poc ) + h->fref[0][h->i_ref[0]++] = h->frames.reference[i]; + else if( h->frames.reference[i]->i_poc > i_poc ) + h->fref[1][h->i_ref[1]++] = h->frames.reference[i]; + } + + if( h->sh.i_mmco_remove_from_end ) + { + /* Order ref0 for MMCO remove */ + do + { + b_ok = 1; + for( int i = 0; i < h->i_ref[0] - 1; i++ ) + { + if( h->fref[0][i]->i_frame < h->fref[0][i+1]->i_frame ) + { + XCHG( x264_frame_t*, h->fref[0][i], h->fref[0][i+1] ); + b_ok = 0; + break; + } + } + } while( !b_ok ); + + for( int i = h->i_ref[0]-1; i >= h->i_ref[0] - h->sh.i_mmco_remove_from_end; i-- ) + { + int diff = h->i_frame_num - h->fref[0][i]->i_frame_num; + h->sh.mmco[h->sh.i_mmco_command_count].i_poc = h->fref[0][i]->i_poc; + h->sh.mmco[h->sh.i_mmco_command_count++].i_difference_of_pic_nums = diff; + } + } + + /* Order reference lists by distance from the current frame. */ + for( int list = 0; list < 2; list++ ) + { + h->fref_nearest[list] = h->fref[list][0]; + do + { + b_ok = 1; + for( int i = 0; i < h->i_ref[list] - 1; i++ ) + { + if( list ? h->fref[list][i+1]->i_poc < h->fref_nearest[list]->i_poc + : h->fref[list][i+1]->i_poc > h->fref_nearest[list]->i_poc ) + h->fref_nearest[list] = h->fref[list][i+1]; + if( x264_reference_distance( h, h->fref[list][i] ) > x264_reference_distance( h, h->fref[list][i+1] ) ) + { + XCHG( x264_frame_t*, h->fref[list][i], h->fref[list][i+1] ); + b_ok = 0; + break; + } + } + } while( !b_ok ); + } + + x264_reference_check_reorder( h ); + + h->i_ref[1] = X264_MIN( h->i_ref[1], h->frames.i_max_ref1 ); + h->i_ref[0] = X264_MIN( h->i_ref[0], h->frames.i_max_ref0 ); + h->i_ref[0] = X264_MIN( h->i_ref[0], h->param.i_frame_reference ); // if reconfig() has lowered the limit + + /* For Blu-ray compliance, don't reference frames outside of the minigop. */ + if( IS_X264_TYPE_B( h->fenc->i_type ) && h->param.b_bluray_compat ) + h->i_ref[0] = X264_MIN( h->i_ref[0], IS_X264_TYPE_B( h->fref[0][0]->i_type ) + 1 ); + + /* add duplicates */ + if( h->fenc->i_type == X264_TYPE_P ) + { + int idx = -1; + if( h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE ) + { + x264_weight_t w[3]; + w[1].weightfn = w[2].weightfn = NULL; + if( h->param.rc.b_stat_read ) + x264_ratecontrol_set_weights( h, h->fenc ); + + if( !h->fenc->weight[0][0].weightfn ) + { + h->fenc->weight[0][0].i_denom = 0; + SET_WEIGHT( w[0], 1, 1, 0, -1 ); + idx = x264_weighted_reference_duplicate( h, 0, w ); + } + else + { + if( h->fenc->weight[0][0].i_scale == 1<fenc->weight[0][0].i_denom ) + { + SET_WEIGHT( h->fenc->weight[0][0], 1, 1, 0, h->fenc->weight[0][0].i_offset ); + } + x264_weighted_reference_duplicate( h, 0, x264_weight_none ); + if( h->fenc->weight[0][0].i_offset > -128 ) + { + w[0] = h->fenc->weight[0][0]; + w[0].i_offset--; + h->mc.weight_cache( h, &w[0] ); + idx = x264_weighted_reference_duplicate( h, 0, w ); + } + } + } + h->mb.ref_blind_dupe = idx; + } + + assert( h->i_ref[0] + h->i_ref[1] <= X264_REF_MAX ); + h->mb.pic.i_fref[0] = h->i_ref[0]; + h->mb.pic.i_fref[1] = h->i_ref[1]; +} + +static void x264_fdec_filter_row( x264_t *h, int mb_y, int pass ) +{ + /* mb_y is the mb to be encoded next, not the mb to be filtered here */ + int b_hpel = h->fdec->b_kept_as_ref; + int b_deblock = h->sh.i_disable_deblocking_filter_idc != 1; + int b_end = mb_y == h->i_threadslice_end; + int b_measure_quality = 1; + int min_y = mb_y - (1 << SLICE_MBAFF); + int b_start = min_y == h->i_threadslice_start; + /* Even in interlaced mode, deblocking never modifies more than 4 pixels + * above each MB, as bS=4 doesn't happen for the top of interlaced mbpairs. */ + int minpix_y = min_y*16 - 4 * !b_start; + int maxpix_y = mb_y*16 - 4 * !b_end; + b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv; + if( h->param.b_sliced_threads ) + { + switch( pass ) + { + /* During encode: only do deblock if asked for */ + default: + case 0: + b_deblock &= h->param.b_full_recon; + b_hpel = 0; + break; + /* During post-encode pass: do deblock if not done yet, do hpel for all + * rows except those between slices. */ + case 1: + b_deblock &= !h->param.b_full_recon; + b_hpel &= !(b_start && min_y > 0); + b_measure_quality = 0; + break; + /* Final pass: do the rows between slices in sequence. */ + case 2: + b_deblock = 0; + b_measure_quality = 0; + break; + } + } + if( mb_y & SLICE_MBAFF ) + return; + if( min_y < h->i_threadslice_start ) + return; + + if( b_deblock ) + for( int y = min_y; y < mb_y; y += (1 << SLICE_MBAFF) ) + x264_frame_deblock_row( h, y ); + + /* FIXME: Prediction requires different borders for interlaced/progressive mc, + * but the actual image data is equivalent. For now, maintain this + * consistency by copying deblocked pixels between planes. */ + if( PARAM_INTERLACED && (!h->param.b_sliced_threads || pass == 1) ) + for( int p = 0; p < h->fdec->i_plane; p++ ) + for( int i = minpix_y>>(CHROMA_V_SHIFT && p); i < maxpix_y>>(CHROMA_V_SHIFT && p); i++ ) + memcpy( h->fdec->plane_fld[p] + i*h->fdec->i_stride[p], + h->fdec->plane[p] + i*h->fdec->i_stride[p], + h->mb.i_mb_width*16*sizeof(pixel) ); + + if( h->fdec->b_kept_as_ref && (!h->param.b_sliced_threads || pass == 1) ) + x264_frame_expand_border( h, h->fdec, min_y ); + if( b_hpel ) + { + int end = mb_y == h->mb.i_mb_height; + /* Can't do hpel until the previous slice is done encoding. */ + if( h->param.analyse.i_subpel_refine ) + { + x264_frame_filter( h, h->fdec, min_y, end ); + x264_frame_expand_border_filtered( h, h->fdec, min_y, end ); + } + } + + if( SLICE_MBAFF && pass == 0 ) + for( int i = 0; i < 3; i++ ) + { + XCHG( pixel *, h->intra_border_backup[0][i], h->intra_border_backup[3][i] ); + XCHG( pixel *, h->intra_border_backup[1][i], h->intra_border_backup[4][i] ); + } + + if( h->i_thread_frames > 1 && h->fdec->b_kept_as_ref ) + x264_frame_cond_broadcast( h->fdec, mb_y*16 + (b_end ? 10000 : -(X264_THREAD_HEIGHT << SLICE_MBAFF)) ); + + if( b_measure_quality ) + { + maxpix_y = X264_MIN( maxpix_y, h->param.i_height ); + if( h->param.analyse.b_psnr ) + { + for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ ) + h->stat.frame.i_ssd[p] += x264_pixel_ssd_wxh( &h->pixf, + h->fdec->plane[p] + minpix_y * h->fdec->i_stride[p], h->fdec->i_stride[p], + h->fenc->plane[p] + minpix_y * h->fenc->i_stride[p], h->fenc->i_stride[p], + h->param.i_width, maxpix_y-minpix_y ); + if( !CHROMA444 ) + { + uint64_t ssd_u, ssd_v; + int v_shift = CHROMA_V_SHIFT; + x264_pixel_ssd_nv12( &h->pixf, + h->fdec->plane[1] + (minpix_y>>v_shift) * h->fdec->i_stride[1], h->fdec->i_stride[1], + h->fenc->plane[1] + (minpix_y>>v_shift) * h->fenc->i_stride[1], h->fenc->i_stride[1], + h->param.i_width>>1, (maxpix_y-minpix_y)>>v_shift, &ssd_u, &ssd_v ); + h->stat.frame.i_ssd[1] += ssd_u; + h->stat.frame.i_ssd[2] += ssd_v; + } + } + + if( h->param.analyse.b_ssim ) + { + int ssim_cnt; + x264_emms(); + /* offset by 2 pixels to avoid alignment of ssim blocks with dct blocks, + * and overlap by 4 */ + minpix_y += b_start ? 2 : -6; + h->stat.frame.f_ssim += + x264_pixel_ssim_wxh( &h->pixf, + h->fdec->plane[0] + 2+minpix_y*h->fdec->i_stride[0], h->fdec->i_stride[0], + h->fenc->plane[0] + 2+minpix_y*h->fenc->i_stride[0], h->fenc->i_stride[0], + h->param.i_width-2, maxpix_y-minpix_y, h->scratch_buffer, &ssim_cnt ); + h->stat.frame.i_ssim_cnt += ssim_cnt; + } + } +} + +static inline int x264_reference_update( x264_t *h ) +{ + if( !h->fdec->b_kept_as_ref ) + { + if( h->i_thread_frames > 1 ) + { + x264_frame_push_unused( h, h->fdec ); + h->fdec = x264_frame_pop_unused( h, 1 ); + if( !h->fdec ) + return -1; + } + return 0; + } + + /* apply mmco from previous frame. */ + for( int i = 0; i < h->sh.i_mmco_command_count; i++ ) + for( int j = 0; h->frames.reference[j]; j++ ) + if( h->frames.reference[j]->i_poc == h->sh.mmco[i].i_poc ) + x264_frame_push_unused( h, x264_frame_shift( &h->frames.reference[j] ) ); + + /* move frame in the buffer */ + x264_frame_push( h->frames.reference, h->fdec ); + if( h->frames.reference[h->sps->i_num_ref_frames] ) + x264_frame_push_unused( h, x264_frame_shift( h->frames.reference ) ); + h->fdec = x264_frame_pop_unused( h, 1 ); + if( !h->fdec ) + return -1; + return 0; +} + +static inline void x264_reference_reset( x264_t *h ) +{ + while( h->frames.reference[0] ) + x264_frame_push_unused( h, x264_frame_pop( h->frames.reference ) ); + h->fdec->i_poc = + h->fenc->i_poc = 0; +} + +static inline void x264_reference_hierarchy_reset( x264_t *h ) +{ + int ref; + int b_hasdelayframe = 0; + + /* look for delay frames -- chain must only contain frames that are disposable */ + for( int i = 0; h->frames.current[i] && IS_DISPOSABLE( h->frames.current[i]->i_type ); i++ ) + b_hasdelayframe |= h->frames.current[i]->i_coded + != h->frames.current[i]->i_frame + h->sps->vui.i_num_reorder_frames; + + /* This function must handle b-pyramid and clear frames for open-gop */ + if( h->param.i_bframe_pyramid != X264_B_PYRAMID_STRICT && !b_hasdelayframe && h->frames.i_poc_last_open_gop == -1 ) + return; + + /* Remove last BREF. There will never be old BREFs in the + * dpb during a BREF decode when pyramid == STRICT */ + for( ref = 0; h->frames.reference[ref]; ref++ ) + { + if( ( h->param.i_bframe_pyramid == X264_B_PYRAMID_STRICT + && h->frames.reference[ref]->i_type == X264_TYPE_BREF ) + || ( h->frames.reference[ref]->i_poc < h->frames.i_poc_last_open_gop + && h->sh.i_type != SLICE_TYPE_B ) ) + { + int diff = h->i_frame_num - h->frames.reference[ref]->i_frame_num; + h->sh.mmco[h->sh.i_mmco_command_count].i_difference_of_pic_nums = diff; + h->sh.mmco[h->sh.i_mmco_command_count++].i_poc = h->frames.reference[ref]->i_poc; + x264_frame_push_unused( h, x264_frame_shift( &h->frames.reference[ref] ) ); + h->b_ref_reorder[0] = 1; + ref--; + } + } + + /* Prepare room in the dpb for the delayed display time of the later b-frame's */ + if( h->param.i_bframe_pyramid ) + h->sh.i_mmco_remove_from_end = X264_MAX( ref + 2 - h->frames.i_max_dpb, 0 ); +} + +static inline void x264_slice_init( x264_t *h, int i_nal_type, int i_global_qp ) +{ + /* ------------------------ Create slice header ----------------------- */ + if( i_nal_type == NAL_SLICE_IDR ) + { + x264_slice_header_init( h, &h->sh, h->sps, h->pps, h->i_idr_pic_id, h->i_frame_num, i_global_qp ); + + /* alternate id */ + if( h->param.i_avcintra_class ) + { + switch( h->i_idr_pic_id ) + { + case 5: + h->i_idr_pic_id = 3; + break; + case 3: + h->i_idr_pic_id = 4; + break; + case 4: + default: + h->i_idr_pic_id = 5; + break; + } + } + else + h->i_idr_pic_id ^= 1; + } + else + { + x264_slice_header_init( h, &h->sh, h->sps, h->pps, -1, h->i_frame_num, i_global_qp ); + + h->sh.i_num_ref_idx_l0_active = h->i_ref[0] <= 0 ? 1 : h->i_ref[0]; + h->sh.i_num_ref_idx_l1_active = h->i_ref[1] <= 0 ? 1 : h->i_ref[1]; + if( h->sh.i_num_ref_idx_l0_active != h->pps->i_num_ref_idx_l0_default_active || + (h->sh.i_type == SLICE_TYPE_B && h->sh.i_num_ref_idx_l1_active != h->pps->i_num_ref_idx_l1_default_active) ) + { + h->sh.b_num_ref_idx_override = 1; + } + } + + if( h->fenc->i_type == X264_TYPE_BREF && h->param.b_bluray_compat && h->sh.i_mmco_command_count ) + { + h->b_sh_backup = 1; + h->sh_backup = h->sh; + } + + h->fdec->i_frame_num = h->sh.i_frame_num; + + if( h->sps->i_poc_type == 0 ) + { + h->sh.i_poc = h->fdec->i_poc; + if( PARAM_INTERLACED ) + { + h->sh.i_delta_poc_bottom = h->param.b_tff ? 1 : -1; + h->sh.i_poc += h->sh.i_delta_poc_bottom == -1; + } + else + h->sh.i_delta_poc_bottom = 0; + h->fdec->i_delta_poc[0] = h->sh.i_delta_poc_bottom == -1; + h->fdec->i_delta_poc[1] = h->sh.i_delta_poc_bottom == 1; + } + else + { + /* Nothing to do ? */ + } + + x264_macroblock_slice_init( h ); +} + +typedef struct +{ + int skip; + uint8_t cabac_prevbyte; + bs_t bs; + x264_cabac_t cabac; + x264_frame_stat_t stat; + int last_qp; + int last_dqp; + int field_decoding_flag; +} x264_bs_bak_t; + +static ALWAYS_INLINE void x264_bitstream_backup( x264_t *h, x264_bs_bak_t *bak, int i_skip, int full ) +{ + if( full ) + { + bak->stat = h->stat.frame; + bak->last_qp = h->mb.i_last_qp; + bak->last_dqp = h->mb.i_last_dqp; + bak->field_decoding_flag = h->mb.field_decoding_flag; + } + else + { + bak->stat.i_mv_bits = h->stat.frame.i_mv_bits; + bak->stat.i_tex_bits = h->stat.frame.i_tex_bits; + } + /* In the per-MB backup, we don't need the contexts because flushing the CABAC + * encoder has no context dependency and in this case, a slice is ended (and + * thus the content of all contexts are thrown away). */ + if( h->param.b_cabac ) + { + if( full ) + memcpy( &bak->cabac, &h->cabac, sizeof(x264_cabac_t) ); + else + memcpy( &bak->cabac, &h->cabac, offsetof(x264_cabac_t, f8_bits_encoded) ); + /* x264's CABAC writer modifies the previous byte during carry, so it has to be + * backed up. */ + bak->cabac_prevbyte = h->cabac.p[-1]; + } + else + { + bak->bs = h->out.bs; + bak->skip = i_skip; + } +} + +static ALWAYS_INLINE void x264_bitstream_restore( x264_t *h, x264_bs_bak_t *bak, int *skip, int full ) +{ + if( full ) + { + h->stat.frame = bak->stat; + h->mb.i_last_qp = bak->last_qp; + h->mb.i_last_dqp = bak->last_dqp; + h->mb.field_decoding_flag = bak->field_decoding_flag; + } + else + { + h->stat.frame.i_mv_bits = bak->stat.i_mv_bits; + h->stat.frame.i_tex_bits = bak->stat.i_tex_bits; + } + if( h->param.b_cabac ) + { + if( full ) + memcpy( &h->cabac, &bak->cabac, sizeof(x264_cabac_t) ); + else + memcpy( &h->cabac, &bak->cabac, offsetof(x264_cabac_t, f8_bits_encoded) ); + h->cabac.p[-1] = bak->cabac_prevbyte; + } + else + { + h->out.bs = bak->bs; + *skip = bak->skip; + } +} + +static intptr_t x264_slice_write( x264_t *h ) +{ + int i_skip; + int mb_xy, i_mb_x, i_mb_y; + /* NALUs other than the first use a 3-byte startcode. + * Add one extra byte for the rbsp, and one more for the final CABAC putbyte. + * Then add an extra 5 bytes just in case, to account for random NAL escapes and + * other inaccuracies. */ + int overhead_guess = (NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal)) + 1 + h->param.b_cabac + 5; + int slice_max_size = h->param.i_slice_max_size > 0 ? (h->param.i_slice_max_size-overhead_guess)*8 : 0; + int back_up_bitstream_cavlc = !h->param.b_cabac && h->sps->i_profile_idc < PROFILE_HIGH; + int back_up_bitstream = slice_max_size || back_up_bitstream_cavlc; + int starting_bits = bs_pos(&h->out.bs); + int b_deblock = h->sh.i_disable_deblocking_filter_idc != 1; + int b_hpel = h->fdec->b_kept_as_ref; + int orig_last_mb = h->sh.i_last_mb; + int thread_last_mb = h->i_threadslice_end * h->mb.i_mb_width - 1; + uint8_t *last_emu_check; +#define BS_BAK_SLICE_MAX_SIZE 0 +#define BS_BAK_CAVLC_OVERFLOW 1 +#define BS_BAK_SLICE_MIN_MBS 2 +#define BS_BAK_ROW_VBV 3 + x264_bs_bak_t bs_bak[4]; + b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv; + bs_realign( &h->out.bs ); + + /* Slice */ + x264_nal_start( h, h->i_nal_type, h->i_nal_ref_idc ); + h->out.nal[h->out.i_nal].i_first_mb = h->sh.i_first_mb; + + /* Slice header */ + x264_macroblock_thread_init( h ); + + /* Set the QP equal to the first QP in the slice for more accurate CABAC initialization. */ + h->mb.i_mb_xy = h->sh.i_first_mb; + h->sh.i_qp = x264_ratecontrol_mb_qp( h ); + h->sh.i_qp = SPEC_QP( h->sh.i_qp ); + h->sh.i_qp_delta = h->sh.i_qp - h->pps->i_pic_init_qp; + + x264_slice_header_write( &h->out.bs, &h->sh, h->i_nal_ref_idc ); + if( h->param.b_cabac ) + { + /* alignment needed */ + bs_align_1( &h->out.bs ); + + /* init cabac */ + x264_cabac_context_init( h, &h->cabac, h->sh.i_type, x264_clip3( h->sh.i_qp-QP_BD_OFFSET, 0, 51 ), h->sh.i_cabac_init_idc ); + x264_cabac_encode_init ( &h->cabac, h->out.bs.p, h->out.bs.p_end ); + last_emu_check = h->cabac.p; + } + else + last_emu_check = h->out.bs.p; + h->mb.i_last_qp = h->sh.i_qp; + h->mb.i_last_dqp = 0; + h->mb.field_decoding_flag = 0; + + i_mb_y = h->sh.i_first_mb / h->mb.i_mb_width; + i_mb_x = h->sh.i_first_mb % h->mb.i_mb_width; + i_skip = 0; + + while( 1 ) + { + mb_xy = i_mb_x + i_mb_y * h->mb.i_mb_width; + int mb_spos = bs_pos(&h->out.bs) + x264_cabac_pos(&h->cabac); + + if( i_mb_x == 0 ) + { + if( x264_bitstream_check_buffer( h ) ) + return -1; + if( !(i_mb_y & SLICE_MBAFF) && h->param.rc.i_vbv_buffer_size ) + x264_bitstream_backup( h, &bs_bak[BS_BAK_ROW_VBV], i_skip, 1 ); + if( !h->mb.b_reencode_mb ) + x264_fdec_filter_row( h, i_mb_y, 0 ); + } + + if( back_up_bitstream ) + { + if( back_up_bitstream_cavlc ) + x264_bitstream_backup( h, &bs_bak[BS_BAK_CAVLC_OVERFLOW], i_skip, 0 ); + if( slice_max_size && !(i_mb_y & SLICE_MBAFF) ) + { + x264_bitstream_backup( h, &bs_bak[BS_BAK_SLICE_MAX_SIZE], i_skip, 0 ); + if( (thread_last_mb+1-mb_xy) == h->param.i_slice_min_mbs ) + x264_bitstream_backup( h, &bs_bak[BS_BAK_SLICE_MIN_MBS], i_skip, 0 ); + } + } + + if( PARAM_INTERLACED ) + { + if( h->mb.b_adaptive_mbaff ) + { + if( !(i_mb_y&1) ) + { + /* FIXME: VSAD is fast but fairly poor at choosing the best interlace type. */ + h->mb.b_interlaced = x264_field_vsad( h, i_mb_x, i_mb_y ); + memcpy( &h->zigzagf, MB_INTERLACED ? &h->zigzagf_interlaced : &h->zigzagf_progressive, sizeof(h->zigzagf) ); + if( !MB_INTERLACED && (i_mb_y+2) == h->mb.i_mb_height ) + x264_expand_border_mbpair( h, i_mb_x, i_mb_y ); + } + } + h->mb.field[mb_xy] = MB_INTERLACED; + } + + /* load cache */ + if( SLICE_MBAFF ) + x264_macroblock_cache_load_interlaced( h, i_mb_x, i_mb_y ); + else + x264_macroblock_cache_load_progressive( h, i_mb_x, i_mb_y ); + + x264_macroblock_analyse( h ); + + /* encode this macroblock -> be careful it can change the mb type to P_SKIP if needed */ +reencode: + x264_macroblock_encode( h ); + + if( h->param.b_cabac ) + { + if( mb_xy > h->sh.i_first_mb && !(SLICE_MBAFF && (i_mb_y&1)) ) + x264_cabac_encode_terminal( &h->cabac ); + + if( IS_SKIP( h->mb.i_type ) ) + x264_cabac_mb_skip( h, 1 ); + else + { + if( h->sh.i_type != SLICE_TYPE_I ) + x264_cabac_mb_skip( h, 0 ); + x264_macroblock_write_cabac( h, &h->cabac ); + } + } + else + { + if( IS_SKIP( h->mb.i_type ) ) + i_skip++; + else + { + if( h->sh.i_type != SLICE_TYPE_I ) + { + bs_write_ue( &h->out.bs, i_skip ); /* skip run */ + i_skip = 0; + } + x264_macroblock_write_cavlc( h ); + /* If there was a CAVLC level code overflow, try again at a higher QP. */ + if( h->mb.b_overflow ) + { + h->mb.i_chroma_qp = h->chroma_qp_table[++h->mb.i_qp]; + h->mb.i_skip_intra = 0; + h->mb.b_skip_mc = 0; + h->mb.b_overflow = 0; + x264_bitstream_restore( h, &bs_bak[BS_BAK_CAVLC_OVERFLOW], &i_skip, 0 ); + goto reencode; + } + } + } + + int total_bits = bs_pos(&h->out.bs) + x264_cabac_pos(&h->cabac); + int mb_size = total_bits - mb_spos; + + if( slice_max_size && (!SLICE_MBAFF || (i_mb_y&1)) ) + { + /* Count the skip run, just in case. */ + if( !h->param.b_cabac ) + total_bits += bs_size_ue_big( i_skip ); + /* Check for escape bytes. */ + uint8_t *end = h->param.b_cabac ? h->cabac.p : h->out.bs.p; + for( ; last_emu_check < end - 2; last_emu_check++ ) + if( last_emu_check[0] == 0 && last_emu_check[1] == 0 && last_emu_check[2] <= 3 ) + { + slice_max_size -= 8; + last_emu_check++; + } + /* We'll just re-encode this last macroblock if we go over the max slice size. */ + if( total_bits - starting_bits > slice_max_size && !h->mb.b_reencode_mb ) + { + if( !x264_frame_new_slice( h, h->fdec ) ) + { + /* Handle the most obnoxious slice-min-mbs edge case: we need to end the slice + * because it's gone over the maximum size, but doing so would violate slice-min-mbs. + * If possible, roll back to the last checkpoint and try again. + * We could try raising QP, but that would break in the case where a slice spans multiple + * rows, which the re-encoding infrastructure can't currently handle. */ + if( mb_xy <= thread_last_mb && (thread_last_mb+1-mb_xy) < h->param.i_slice_min_mbs ) + { + if( thread_last_mb-h->param.i_slice_min_mbs < h->sh.i_first_mb+h->param.i_slice_min_mbs ) + { + x264_log( h, X264_LOG_WARNING, "slice-max-size violated (frame %d, cause: slice-min-mbs)\n", h->i_frame ); + slice_max_size = 0; + goto cont; + } + x264_bitstream_restore( h, &bs_bak[BS_BAK_SLICE_MIN_MBS], &i_skip, 0 ); + h->mb.b_reencode_mb = 1; + h->sh.i_last_mb = thread_last_mb-h->param.i_slice_min_mbs; + break; + } + if( mb_xy-SLICE_MBAFF*h->mb.i_mb_stride != h->sh.i_first_mb ) + { + x264_bitstream_restore( h, &bs_bak[BS_BAK_SLICE_MAX_SIZE], &i_skip, 0 ); + h->mb.b_reencode_mb = 1; + if( SLICE_MBAFF ) + { + // set to bottom of previous mbpair + if( i_mb_x ) + h->sh.i_last_mb = mb_xy-1+h->mb.i_mb_stride*(!(i_mb_y&1)); + else + h->sh.i_last_mb = (i_mb_y-2+!(i_mb_y&1))*h->mb.i_mb_stride + h->mb.i_mb_width - 1; + } + else + h->sh.i_last_mb = mb_xy-1; + break; + } + else + h->sh.i_last_mb = mb_xy; + } + else + slice_max_size = 0; + } + } +cont: + h->mb.b_reencode_mb = 0; + + /* save cache */ + x264_macroblock_cache_save( h ); + + if( x264_ratecontrol_mb( h, mb_size ) < 0 ) + { + x264_bitstream_restore( h, &bs_bak[BS_BAK_ROW_VBV], &i_skip, 1 ); + h->mb.b_reencode_mb = 1; + i_mb_x = 0; + i_mb_y = i_mb_y - SLICE_MBAFF; + h->mb.i_mb_prev_xy = i_mb_y * h->mb.i_mb_stride - 1; + h->sh.i_last_mb = orig_last_mb; + continue; + } + + /* accumulate mb stats */ + h->stat.frame.i_mb_count[h->mb.i_type]++; + + int b_intra = IS_INTRA( h->mb.i_type ); + int b_skip = IS_SKIP( h->mb.i_type ); + if( h->param.i_log_level >= X264_LOG_INFO || h->param.rc.b_stat_write ) + { + if( !b_intra && !b_skip && !IS_DIRECT( h->mb.i_type ) ) + { + if( h->mb.i_partition != D_8x8 ) + h->stat.frame.i_mb_partition[h->mb.i_partition] += 4; + else + for( int i = 0; i < 4; i++ ) + h->stat.frame.i_mb_partition[h->mb.i_sub_partition[i]] ++; + if( h->param.i_frame_reference > 1 ) + for( int i_list = 0; i_list <= (h->sh.i_type == SLICE_TYPE_B); i_list++ ) + for( int i = 0; i < 4; i++ ) + { + int i_ref = h->mb.cache.ref[i_list][ x264_scan8[4*i] ]; + if( i_ref >= 0 ) + h->stat.frame.i_mb_count_ref[i_list][i_ref] ++; + } + } + } + + if( h->param.i_log_level >= X264_LOG_INFO ) + { + if( h->mb.i_cbp_luma | h->mb.i_cbp_chroma ) + { + if( CHROMA444 ) + { + for( int i = 0; i < 4; i++ ) + if( h->mb.i_cbp_luma & (1 << i) ) + for( int p = 0; p < 3; p++ ) + { + int s8 = i*4+p*16; + int nnz8x8 = M16( &h->mb.cache.non_zero_count[x264_scan8[s8]+0] ) + | M16( &h->mb.cache.non_zero_count[x264_scan8[s8]+8] ); + h->stat.frame.i_mb_cbp[!b_intra + p*2] += !!nnz8x8; + } + } + else + { + int cbpsum = (h->mb.i_cbp_luma&1) + ((h->mb.i_cbp_luma>>1)&1) + + ((h->mb.i_cbp_luma>>2)&1) + (h->mb.i_cbp_luma>>3); + h->stat.frame.i_mb_cbp[!b_intra + 0] += cbpsum; + h->stat.frame.i_mb_cbp[!b_intra + 2] += !!h->mb.i_cbp_chroma; + h->stat.frame.i_mb_cbp[!b_intra + 4] += h->mb.i_cbp_chroma >> 1; + } + } + if( h->mb.i_cbp_luma && !b_intra ) + { + h->stat.frame.i_mb_count_8x8dct[0] ++; + h->stat.frame.i_mb_count_8x8dct[1] += h->mb.b_transform_8x8; + } + if( b_intra && h->mb.i_type != I_PCM ) + { + if( h->mb.i_type == I_16x16 ) + h->stat.frame.i_mb_pred_mode[0][h->mb.i_intra16x16_pred_mode]++; + else if( h->mb.i_type == I_8x8 ) + for( int i = 0; i < 16; i += 4 ) + h->stat.frame.i_mb_pred_mode[1][h->mb.cache.intra4x4_pred_mode[x264_scan8[i]]]++; + else //if( h->mb.i_type == I_4x4 ) + for( int i = 0; i < 16; i++ ) + h->stat.frame.i_mb_pred_mode[2][h->mb.cache.intra4x4_pred_mode[x264_scan8[i]]]++; + h->stat.frame.i_mb_pred_mode[3][x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode]]++; + } + h->stat.frame.i_mb_field[b_intra?0:b_skip?2:1] += MB_INTERLACED; + } + + /* calculate deblock strength values (actual deblocking is done per-row along with hpel) */ + if( b_deblock ) + x264_macroblock_deblock_strength( h ); + + if( mb_xy == h->sh.i_last_mb ) + break; + + if( SLICE_MBAFF ) + { + i_mb_x += i_mb_y & 1; + i_mb_y ^= i_mb_x < h->mb.i_mb_width; + } + else + i_mb_x++; + if( i_mb_x == h->mb.i_mb_width ) + { + i_mb_y++; + i_mb_x = 0; + } + } + if( h->sh.i_last_mb < h->sh.i_first_mb ) + return 0; + + h->out.nal[h->out.i_nal].i_last_mb = h->sh.i_last_mb; + + if( h->param.b_cabac ) + { + x264_cabac_encode_flush( h, &h->cabac ); + h->out.bs.p = h->cabac.p; + } + else + { + if( i_skip > 0 ) + bs_write_ue( &h->out.bs, i_skip ); /* last skip run */ + /* rbsp_slice_trailing_bits */ + bs_rbsp_trailing( &h->out.bs ); + bs_flush( &h->out.bs ); + } + if( x264_nal_end( h ) ) + return -1; + + if( h->sh.i_last_mb == (h->i_threadslice_end * h->mb.i_mb_width - 1) ) + { + h->stat.frame.i_misc_bits = bs_pos( &h->out.bs ) + + (h->out.i_nal*NALU_OVERHEAD * 8) + - h->stat.frame.i_tex_bits + - h->stat.frame.i_mv_bits; + x264_fdec_filter_row( h, h->i_threadslice_end, 0 ); + + if( h->param.b_sliced_threads ) + { + /* Tell the main thread we're done. */ + x264_threadslice_cond_broadcast( h, 1 ); + /* Do hpel now */ + for( int mb_y = h->i_threadslice_start; mb_y <= h->i_threadslice_end; mb_y++ ) + x264_fdec_filter_row( h, mb_y, 1 ); + x264_threadslice_cond_broadcast( h, 2 ); + /* Do the first row of hpel, now that the previous slice is done */ + if( h->i_thread_idx > 0 ) + { + x264_threadslice_cond_wait( h->thread[h->i_thread_idx-1], 2 ); + x264_fdec_filter_row( h, h->i_threadslice_start + (1 << SLICE_MBAFF), 2 ); + } + } + + /* Free mb info after the last thread's done using it */ + if( h->fdec->mb_info_free && (!h->param.b_sliced_threads || h->i_thread_idx == (h->param.i_threads-1)) ) + { + h->fdec->mb_info_free( h->fdec->mb_info ); + h->fdec->mb_info = NULL; + h->fdec->mb_info_free = NULL; + } + } + + return 0; +} + +static void x264_thread_sync_context( x264_t *dst, x264_t *src ) +{ + if( dst == src ) + return; + + // reference counting + for( x264_frame_t **f = src->frames.reference; *f; f++ ) + (*f)->i_reference_count++; + for( x264_frame_t **f = dst->frames.reference; *f; f++ ) + x264_frame_push_unused( src, *f ); + src->fdec->i_reference_count++; + x264_frame_push_unused( src, dst->fdec ); + + // copy everything except the per-thread pointers and the constants. + memcpy( &dst->i_frame, &src->i_frame, offsetof(x264_t, mb.base) - offsetof(x264_t, i_frame) ); + dst->param = src->param; + dst->stat = src->stat; + dst->pixf = src->pixf; + dst->reconfig = src->reconfig; +} + +static void x264_thread_sync_stat( x264_t *dst, x264_t *src ) +{ + if( dst != src ) + memcpy( &dst->stat, &src->stat, offsetof(x264_t, stat.frame) - offsetof(x264_t, stat) ); +} + +static void *x264_slices_write( x264_t *h ) +{ + int i_slice_num = 0; + int last_thread_mb = h->sh.i_last_mb; + + /* init stats */ + memset( &h->stat.frame, 0, sizeof(h->stat.frame) ); + h->mb.b_reencode_mb = 0; + while( h->sh.i_first_mb + SLICE_MBAFF*h->mb.i_mb_stride <= last_thread_mb ) + { + h->sh.i_last_mb = last_thread_mb; + if( !i_slice_num || !x264_frame_new_slice( h, h->fdec ) ) + { + if( h->param.i_slice_max_mbs ) + { + if( SLICE_MBAFF ) + { + // convert first to mbaff form, add slice-max-mbs, then convert back to normal form + int last_mbaff = 2*(h->sh.i_first_mb % h->mb.i_mb_width) + + h->mb.i_mb_width*(h->sh.i_first_mb / h->mb.i_mb_width) + + h->param.i_slice_max_mbs - 1; + int last_x = (last_mbaff % (2*h->mb.i_mb_width))/2; + int last_y = (last_mbaff / (2*h->mb.i_mb_width))*2 + 1; + h->sh.i_last_mb = last_x + h->mb.i_mb_stride*last_y; + } + else + { + h->sh.i_last_mb = h->sh.i_first_mb + h->param.i_slice_max_mbs - 1; + if( h->sh.i_last_mb < last_thread_mb && last_thread_mb - h->sh.i_last_mb < h->param.i_slice_min_mbs ) + h->sh.i_last_mb = last_thread_mb - h->param.i_slice_min_mbs; + } + i_slice_num++; + } + else if( h->param.i_slice_count && !h->param.b_sliced_threads ) + { + int height = h->mb.i_mb_height >> PARAM_INTERLACED; + int width = h->mb.i_mb_width << PARAM_INTERLACED; + i_slice_num++; + h->sh.i_last_mb = (height * i_slice_num + h->param.i_slice_count/2) / h->param.i_slice_count * width - 1; + } + } + h->sh.i_last_mb = X264_MIN( h->sh.i_last_mb, last_thread_mb ); + if( x264_stack_align( x264_slice_write, h ) ) + goto fail; + h->sh.i_first_mb = h->sh.i_last_mb + 1; + // if i_first_mb is not the last mb in a row then go to the next mb in MBAFF order + if( SLICE_MBAFF && h->sh.i_first_mb % h->mb.i_mb_width ) + h->sh.i_first_mb -= h->mb.i_mb_stride; + } + + return (void *)0; + +fail: + /* Tell other threads we're done, so they wouldn't wait for it */ + if( h->param.b_sliced_threads ) + x264_threadslice_cond_broadcast( h, 2 ); + return (void *)-1; +} + +static int x264_threaded_slices_write( x264_t *h ) +{ + /* set first/last mb and sync contexts */ + for( int i = 0; i < h->param.i_threads; i++ ) + { + x264_t *t = h->thread[i]; + if( i ) + { + t->param = h->param; + memcpy( &t->i_frame, &h->i_frame, offsetof(x264_t, rc) - offsetof(x264_t, i_frame) ); + } + int height = h->mb.i_mb_height >> PARAM_INTERLACED; + t->i_threadslice_start = ((height * i + h->param.i_slice_count/2) / h->param.i_threads) << PARAM_INTERLACED; + t->i_threadslice_end = ((height * (i+1) + h->param.i_slice_count/2) / h->param.i_threads) << PARAM_INTERLACED; + t->sh.i_first_mb = t->i_threadslice_start * h->mb.i_mb_width; + t->sh.i_last_mb = t->i_threadslice_end * h->mb.i_mb_width - 1; + } + + x264_stack_align( x264_analyse_weight_frame, h, h->mb.i_mb_height*16 + 16 ); + + x264_threads_distribute_ratecontrol( h ); + + /* setup */ + for( int i = 0; i < h->param.i_threads; i++ ) + { + h->thread[i]->i_thread_idx = i; + h->thread[i]->b_thread_active = 1; + x264_threadslice_cond_broadcast( h->thread[i], 0 ); + } + /* dispatch */ + for( int i = 0; i < h->param.i_threads; i++ ) + x264_threadpool_run( h->threadpool, (void*)x264_slices_write, h->thread[i] ); + /* wait */ + for( int i = 0; i < h->param.i_threads; i++ ) + x264_threadslice_cond_wait( h->thread[i], 1 ); + + x264_threads_merge_ratecontrol( h ); + + for( int i = 1; i < h->param.i_threads; i++ ) + { + x264_t *t = h->thread[i]; + for( int j = 0; j < t->out.i_nal; j++ ) + { + h->out.nal[h->out.i_nal] = t->out.nal[j]; + h->out.i_nal++; + x264_nal_check_buffer( h ); + } + /* All entries in stat.frame are ints except for ssd/ssim. */ + for( int j = 0; j < (offsetof(x264_t,stat.frame.i_ssd) - offsetof(x264_t,stat.frame.i_mv_bits)) / sizeof(int); j++ ) + ((int*)&h->stat.frame)[j] += ((int*)&t->stat.frame)[j]; + for( int j = 0; j < 3; j++ ) + h->stat.frame.i_ssd[j] += t->stat.frame.i_ssd[j]; + h->stat.frame.f_ssim += t->stat.frame.f_ssim; + h->stat.frame.i_ssim_cnt += t->stat.frame.i_ssim_cnt; + } + + return 0; +} + +void x264_encoder_intra_refresh( x264_t *h ) +{ + h = h->thread[h->i_thread_phase]; + h->b_queued_intra_refresh = 1; +} + +int x264_encoder_invalidate_reference( x264_t *h, int64_t pts ) +{ + if( h->param.i_bframe ) + { + x264_log( h, X264_LOG_ERROR, "x264_encoder_invalidate_reference is not supported with B-frames enabled\n" ); + return -1; + } + if( h->param.b_intra_refresh ) + { + x264_log( h, X264_LOG_ERROR, "x264_encoder_invalidate_reference is not supported with intra refresh enabled\n" ); + return -1; + } + h = h->thread[h->i_thread_phase]; + if( pts >= h->i_last_idr_pts ) + { + for( int i = 0; h->frames.reference[i]; i++ ) + if( pts <= h->frames.reference[i]->i_pts ) + h->frames.reference[i]->b_corrupt = 1; + if( pts <= h->fdec->i_pts ) + h->fdec->b_corrupt = 1; + } + return 0; +} + +/**************************************************************************** + * x264_encoder_encode: + * XXX: i_poc : is the poc of the current given picture + * i_frame : is the number of the frame being coded + * ex: type frame poc + * I 0 2*0 + * P 1 2*3 + * B 2 2*1 + * B 3 2*2 + * P 4 2*6 + * B 5 2*4 + * B 6 2*5 + ****************************************************************************/ +int x264_encoder_encode( x264_t *h, + x264_nal_t **pp_nal, int *pi_nal, + x264_picture_t *pic_in, + x264_picture_t *pic_out ) +{ + x264_t *thread_current, *thread_prev, *thread_oldest; + int i_nal_type, i_nal_ref_idc, i_global_qp; + int overhead = NALU_OVERHEAD; + +#if HAVE_OPENCL + if( h->opencl.b_fatal_error ) + return -1; +#endif + + if( h->i_thread_frames > 1 ) + { + thread_prev = h->thread[ h->i_thread_phase ]; + h->i_thread_phase = (h->i_thread_phase + 1) % h->i_thread_frames; + thread_current = h->thread[ h->i_thread_phase ]; + thread_oldest = h->thread[ (h->i_thread_phase + 1) % h->i_thread_frames ]; + x264_thread_sync_context( thread_current, thread_prev ); + x264_thread_sync_ratecontrol( thread_current, thread_prev, thread_oldest ); + h = thread_current; + } + else + { + thread_current = + thread_oldest = h; + } + h->i_cpb_delay_pir_offset = h->i_cpb_delay_pir_offset_next; + + /* no data out */ + *pi_nal = 0; + *pp_nal = NULL; + + /* ------------------- Setup new frame from picture -------------------- */ + if( pic_in != NULL ) + { + if( h->lookahead->b_exit_thread ) + { + x264_log( h, X264_LOG_ERROR, "lookahead thread is already stopped\n" ); + return -1; + } + + /* 1: Copy the picture to a frame and move it to a buffer */ + x264_frame_t *fenc = x264_frame_pop_unused( h, 0 ); + if( !fenc ) + return -1; + + if( x264_frame_copy_picture( h, fenc, pic_in ) < 0 ) + return -1; + + if( h->param.i_width != 16 * h->mb.i_mb_width || + h->param.i_height != 16 * h->mb.i_mb_height ) + x264_frame_expand_border_mod16( h, fenc ); + + fenc->i_frame = h->frames.i_input++; + + if( fenc->i_frame == 0 ) + h->frames.i_first_pts = fenc->i_pts; + if( h->frames.i_bframe_delay && fenc->i_frame == h->frames.i_bframe_delay ) + h->frames.i_bframe_delay_time = fenc->i_pts - h->frames.i_first_pts; + + if( h->param.b_vfr_input && fenc->i_pts <= h->frames.i_largest_pts ) + x264_log( h, X264_LOG_WARNING, "non-strictly-monotonic PTS\n" ); + + h->frames.i_second_largest_pts = h->frames.i_largest_pts; + h->frames.i_largest_pts = fenc->i_pts; + + if( (fenc->i_pic_struct < PIC_STRUCT_AUTO) || (fenc->i_pic_struct > PIC_STRUCT_TRIPLE) ) + fenc->i_pic_struct = PIC_STRUCT_AUTO; + + if( fenc->i_pic_struct == PIC_STRUCT_AUTO ) + { +#if HAVE_INTERLACED + int b_interlaced = fenc->param ? fenc->param->b_interlaced : h->param.b_interlaced; +#else + int b_interlaced = 0; +#endif + if( b_interlaced ) + { + int b_tff = fenc->param ? fenc->param->b_tff : h->param.b_tff; + fenc->i_pic_struct = b_tff ? PIC_STRUCT_TOP_BOTTOM : PIC_STRUCT_BOTTOM_TOP; + } + else + fenc->i_pic_struct = PIC_STRUCT_PROGRESSIVE; + } + + if( h->param.rc.b_mb_tree && h->param.rc.b_stat_read ) + { + if( x264_macroblock_tree_read( h, fenc, pic_in->prop.quant_offsets ) ) + return -1; + } + else + x264_stack_align( x264_adaptive_quant_frame, h, fenc, pic_in->prop.quant_offsets ); + + if( pic_in->prop.quant_offsets_free ) + pic_in->prop.quant_offsets_free( pic_in->prop.quant_offsets ); + + if( h->frames.b_have_lowres ) + x264_frame_init_lowres( h, fenc ); + + /* 2: Place the frame into the queue for its slice type decision */ + x264_lookahead_put_frame( h, fenc ); + + if( h->frames.i_input <= h->frames.i_delay + 1 - h->i_thread_frames ) + { + /* Nothing yet to encode, waiting for filling of buffers */ + pic_out->i_type = X264_TYPE_AUTO; + return 0; + } + } + else + { + /* signal kills for lookahead thread */ + x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex ); + h->lookahead->b_exit_thread = 1; + x264_pthread_cond_broadcast( &h->lookahead->ifbuf.cv_fill ); + x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex ); + } + + h->i_frame++; + /* 3: The picture is analyzed in the lookahead */ + if( !h->frames.current[0] ) + x264_lookahead_get_frames( h ); + + if( !h->frames.current[0] && x264_lookahead_is_empty( h ) ) + return x264_encoder_frame_end( thread_oldest, thread_current, pp_nal, pi_nal, pic_out ); + + /* ------------------- Get frame to be encoded ------------------------- */ + /* 4: get picture to encode */ + h->fenc = x264_frame_shift( h->frames.current ); + + /* If applicable, wait for previous frame reconstruction to finish */ + if( h->param.b_sliced_threads ) + if( x264_threadpool_wait_all( h ) < 0 ) + return -1; + + if( h->i_frame == 0 ) + h->i_reordered_pts_delay = h->fenc->i_reordered_pts; + if( h->reconfig ) + { + x264_encoder_reconfig_apply( h, &h->reconfig_h->param ); + h->reconfig = 0; + } + if( h->fenc->param ) + { + x264_encoder_reconfig_apply( h, h->fenc->param ); + if( h->fenc->param->param_free ) + { + h->fenc->param->param_free( h->fenc->param ); + h->fenc->param = NULL; + } + } + x264_ratecontrol_zone_init( h ); + + // ok to call this before encoding any frames, since the initial values of fdec have b_kept_as_ref=0 + if( x264_reference_update( h ) ) + return -1; + h->fdec->i_lines_completed = -1; + + if( !IS_X264_TYPE_I( h->fenc->i_type ) ) + { + int valid_refs_left = 0; + for( int i = 0; h->frames.reference[i]; i++ ) + if( !h->frames.reference[i]->b_corrupt ) + valid_refs_left++; + /* No valid reference frames left: force an IDR. */ + if( !valid_refs_left ) + { + h->fenc->b_keyframe = 1; + h->fenc->i_type = X264_TYPE_IDR; + } + } + + if( h->fenc->b_keyframe ) + { + h->frames.i_last_keyframe = h->fenc->i_frame; + if( h->fenc->i_type == X264_TYPE_IDR ) + { + h->i_frame_num = 0; + h->frames.i_last_idr = h->fenc->i_frame; + } + } + h->sh.i_mmco_command_count = + h->sh.i_mmco_remove_from_end = 0; + h->b_ref_reorder[0] = + h->b_ref_reorder[1] = 0; + h->fdec->i_poc = + h->fenc->i_poc = 2 * ( h->fenc->i_frame - X264_MAX( h->frames.i_last_idr, 0 ) ); + + /* ------------------- Setup frame context ----------------------------- */ + /* 5: Init data dependent of frame type */ + if( h->fenc->i_type == X264_TYPE_IDR ) + { + /* reset ref pictures */ + i_nal_type = NAL_SLICE_IDR; + i_nal_ref_idc = NAL_PRIORITY_HIGHEST; + h->sh.i_type = SLICE_TYPE_I; + x264_reference_reset( h ); + h->frames.i_poc_last_open_gop = -1; + } + else if( h->fenc->i_type == X264_TYPE_I ) + { + i_nal_type = NAL_SLICE; + i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/ + h->sh.i_type = SLICE_TYPE_I; + x264_reference_hierarchy_reset( h ); + if( h->param.b_open_gop ) + h->frames.i_poc_last_open_gop = h->fenc->b_keyframe ? h->fenc->i_poc : -1; + } + else if( h->fenc->i_type == X264_TYPE_P ) + { + i_nal_type = NAL_SLICE; + i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/ + h->sh.i_type = SLICE_TYPE_P; + x264_reference_hierarchy_reset( h ); + h->frames.i_poc_last_open_gop = -1; + } + else if( h->fenc->i_type == X264_TYPE_BREF ) + { + i_nal_type = NAL_SLICE; + i_nal_ref_idc = h->param.i_bframe_pyramid == X264_B_PYRAMID_STRICT ? NAL_PRIORITY_LOW : NAL_PRIORITY_HIGH; + h->sh.i_type = SLICE_TYPE_B; + x264_reference_hierarchy_reset( h ); + } + else /* B frame */ + { + i_nal_type = NAL_SLICE; + i_nal_ref_idc = NAL_PRIORITY_DISPOSABLE; + h->sh.i_type = SLICE_TYPE_B; + } + + h->fdec->i_type = h->fenc->i_type; + h->fdec->i_frame = h->fenc->i_frame; + h->fenc->b_kept_as_ref = + h->fdec->b_kept_as_ref = i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE && h->param.i_keyint_max > 1; + + h->fdec->mb_info = h->fenc->mb_info; + h->fdec->mb_info_free = h->fenc->mb_info_free; + h->fenc->mb_info = NULL; + h->fenc->mb_info_free = NULL; + + h->fdec->i_pts = h->fenc->i_pts; + if( h->frames.i_bframe_delay ) + { + int64_t *prev_reordered_pts = thread_current->frames.i_prev_reordered_pts; + h->fdec->i_dts = h->i_frame > h->frames.i_bframe_delay + ? prev_reordered_pts[ (h->i_frame - h->frames.i_bframe_delay) % h->frames.i_bframe_delay ] + : h->fenc->i_reordered_pts - h->frames.i_bframe_delay_time; + prev_reordered_pts[ h->i_frame % h->frames.i_bframe_delay ] = h->fenc->i_reordered_pts; + } + else + h->fdec->i_dts = h->fenc->i_reordered_pts; + if( h->fenc->i_type == X264_TYPE_IDR ) + h->i_last_idr_pts = h->fdec->i_pts; + + /* ------------------- Init ----------------------------- */ + /* build ref list 0/1 */ + x264_reference_build_list( h, h->fdec->i_poc ); + + /* ---------------------- Write the bitstream -------------------------- */ + /* Init bitstream context */ + if( h->param.b_sliced_threads ) + { + for( int i = 0; i < h->param.i_threads; i++ ) + { + bs_init( &h->thread[i]->out.bs, h->thread[i]->out.p_bitstream, h->thread[i]->out.i_bitstream ); + h->thread[i]->out.i_nal = 0; + } + } + else + { + bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream ); + h->out.i_nal = 0; + } + + if( h->param.b_aud ) + { + int pic_type; + + if( h->sh.i_type == SLICE_TYPE_I ) + pic_type = 0; + else if( h->sh.i_type == SLICE_TYPE_P ) + pic_type = 1; + else if( h->sh.i_type == SLICE_TYPE_B ) + pic_type = 2; + else + pic_type = 7; + + x264_nal_start( h, NAL_AUD, NAL_PRIORITY_DISPOSABLE ); + bs_write( &h->out.bs, 3, pic_type ); + bs_rbsp_trailing( &h->out.bs ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD; + } + + h->i_nal_type = i_nal_type; + h->i_nal_ref_idc = i_nal_ref_idc; + + if( h->param.b_intra_refresh ) + { + if( IS_X264_TYPE_I( h->fenc->i_type ) ) + { + h->fdec->i_frames_since_pir = 0; + h->b_queued_intra_refresh = 0; + /* PIR is currently only supported with ref == 1, so any intra frame effectively refreshes + * the whole frame and counts as an intra refresh. */ + h->fdec->f_pir_position = h->mb.i_mb_width; + } + else if( h->fenc->i_type == X264_TYPE_P ) + { + int pocdiff = (h->fdec->i_poc - h->fref[0][0]->i_poc)/2; + float increment = X264_MAX( ((float)h->mb.i_mb_width-1) / h->param.i_keyint_max, 1 ); + h->fdec->f_pir_position = h->fref[0][0]->f_pir_position; + h->fdec->i_frames_since_pir = h->fref[0][0]->i_frames_since_pir + pocdiff; + if( h->fdec->i_frames_since_pir >= h->param.i_keyint_max || + (h->b_queued_intra_refresh && h->fdec->f_pir_position + 0.5 >= h->mb.i_mb_width) ) + { + h->fdec->f_pir_position = 0; + h->fdec->i_frames_since_pir = 0; + h->b_queued_intra_refresh = 0; + h->fenc->b_keyframe = 1; + } + h->fdec->i_pir_start_col = h->fdec->f_pir_position+0.5; + h->fdec->f_pir_position += increment * pocdiff; + h->fdec->i_pir_end_col = h->fdec->f_pir_position+0.5; + /* If our intra refresh has reached the right side of the frame, we're done. */ + if( h->fdec->i_pir_end_col >= h->mb.i_mb_width - 1 ) + { + h->fdec->f_pir_position = h->mb.i_mb_width; + h->fdec->i_pir_end_col = h->mb.i_mb_width - 1; + } + } + } + + if( h->fenc->b_keyframe ) + { + /* Write SPS and PPS */ + if( h->param.b_repeat_headers ) + { + /* generate sequence parameters */ + x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST ); + x264_sps_write( &h->out.bs, h->sps ); + if( x264_nal_end( h ) ) + return -1; + /* Pad AUD/SPS to 256 bytes like Panasonic */ + if( h->param.i_avcintra_class ) + h->out.nal[h->out.i_nal-1].i_padding = 256 - bs_pos( &h->out.bs ) / 8 - 2*NALU_OVERHEAD; + overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + NALU_OVERHEAD; + + /* generate picture parameters */ + x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); + x264_pps_write( &h->out.bs, h->sps, h->pps ); + if( x264_nal_end( h ) ) + return -1; + if( h->param.i_avcintra_class ) + h->out.nal[h->out.i_nal-1].i_padding = 256 - h->out.nal[h->out.i_nal-1].i_payload - NALU_OVERHEAD; + overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + NALU_OVERHEAD; + } + + /* when frame threading is used, buffering period sei is written in x264_encoder_frame_end */ + if( h->i_thread_frames == 1 && h->sps->vui.b_nal_hrd_parameters_present ) + { + x264_hrd_fullness( h ); + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_buffering_period_write( h, &h->out.bs ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + } + } + + /* write extra sei */ + for( int i = 0; i < h->fenc->extra_sei.num_payloads; i++ ) + { + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_write( &h->out.bs, h->fenc->extra_sei.payloads[i].payload, h->fenc->extra_sei.payloads[i].payload_size, + h->fenc->extra_sei.payloads[i].payload_type ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + if( h->fenc->extra_sei.sei_free ) + { + h->fenc->extra_sei.sei_free( h->fenc->extra_sei.payloads[i].payload ); + h->fenc->extra_sei.payloads[i].payload = NULL; + } + } + + if( h->fenc->extra_sei.sei_free ) + { + h->fenc->extra_sei.sei_free( h->fenc->extra_sei.payloads ); + h->fenc->extra_sei.payloads = NULL; + h->fenc->extra_sei.sei_free = NULL; + } + + if( h->fenc->b_keyframe ) + { + /* Avid's decoder strictly wants two SEIs for AVC-Intra so we can't insert the x264 SEI */ + if( h->param.b_repeat_headers && h->fenc->i_frame == 0 && !h->param.i_avcintra_class ) + { + /* identify ourself */ + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + if( x264_sei_version_write( h, &h->out.bs ) ) + return -1; + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + } + + if( h->fenc->i_type != X264_TYPE_IDR ) + { + int time_to_recovery = h->param.b_open_gop ? 0 : X264_MIN( h->mb.i_mb_width - 1, h->param.i_keyint_max ) + h->param.i_bframe - 1; + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_recovery_point_write( h, &h->out.bs, time_to_recovery ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + } + } + + if( h->param.i_frame_packing >= 0 && (h->fenc->b_keyframe || h->param.i_frame_packing == 5) ) + { + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_frame_packing_write( h, &h->out.bs ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + } + + /* generate sei pic timing */ + if( h->sps->vui.b_pic_struct_present || h->sps->vui.b_nal_hrd_parameters_present ) + { + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_pic_timing_write( h, &h->out.bs ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + } + + /* As required by Blu-ray. */ + if( !IS_X264_TYPE_B( h->fenc->i_type ) && h->b_sh_backup ) + { + h->b_sh_backup = 0; + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_dec_ref_pic_marking_write( h, &h->out.bs ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + } + + if( h->fenc->b_keyframe && h->param.b_intra_refresh ) + h->i_cpb_delay_pir_offset_next = h->fenc->i_cpb_delay; + + /* Filler space: 10 or 18 SEIs' worth of space, depending on resolution */ + if( h->param.i_avcintra_class ) + { + /* Write an empty filler NAL to mimic the AUD in the P2 format*/ + x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE ); + x264_filler_write( h, &h->out.bs, 0 ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD; + + /* All lengths are magic lengths that decoders expect to see */ + /* "UMID" SEI */ + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + if( x264_sei_avcintra_umid_write( h, &h->out.bs ) < 0 ) + return -1; + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + + int unpadded_len; + int total_len; + if( h->param.i_height == 1080 ) + { + unpadded_len = 5780; + total_len = 17*512; + } + else + { + unpadded_len = 2900; + total_len = 9*512; + } + /* "VANC" SEI */ + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + if( x264_sei_avcintra_vanc_write( h, &h->out.bs, unpadded_len ) < 0 ) + return -1; + if( x264_nal_end( h ) ) + return -1; + + h->out.nal[h->out.i_nal-1].i_padding = total_len - h->out.nal[h->out.i_nal-1].i_payload - SEI_OVERHEAD; + overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + SEI_OVERHEAD; + } + + /* Init the rate control */ + /* FIXME: Include slice header bit cost. */ + x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 ); + i_global_qp = x264_ratecontrol_qp( h ); + + pic_out->i_qpplus1 = + h->fdec->i_qpplus1 = i_global_qp + 1; + + if( h->param.rc.b_stat_read && h->sh.i_type != SLICE_TYPE_I ) + { + x264_reference_build_list_optimal( h ); + x264_reference_check_reorder( h ); + } + + if( h->i_ref[0] ) + h->fdec->i_poc_l0ref0 = h->fref[0][0]->i_poc; + + /* ------------------------ Create slice header ----------------------- */ + x264_slice_init( h, i_nal_type, i_global_qp ); + + /*------------------------- Weights -------------------------------------*/ + if( h->sh.i_type == SLICE_TYPE_B ) + x264_macroblock_bipred_init( h ); + + x264_weighted_pred_init( h ); + + if( i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE ) + h->i_frame_num++; + + /* Write frame */ + h->i_threadslice_start = 0; + h->i_threadslice_end = h->mb.i_mb_height; + if( h->i_thread_frames > 1 ) + { + x264_threadpool_run( h->threadpool, (void*)x264_slices_write, h ); + h->b_thread_active = 1; + } + else if( h->param.b_sliced_threads ) + { + if( x264_threaded_slices_write( h ) ) + return -1; + } + else + if( (intptr_t)x264_slices_write( h ) ) + return -1; + + return x264_encoder_frame_end( thread_oldest, thread_current, pp_nal, pi_nal, pic_out ); +} + +static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, + x264_nal_t **pp_nal, int *pi_nal, + x264_picture_t *pic_out ) +{ + char psz_message[80]; + + if( !h->param.b_sliced_threads && h->b_thread_active ) + { + h->b_thread_active = 0; + if( (intptr_t)x264_threadpool_wait( h->threadpool, h ) ) + return -1; + } + if( !h->out.i_nal ) + { + pic_out->i_type = X264_TYPE_AUTO; + return 0; + } + + x264_emms(); + + /* generate buffering period sei and insert it into place */ + if( h->i_thread_frames > 1 && h->fenc->b_keyframe && h->sps->vui.b_nal_hrd_parameters_present ) + { + x264_hrd_fullness( h ); + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_buffering_period_write( h, &h->out.bs ); + if( x264_nal_end( h ) ) + return -1; + /* buffering period sei must follow AUD, SPS and PPS and precede all other SEIs */ + int idx = 0; + while( h->out.nal[idx].i_type == NAL_AUD || + h->out.nal[idx].i_type == NAL_SPS || + h->out.nal[idx].i_type == NAL_PPS ) + idx++; + x264_nal_t nal_tmp = h->out.nal[h->out.i_nal-1]; + memmove( &h->out.nal[idx+1], &h->out.nal[idx], (h->out.i_nal-idx-1)*sizeof(x264_nal_t) ); + h->out.nal[idx] = nal_tmp; + } + + int frame_size = x264_encoder_encapsulate_nals( h, 0 ); + if( frame_size < 0 ) + return -1; + + /* Set output picture properties */ + pic_out->i_type = h->fenc->i_type; + + pic_out->b_keyframe = h->fenc->b_keyframe; + pic_out->i_pic_struct = h->fenc->i_pic_struct; + + pic_out->i_pts = h->fdec->i_pts; + pic_out->i_dts = h->fdec->i_dts; + + if( pic_out->i_pts < pic_out->i_dts ) + x264_log( h, X264_LOG_WARNING, "invalid DTS: PTS is less than DTS\n" ); + + pic_out->opaque = h->fenc->opaque; + + pic_out->img.i_csp = h->fdec->i_csp; +#if HIGH_BIT_DEPTH + pic_out->img.i_csp |= X264_CSP_HIGH_DEPTH; +#endif + pic_out->img.i_plane = h->fdec->i_plane; + for( int i = 0; i < pic_out->img.i_plane; i++ ) + { + pic_out->img.i_stride[i] = h->fdec->i_stride[i] * sizeof(pixel); + pic_out->img.plane[i] = (uint8_t*)h->fdec->plane[i]; + } + + x264_frame_push_unused( thread_current, h->fenc ); + + /* ---------------------- Update encoder state ------------------------- */ + + /* update rc */ + int filler = 0; + if( x264_ratecontrol_end( h, frame_size * 8, &filler ) < 0 ) + return -1; + + pic_out->hrd_timing = h->fenc->hrd_timing; + pic_out->prop.f_crf_avg = h->fdec->f_crf_avg; + + /* Filler in AVC-Intra mode is written as zero bytes to the last slice + * We don't know the size of the last slice until encapsulation so we add filler to the encapsulated NAL */ + if( h->param.i_avcintra_class ) + { + if( x264_check_encapsulated_buffer( h, h->thread[0], h->out.i_nal, frame_size, frame_size + filler ) < 0 ) + return -1; + + x264_nal_t *nal = &h->out.nal[h->out.i_nal-1]; + memset( nal->p_payload + nal->i_payload, 0, filler ); + nal->i_payload += filler; + nal->i_padding = filler; + frame_size += filler; + + /* Fix up the size header for mp4/etc */ + if( !h->param.b_annexb ) + { + /* Size doesn't include the size of the header we're writing now. */ + uint8_t *nal_data = nal->p_payload; + int chunk_size = nal->i_payload - 4; + nal_data[0] = chunk_size >> 24; + nal_data[1] = chunk_size >> 16; + nal_data[2] = chunk_size >> 8; + nal_data[3] = chunk_size >> 0; + } + } + else + { + while( filler > 0 ) + { + int f, overhead = FILLER_OVERHEAD - h->param.b_annexb; + if( h->param.i_slice_max_size && filler > h->param.i_slice_max_size ) + { + int next_size = filler - h->param.i_slice_max_size; + int overflow = X264_MAX( overhead - next_size, 0 ); + f = h->param.i_slice_max_size - overhead - overflow; + } + else + f = X264_MAX( 0, filler - overhead ); + + if( x264_bitstream_check_buffer_filler( h, f ) ) + return -1; + x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE ); + x264_filler_write( h, &h->out.bs, f ); + if( x264_nal_end( h ) ) + return -1; + int total_size = x264_encoder_encapsulate_nals( h, h->out.i_nal-1 ); + if( total_size < 0 ) + return -1; + frame_size += total_size; + filler -= total_size; + } + } + + /* End bitstream, set output */ + *pi_nal = h->out.i_nal; + *pp_nal = h->out.nal; + + h->out.i_nal = 0; + + x264_noise_reduction_update( h ); + + /* ---------------------- Compute/Print statistics --------------------- */ + x264_thread_sync_stat( h, h->thread[0] ); + + /* Slice stat */ + h->stat.i_frame_count[h->sh.i_type]++; + h->stat.i_frame_size[h->sh.i_type] += frame_size; + h->stat.f_frame_qp[h->sh.i_type] += h->fdec->f_qp_avg_aq; + + for( int i = 0; i < X264_MBTYPE_MAX; i++ ) + h->stat.i_mb_count[h->sh.i_type][i] += h->stat.frame.i_mb_count[i]; + for( int i = 0; i < X264_PARTTYPE_MAX; i++ ) + h->stat.i_mb_partition[h->sh.i_type][i] += h->stat.frame.i_mb_partition[i]; + for( int i = 0; i < 2; i++ ) + h->stat.i_mb_count_8x8dct[i] += h->stat.frame.i_mb_count_8x8dct[i]; + for( int i = 0; i < 6; i++ ) + h->stat.i_mb_cbp[i] += h->stat.frame.i_mb_cbp[i]; + for( int i = 0; i < 4; i++ ) + for( int j = 0; j < 13; j++ ) + h->stat.i_mb_pred_mode[i][j] += h->stat.frame.i_mb_pred_mode[i][j]; + if( h->sh.i_type != SLICE_TYPE_I ) + for( int i_list = 0; i_list < 2; i_list++ ) + for( int i = 0; i < X264_REF_MAX*2; i++ ) + h->stat.i_mb_count_ref[h->sh.i_type][i_list][i] += h->stat.frame.i_mb_count_ref[i_list][i]; + for( int i = 0; i < 3; i++ ) + h->stat.i_mb_field[i] += h->stat.frame.i_mb_field[i]; + if( h->sh.i_type == SLICE_TYPE_P && h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE ) + { + h->stat.i_wpred[0] += !!h->sh.weight[0][0].weightfn; + h->stat.i_wpred[1] += !!h->sh.weight[0][1].weightfn || !!h->sh.weight[0][2].weightfn; + } + if( h->sh.i_type == SLICE_TYPE_B ) + { + h->stat.i_direct_frames[ h->sh.b_direct_spatial_mv_pred ] ++; + if( h->mb.b_direct_auto_write ) + { + //FIXME somewhat arbitrary time constants + if( h->stat.i_direct_score[0] + h->stat.i_direct_score[1] > h->mb.i_mb_count ) + for( int i = 0; i < 2; i++ ) + h->stat.i_direct_score[i] = h->stat.i_direct_score[i] * 9/10; + for( int i = 0; i < 2; i++ ) + h->stat.i_direct_score[i] += h->stat.frame.i_direct_score[i]; + } + } + else + h->stat.i_consecutive_bframes[h->fenc->i_bframes]++; + + psz_message[0] = '\0'; + double dur = h->fenc->f_duration; + h->stat.f_frame_duration[h->sh.i_type] += dur; + if( h->param.analyse.b_psnr ) + { + int64_t ssd[3] = + { + h->stat.frame.i_ssd[0], + h->stat.frame.i_ssd[1], + h->stat.frame.i_ssd[2], + }; + int luma_size = h->param.i_width * h->param.i_height; + int chroma_size = CHROMA_SIZE( luma_size ); + pic_out->prop.f_psnr[0] = x264_psnr( ssd[0], luma_size ); + pic_out->prop.f_psnr[1] = x264_psnr( ssd[1], chroma_size ); + pic_out->prop.f_psnr[2] = x264_psnr( ssd[2], chroma_size ); + pic_out->prop.f_psnr_avg = x264_psnr( ssd[0] + ssd[1] + ssd[2], luma_size + chroma_size*2 ); + + h->stat.f_ssd_global[h->sh.i_type] += dur * (ssd[0] + ssd[1] + ssd[2]); + h->stat.f_psnr_average[h->sh.i_type] += dur * pic_out->prop.f_psnr_avg; + h->stat.f_psnr_mean_y[h->sh.i_type] += dur * pic_out->prop.f_psnr[0]; + h->stat.f_psnr_mean_u[h->sh.i_type] += dur * pic_out->prop.f_psnr[1]; + h->stat.f_psnr_mean_v[h->sh.i_type] += dur * pic_out->prop.f_psnr[2]; + + snprintf( psz_message, 80, " PSNR Y:%5.2f U:%5.2f V:%5.2f", pic_out->prop.f_psnr[0], + pic_out->prop.f_psnr[1], + pic_out->prop.f_psnr[2] ); + } + + if( h->param.analyse.b_ssim ) + { + pic_out->prop.f_ssim = h->stat.frame.f_ssim / h->stat.frame.i_ssim_cnt; + h->stat.f_ssim_mean_y[h->sh.i_type] += pic_out->prop.f_ssim * dur; + int msg_len = strlen(psz_message); + snprintf( psz_message + msg_len, 80 - msg_len, " SSIM Y:%.5f", pic_out->prop.f_ssim ); + } + psz_message[79] = '\0'; + + x264_log( h, X264_LOG_DEBUG, + "frame=%4d QP=%.2f NAL=%d Slice:%c Poc:%-3d I:%-4d P:%-4d SKIP:%-4d size=%d bytes%s\n", + h->i_frame, + h->fdec->f_qp_avg_aq, + h->i_nal_ref_idc, + h->sh.i_type == SLICE_TYPE_I ? 'I' : (h->sh.i_type == SLICE_TYPE_P ? 'P' : 'B' ), + h->fdec->i_poc, + h->stat.frame.i_mb_count_i, + h->stat.frame.i_mb_count_p, + h->stat.frame.i_mb_count_skip, + frame_size, + psz_message ); + + // keep stats all in one place + x264_thread_sync_stat( h->thread[0], h ); + // for the use of the next frame + x264_thread_sync_stat( thread_current, h ); + +#ifdef DEBUG_MB_TYPE +{ + static const char mb_chars[] = { 'i', 'i', 'I', 'C', 'P', '8', 'S', + 'D', '<', 'X', 'B', 'X', '>', 'B', 'B', 'B', 'B', '8', 'S' }; + for( int mb_xy = 0; mb_xy < h->mb.i_mb_width * h->mb.i_mb_height; mb_xy++ ) + { + if( h->mb.type[mb_xy] < X264_MBTYPE_MAX && h->mb.type[mb_xy] >= 0 ) + fprintf( stderr, "%c ", mb_chars[ h->mb.type[mb_xy] ] ); + else + fprintf( stderr, "? " ); + + if( (mb_xy+1) % h->mb.i_mb_width == 0 ) + fprintf( stderr, "\n" ); + } +} +#endif + + /* Remove duplicates, must be done near the end as breaks h->fref0 array + * by freeing some of its pointers. */ + for( int i = 0; i < h->i_ref[0]; i++ ) + if( h->fref[0][i] && h->fref[0][i]->b_duplicate ) + { + x264_frame_push_blank_unused( h, h->fref[0][i] ); + h->fref[0][i] = 0; + } + + if( h->param.psz_dump_yuv ) + x264_frame_dump( h ); + x264_emms(); + + return frame_size; +} + +static void x264_print_intra( int64_t *i_mb_count, double i_count, int b_print_pcm, char *intra ) +{ + intra += sprintf( intra, "I16..4%s: %4.1f%% %4.1f%% %4.1f%%", + b_print_pcm ? "..PCM" : "", + i_mb_count[I_16x16]/ i_count, + i_mb_count[I_8x8] / i_count, + i_mb_count[I_4x4] / i_count ); + if( b_print_pcm ) + sprintf( intra, " %4.1f%%", i_mb_count[I_PCM] / i_count ); +} + +/**************************************************************************** + * x264_encoder_close: + ****************************************************************************/ +void x264_encoder_close ( x264_t *h ) +{ + int64_t i_yuv_size = FRAME_SIZE( h->param.i_width * h->param.i_height ); + int64_t i_mb_count_size[2][7] = {{0}}; + char buf[200]; + int b_print_pcm = h->stat.i_mb_count[SLICE_TYPE_I][I_PCM] + || h->stat.i_mb_count[SLICE_TYPE_P][I_PCM] + || h->stat.i_mb_count[SLICE_TYPE_B][I_PCM]; + + x264_lookahead_delete( h ); + +#if HAVE_OPENCL + x264_opencl_lookahead_delete( h ); + x264_opencl_function_t *ocl = h->opencl.ocl; +#endif + + if( h->param.b_sliced_threads ) + x264_threadpool_wait_all( h ); + if( h->param.i_threads > 1 ) + x264_threadpool_delete( h->threadpool ); + if( h->param.i_lookahead_threads > 1 ) + x264_threadpool_delete( h->lookaheadpool ); + if( h->i_thread_frames > 1 ) + { + for( int i = 0; i < h->i_thread_frames; i++ ) + if( h->thread[i]->b_thread_active ) + { + assert( h->thread[i]->fenc->i_reference_count == 1 ); + x264_frame_delete( h->thread[i]->fenc ); + } + + x264_t *thread_prev = h->thread[h->i_thread_phase]; + x264_thread_sync_ratecontrol( h, thread_prev, h ); + x264_thread_sync_ratecontrol( thread_prev, thread_prev, h ); + h->i_frame = thread_prev->i_frame + 1 - h->i_thread_frames; + } + h->i_frame++; + + /* Slices used and PSNR */ + for( int i = 0; i < 3; i++ ) + { + static const uint8_t slice_order[] = { SLICE_TYPE_I, SLICE_TYPE_P, SLICE_TYPE_B }; + int i_slice = slice_order[i]; + + if( h->stat.i_frame_count[i_slice] > 0 ) + { + int i_count = h->stat.i_frame_count[i_slice]; + double dur = h->stat.f_frame_duration[i_slice]; + if( h->param.analyse.b_psnr ) + { + x264_log( h, X264_LOG_INFO, + "frame %c:%-5d Avg QP:%5.2f size:%6.0f PSNR Mean Y:%5.2f U:%5.2f V:%5.2f Avg:%5.2f Global:%5.2f\n", + slice_type_to_char[i_slice], + i_count, + h->stat.f_frame_qp[i_slice] / i_count, + (double)h->stat.i_frame_size[i_slice] / i_count, + h->stat.f_psnr_mean_y[i_slice] / dur, h->stat.f_psnr_mean_u[i_slice] / dur, h->stat.f_psnr_mean_v[i_slice] / dur, + h->stat.f_psnr_average[i_slice] / dur, + x264_psnr( h->stat.f_ssd_global[i_slice], dur * i_yuv_size ) ); + } + else + { + x264_log( h, X264_LOG_INFO, + "frame %c:%-5d Avg QP:%5.2f size:%6.0f\n", + slice_type_to_char[i_slice], + i_count, + h->stat.f_frame_qp[i_slice] / i_count, + (double)h->stat.i_frame_size[i_slice] / i_count ); + } + } + } + if( h->param.i_bframe && h->stat.i_frame_count[SLICE_TYPE_B] ) + { + char *p = buf; + int den = 0; + // weight by number of frames (including the I/P-frames) that are in a sequence of N B-frames + for( int i = 0; i <= h->param.i_bframe; i++ ) + den += (i+1) * h->stat.i_consecutive_bframes[i]; + for( int i = 0; i <= h->param.i_bframe; i++ ) + p += sprintf( p, " %4.1f%%", 100. * (i+1) * h->stat.i_consecutive_bframes[i] / den ); + x264_log( h, X264_LOG_INFO, "consecutive B-frames:%s\n", buf ); + } + + for( int i_type = 0; i_type < 2; i_type++ ) + for( int i = 0; i < X264_PARTTYPE_MAX; i++ ) + { + if( i == D_DIRECT_8x8 ) continue; /* direct is counted as its own type */ + i_mb_count_size[i_type][x264_mb_partition_pixel_table[i]] += h->stat.i_mb_partition[i_type][i]; + } + + /* MB types used */ + if( h->stat.i_frame_count[SLICE_TYPE_I] > 0 ) + { + int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_I]; + double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_I] * h->mb.i_mb_count / 100.0; + x264_print_intra( i_mb_count, i_count, b_print_pcm, buf ); + x264_log( h, X264_LOG_INFO, "mb I %s\n", buf ); + } + if( h->stat.i_frame_count[SLICE_TYPE_P] > 0 ) + { + int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_P]; + double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_P] * h->mb.i_mb_count / 100.0; + int64_t *i_mb_size = i_mb_count_size[SLICE_TYPE_P]; + x264_print_intra( i_mb_count, i_count, b_print_pcm, buf ); + x264_log( h, X264_LOG_INFO, + "mb P %s P16..4: %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% skip:%4.1f%%\n", + buf, + i_mb_size[PIXEL_16x16] / (i_count*4), + (i_mb_size[PIXEL_16x8] + i_mb_size[PIXEL_8x16]) / (i_count*4), + i_mb_size[PIXEL_8x8] / (i_count*4), + (i_mb_size[PIXEL_8x4] + i_mb_size[PIXEL_4x8]) / (i_count*4), + i_mb_size[PIXEL_4x4] / (i_count*4), + i_mb_count[P_SKIP] / i_count ); + } + if( h->stat.i_frame_count[SLICE_TYPE_B] > 0 ) + { + int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_B]; + double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_B] * h->mb.i_mb_count / 100.0; + double i_mb_list_count; + int64_t *i_mb_size = i_mb_count_size[SLICE_TYPE_B]; + int64_t list_count[3] = {0}; /* 0 == L0, 1 == L1, 2 == BI */ + x264_print_intra( i_mb_count, i_count, b_print_pcm, buf ); + for( int i = 0; i < X264_PARTTYPE_MAX; i++ ) + for( int j = 0; j < 2; j++ ) + { + int l0 = x264_mb_type_list_table[i][0][j]; + int l1 = x264_mb_type_list_table[i][1][j]; + if( l0 || l1 ) + list_count[l1+l0*l1] += h->stat.i_mb_count[SLICE_TYPE_B][i] * 2; + } + list_count[0] += h->stat.i_mb_partition[SLICE_TYPE_B][D_L0_8x8]; + list_count[1] += h->stat.i_mb_partition[SLICE_TYPE_B][D_L1_8x8]; + list_count[2] += h->stat.i_mb_partition[SLICE_TYPE_B][D_BI_8x8]; + i_mb_count[B_DIRECT] += (h->stat.i_mb_partition[SLICE_TYPE_B][D_DIRECT_8x8]+2)/4; + i_mb_list_count = (list_count[0] + list_count[1] + list_count[2]) / 100.0; + sprintf( buf + strlen(buf), " B16..8: %4.1f%% %4.1f%% %4.1f%% direct:%4.1f%% skip:%4.1f%%", + i_mb_size[PIXEL_16x16] / (i_count*4), + (i_mb_size[PIXEL_16x8] + i_mb_size[PIXEL_8x16]) / (i_count*4), + i_mb_size[PIXEL_8x8] / (i_count*4), + i_mb_count[B_DIRECT] / i_count, + i_mb_count[B_SKIP] / i_count ); + if( i_mb_list_count != 0 ) + sprintf( buf + strlen(buf), " L0:%4.1f%% L1:%4.1f%% BI:%4.1f%%", + list_count[0] / i_mb_list_count, + list_count[1] / i_mb_list_count, + list_count[2] / i_mb_list_count ); + x264_log( h, X264_LOG_INFO, "mb B %s\n", buf ); + } + + x264_ratecontrol_summary( h ); + + if( h->stat.i_frame_count[SLICE_TYPE_I] + h->stat.i_frame_count[SLICE_TYPE_P] + h->stat.i_frame_count[SLICE_TYPE_B] > 0 ) + { +#define SUM3(p) (p[SLICE_TYPE_I] + p[SLICE_TYPE_P] + p[SLICE_TYPE_B]) +#define SUM3b(p,o) (p[SLICE_TYPE_I][o] + p[SLICE_TYPE_P][o] + p[SLICE_TYPE_B][o]) + int64_t i_i8x8 = SUM3b( h->stat.i_mb_count, I_8x8 ); + int64_t i_intra = i_i8x8 + SUM3b( h->stat.i_mb_count, I_4x4 ) + + SUM3b( h->stat.i_mb_count, I_16x16 ); + int64_t i_all_intra = i_intra + SUM3b( h->stat.i_mb_count, I_PCM); + int64_t i_skip = SUM3b( h->stat.i_mb_count, P_SKIP ) + + SUM3b( h->stat.i_mb_count, B_SKIP ); + const int i_count = h->stat.i_frame_count[SLICE_TYPE_I] + + h->stat.i_frame_count[SLICE_TYPE_P] + + h->stat.i_frame_count[SLICE_TYPE_B]; + int64_t i_mb_count = (int64_t)i_count * h->mb.i_mb_count; + int64_t i_inter = i_mb_count - i_skip - i_intra; + const double duration = h->stat.f_frame_duration[SLICE_TYPE_I] + + h->stat.f_frame_duration[SLICE_TYPE_P] + + h->stat.f_frame_duration[SLICE_TYPE_B]; + float f_bitrate = SUM3(h->stat.i_frame_size) / duration / 125; + + if( PARAM_INTERLACED ) + { + char *fieldstats = buf; + fieldstats[0] = 0; + if( i_inter ) + fieldstats += sprintf( fieldstats, " inter:%.1f%%", h->stat.i_mb_field[1] * 100.0 / i_inter ); + if( i_skip ) + fieldstats += sprintf( fieldstats, " skip:%.1f%%", h->stat.i_mb_field[2] * 100.0 / i_skip ); + x264_log( h, X264_LOG_INFO, "field mbs: intra: %.1f%%%s\n", + h->stat.i_mb_field[0] * 100.0 / i_intra, buf ); + } + + if( h->pps->b_transform_8x8_mode ) + { + buf[0] = 0; + if( h->stat.i_mb_count_8x8dct[0] ) + sprintf( buf, " inter:%.1f%%", 100. * h->stat.i_mb_count_8x8dct[1] / h->stat.i_mb_count_8x8dct[0] ); + x264_log( h, X264_LOG_INFO, "8x8 transform intra:%.1f%%%s\n", 100. * i_i8x8 / i_intra, buf ); + } + + if( (h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO || + (h->stat.i_direct_frames[0] && h->stat.i_direct_frames[1])) + && h->stat.i_frame_count[SLICE_TYPE_B] ) + { + x264_log( h, X264_LOG_INFO, "direct mvs spatial:%.1f%% temporal:%.1f%%\n", + h->stat.i_direct_frames[1] * 100. / h->stat.i_frame_count[SLICE_TYPE_B], + h->stat.i_direct_frames[0] * 100. / h->stat.i_frame_count[SLICE_TYPE_B] ); + } + + buf[0] = 0; + int csize = CHROMA444 ? 4 : 1; + if( i_mb_count != i_all_intra ) + sprintf( buf, " inter: %.1f%% %.1f%% %.1f%%", + h->stat.i_mb_cbp[1] * 100.0 / ((i_mb_count - i_all_intra)*4), + h->stat.i_mb_cbp[3] * 100.0 / ((i_mb_count - i_all_intra)*csize), + h->stat.i_mb_cbp[5] * 100.0 / ((i_mb_count - i_all_intra)*csize) ); + x264_log( h, X264_LOG_INFO, "coded y,%s,%s intra: %.1f%% %.1f%% %.1f%%%s\n", + CHROMA444?"u":"uvDC", CHROMA444?"v":"uvAC", + h->stat.i_mb_cbp[0] * 100.0 / (i_all_intra*4), + h->stat.i_mb_cbp[2] * 100.0 / (i_all_intra*csize), + h->stat.i_mb_cbp[4] * 100.0 / (i_all_intra*csize), buf ); + + int64_t fixed_pred_modes[4][9] = {{0}}; + int64_t sum_pred_modes[4] = {0}; + for( int i = 0; i <= I_PRED_16x16_DC_128; i++ ) + { + fixed_pred_modes[0][x264_mb_pred_mode16x16_fix[i]] += h->stat.i_mb_pred_mode[0][i]; + sum_pred_modes[0] += h->stat.i_mb_pred_mode[0][i]; + } + if( sum_pred_modes[0] ) + x264_log( h, X264_LOG_INFO, "i16 v,h,dc,p: %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", + fixed_pred_modes[0][0] * 100.0 / sum_pred_modes[0], + fixed_pred_modes[0][1] * 100.0 / sum_pred_modes[0], + fixed_pred_modes[0][2] * 100.0 / sum_pred_modes[0], + fixed_pred_modes[0][3] * 100.0 / sum_pred_modes[0] ); + for( int i = 1; i <= 2; i++ ) + { + for( int j = 0; j <= I_PRED_8x8_DC_128; j++ ) + { + fixed_pred_modes[i][x264_mb_pred_mode4x4_fix(j)] += h->stat.i_mb_pred_mode[i][j]; + sum_pred_modes[i] += h->stat.i_mb_pred_mode[i][j]; + } + if( sum_pred_modes[i] ) + x264_log( h, X264_LOG_INFO, "i%d v,h,dc,ddl,ddr,vr,hd,vl,hu: %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", (3-i)*4, + fixed_pred_modes[i][0] * 100.0 / sum_pred_modes[i], + fixed_pred_modes[i][1] * 100.0 / sum_pred_modes[i], + fixed_pred_modes[i][2] * 100.0 / sum_pred_modes[i], + fixed_pred_modes[i][3] * 100.0 / sum_pred_modes[i], + fixed_pred_modes[i][4] * 100.0 / sum_pred_modes[i], + fixed_pred_modes[i][5] * 100.0 / sum_pred_modes[i], + fixed_pred_modes[i][6] * 100.0 / sum_pred_modes[i], + fixed_pred_modes[i][7] * 100.0 / sum_pred_modes[i], + fixed_pred_modes[i][8] * 100.0 / sum_pred_modes[i] ); + } + for( int i = 0; i <= I_PRED_CHROMA_DC_128; i++ ) + { + fixed_pred_modes[3][x264_mb_chroma_pred_mode_fix[i]] += h->stat.i_mb_pred_mode[3][i]; + sum_pred_modes[3] += h->stat.i_mb_pred_mode[3][i]; + } + if( sum_pred_modes[3] && !CHROMA444 ) + x264_log( h, X264_LOG_INFO, "i8c dc,h,v,p: %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", + fixed_pred_modes[3][0] * 100.0 / sum_pred_modes[3], + fixed_pred_modes[3][1] * 100.0 / sum_pred_modes[3], + fixed_pred_modes[3][2] * 100.0 / sum_pred_modes[3], + fixed_pred_modes[3][3] * 100.0 / sum_pred_modes[3] ); + + if( h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE && h->stat.i_frame_count[SLICE_TYPE_P] > 0 ) + x264_log( h, X264_LOG_INFO, "Weighted P-Frames: Y:%.1f%% UV:%.1f%%\n", + h->stat.i_wpred[0] * 100.0 / h->stat.i_frame_count[SLICE_TYPE_P], + h->stat.i_wpred[1] * 100.0 / h->stat.i_frame_count[SLICE_TYPE_P] ); + + for( int i_list = 0; i_list < 2; i_list++ ) + for( int i_slice = 0; i_slice < 2; i_slice++ ) + { + char *p = buf; + int64_t i_den = 0; + int i_max = 0; + for( int i = 0; i < X264_REF_MAX*2; i++ ) + if( h->stat.i_mb_count_ref[i_slice][i_list][i] ) + { + i_den += h->stat.i_mb_count_ref[i_slice][i_list][i]; + i_max = i; + } + if( i_max == 0 ) + continue; + for( int i = 0; i <= i_max; i++ ) + p += sprintf( p, " %4.1f%%", 100. * h->stat.i_mb_count_ref[i_slice][i_list][i] / i_den ); + x264_log( h, X264_LOG_INFO, "ref %c L%d:%s\n", "PB"[i_slice], i_list, buf ); + } + + if( h->param.analyse.b_ssim ) + { + float ssim = SUM3( h->stat.f_ssim_mean_y ) / duration; + x264_log( h, X264_LOG_INFO, "SSIM Mean Y:%.7f (%6.3fdb)\n", ssim, x264_ssim( ssim ) ); + } + if( h->param.analyse.b_psnr ) + { + x264_log( h, X264_LOG_INFO, + "PSNR Mean Y:%6.3f U:%6.3f V:%6.3f Avg:%6.3f Global:%6.3f kb/s:%.2f\n", + SUM3( h->stat.f_psnr_mean_y ) / duration, + SUM3( h->stat.f_psnr_mean_u ) / duration, + SUM3( h->stat.f_psnr_mean_v ) / duration, + SUM3( h->stat.f_psnr_average ) / duration, + x264_psnr( SUM3( h->stat.f_ssd_global ), duration * i_yuv_size ), + f_bitrate ); + } + else + x264_log( h, X264_LOG_INFO, "kb/s:%.2f\n", f_bitrate ); + } + + /* rc */ + x264_ratecontrol_delete( h ); + + /* param */ + if( h->param.rc.psz_stat_out ) + free( h->param.rc.psz_stat_out ); + if( h->param.rc.psz_stat_in ) + free( h->param.rc.psz_stat_in ); + + x264_cqm_delete( h ); + x264_free( h->nal_buffer ); + x264_free( h->reconfig_h ); + x264_analyse_free_costs( h ); + + if( h->i_thread_frames > 1 ) + h = h->thread[h->i_thread_phase]; + + /* frames */ + x264_frame_delete_list( h->frames.unused[0] ); + x264_frame_delete_list( h->frames.unused[1] ); + x264_frame_delete_list( h->frames.current ); + x264_frame_delete_list( h->frames.blank_unused ); + + h = h->thread[0]; + + for( int i = 0; i < h->i_thread_frames; i++ ) + if( h->thread[i]->b_thread_active ) + for( int j = 0; j < h->thread[i]->i_ref[0]; j++ ) + if( h->thread[i]->fref[0][j] && h->thread[i]->fref[0][j]->b_duplicate ) + x264_frame_delete( h->thread[i]->fref[0][j] ); + + if( h->param.i_lookahead_threads > 1 ) + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) + x264_free( h->lookahead_thread[i] ); + + for( int i = h->param.i_threads - 1; i >= 0; i-- ) + { + x264_frame_t **frame; + + if( !h->param.b_sliced_threads || i == 0 ) + { + for( frame = h->thread[i]->frames.reference; *frame; frame++ ) + { + assert( (*frame)->i_reference_count > 0 ); + (*frame)->i_reference_count--; + if( (*frame)->i_reference_count == 0 ) + x264_frame_delete( *frame ); + } + frame = &h->thread[i]->fdec; + if( *frame ) + { + assert( (*frame)->i_reference_count > 0 ); + (*frame)->i_reference_count--; + if( (*frame)->i_reference_count == 0 ) + x264_frame_delete( *frame ); + } + x264_macroblock_cache_free( h->thread[i] ); + } + x264_macroblock_thread_free( h->thread[i], 0 ); + x264_free( h->thread[i]->out.p_bitstream ); + x264_free( h->thread[i]->out.nal ); + x264_pthread_mutex_destroy( &h->thread[i]->mutex ); + x264_pthread_cond_destroy( &h->thread[i]->cv ); + x264_free( h->thread[i] ); + } +#if HAVE_OPENCL + x264_opencl_close_library( ocl ); +#endif +} + +int x264_encoder_delayed_frames( x264_t *h ) +{ + int delayed_frames = 0; + if( h->i_thread_frames > 1 ) + { + for( int i = 0; i < h->i_thread_frames; i++ ) + delayed_frames += h->thread[i]->b_thread_active; + h = h->thread[h->i_thread_phase]; + } + for( int i = 0; h->frames.current[i]; i++ ) + delayed_frames++; + x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex ); + x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex ); + x264_pthread_mutex_lock( &h->lookahead->next.mutex ); + delayed_frames += h->lookahead->ifbuf.i_size + h->lookahead->next.i_size + h->lookahead->ofbuf.i_size; + x264_pthread_mutex_unlock( &h->lookahead->next.mutex ); + x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex ); + x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex ); + return delayed_frames; +} + +int x264_encoder_maximum_delayed_frames( x264_t *h ) +{ + return h->frames.i_delay; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/lookahead.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/lookahead.c new file mode 100644 index 00000000..2080c461 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/lookahead.c @@ -0,0 +1,244 @@ +/***************************************************************************** + * lookahead.c: high-level lookahead functions + ***************************************************************************** + * Copyright (C) 2010-2017 Avail Media and x264 project + * + * Authors: Michael Kazmier + * Alex Giladi + * Steven Walters + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +/* LOOKAHEAD (threaded and non-threaded mode) + * + * Lookahead types: + * [1] Slice type / scene cut; + * + * In non-threaded mode, we run the existing slicetype decision code as it was. + * In threaded mode, we run in a separate thread, that lives between the calls + * to x264_encoder_open() and x264_encoder_close(), and performs lookahead for + * the number of frames specified in rc_lookahead. Recommended setting is + * # of bframes + # of threads. + */ +#include "common/common.h" +#include "analyse.h" + +static void x264_lookahead_shift( x264_sync_frame_list_t *dst, x264_sync_frame_list_t *src, int count ) +{ + int i = count; + while( i-- ) + { + assert( dst->i_size < dst->i_max_size ); + assert( src->i_size ); + dst->list[ dst->i_size++ ] = x264_frame_shift( src->list ); + src->i_size--; + } + if( count ) + { + x264_pthread_cond_broadcast( &dst->cv_fill ); + x264_pthread_cond_broadcast( &src->cv_empty ); + } +} + +static void x264_lookahead_update_last_nonb( x264_t *h, x264_frame_t *new_nonb ) +{ + if( h->lookahead->last_nonb ) + x264_frame_push_unused( h, h->lookahead->last_nonb ); + h->lookahead->last_nonb = new_nonb; + new_nonb->i_reference_count++; +} + +#if HAVE_THREAD +static void x264_lookahead_slicetype_decide( x264_t *h ) +{ + x264_stack_align( x264_slicetype_decide, h ); + + x264_lookahead_update_last_nonb( h, h->lookahead->next.list[0] ); + int shift_frames = h->lookahead->next.list[0]->i_bframes + 1; + + x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex ); + while( h->lookahead->ofbuf.i_size == h->lookahead->ofbuf.i_max_size ) + x264_pthread_cond_wait( &h->lookahead->ofbuf.cv_empty, &h->lookahead->ofbuf.mutex ); + + x264_pthread_mutex_lock( &h->lookahead->next.mutex ); + x264_lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, shift_frames ); + x264_pthread_mutex_unlock( &h->lookahead->next.mutex ); + + /* For MB-tree and VBV lookahead, we have to perform propagation analysis on I-frames too. */ + if( h->lookahead->b_analyse_keyframe && IS_X264_TYPE_I( h->lookahead->last_nonb->i_type ) ) + x264_stack_align( x264_slicetype_analyse, h, shift_frames ); + + x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex ); +} + +static void *x264_lookahead_thread( x264_t *h ) +{ + while( !h->lookahead->b_exit_thread ) + { + x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex ); + x264_pthread_mutex_lock( &h->lookahead->next.mutex ); + int shift = X264_MIN( h->lookahead->next.i_max_size - h->lookahead->next.i_size, h->lookahead->ifbuf.i_size ); + x264_lookahead_shift( &h->lookahead->next, &h->lookahead->ifbuf, shift ); + x264_pthread_mutex_unlock( &h->lookahead->next.mutex ); + if( h->lookahead->next.i_size <= h->lookahead->i_slicetype_length + h->param.b_vfr_input ) + { + while( !h->lookahead->ifbuf.i_size && !h->lookahead->b_exit_thread ) + x264_pthread_cond_wait( &h->lookahead->ifbuf.cv_fill, &h->lookahead->ifbuf.mutex ); + x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex ); + } + else + { + x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex ); + x264_lookahead_slicetype_decide( h ); + } + } /* end of input frames */ + x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex ); + x264_pthread_mutex_lock( &h->lookahead->next.mutex ); + x264_lookahead_shift( &h->lookahead->next, &h->lookahead->ifbuf, h->lookahead->ifbuf.i_size ); + x264_pthread_mutex_unlock( &h->lookahead->next.mutex ); + x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex ); + while( h->lookahead->next.i_size ) + x264_lookahead_slicetype_decide( h ); + x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex ); + h->lookahead->b_thread_active = 0; + x264_pthread_cond_broadcast( &h->lookahead->ofbuf.cv_fill ); + x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex ); + return NULL; +} +#endif + +int x264_lookahead_init( x264_t *h, int i_slicetype_length ) +{ + x264_lookahead_t *look; + CHECKED_MALLOCZERO( look, sizeof(x264_lookahead_t) ); + for( int i = 0; i < h->param.i_threads; i++ ) + h->thread[i]->lookahead = look; + + look->i_last_keyframe = - h->param.i_keyint_max; + look->b_analyse_keyframe = (h->param.rc.b_mb_tree || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead)) + && !h->param.rc.b_stat_read; + look->i_slicetype_length = i_slicetype_length; + + /* init frame lists */ + if( x264_sync_frame_list_init( &look->ifbuf, h->param.i_sync_lookahead+3 ) || + x264_sync_frame_list_init( &look->next, h->frames.i_delay+3 ) || + x264_sync_frame_list_init( &look->ofbuf, h->frames.i_delay+3 ) ) + goto fail; + + if( !h->param.i_sync_lookahead ) + return 0; + + x264_t *look_h = h->thread[h->param.i_threads]; + *look_h = *h; + if( x264_macroblock_cache_allocate( look_h ) ) + goto fail; + + if( x264_macroblock_thread_allocate( look_h, 1 ) < 0 ) + goto fail; + + if( x264_pthread_create( &look->thread_handle, NULL, (void*)x264_lookahead_thread, look_h ) ) + goto fail; + look->b_thread_active = 1; + + return 0; +fail: + x264_free( look ); + return -1; +} + +void x264_lookahead_delete( x264_t *h ) +{ + if( h->param.i_sync_lookahead ) + { + x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex ); + h->lookahead->b_exit_thread = 1; + x264_pthread_cond_broadcast( &h->lookahead->ifbuf.cv_fill ); + x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex ); + x264_pthread_join( h->lookahead->thread_handle, NULL ); + x264_macroblock_cache_free( h->thread[h->param.i_threads] ); + x264_macroblock_thread_free( h->thread[h->param.i_threads], 1 ); + x264_free( h->thread[h->param.i_threads] ); + } + x264_sync_frame_list_delete( &h->lookahead->ifbuf ); + x264_sync_frame_list_delete( &h->lookahead->next ); + if( h->lookahead->last_nonb ) + x264_frame_push_unused( h, h->lookahead->last_nonb ); + x264_sync_frame_list_delete( &h->lookahead->ofbuf ); + x264_free( h->lookahead ); +} + +void x264_lookahead_put_frame( x264_t *h, x264_frame_t *frame ) +{ + if( h->param.i_sync_lookahead ) + x264_sync_frame_list_push( &h->lookahead->ifbuf, frame ); + else + x264_sync_frame_list_push( &h->lookahead->next, frame ); +} + +int x264_lookahead_is_empty( x264_t *h ) +{ + x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex ); + x264_pthread_mutex_lock( &h->lookahead->next.mutex ); + int b_empty = !h->lookahead->next.i_size && !h->lookahead->ofbuf.i_size; + x264_pthread_mutex_unlock( &h->lookahead->next.mutex ); + x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex ); + return b_empty; +} + +static void x264_lookahead_encoder_shift( x264_t *h ) +{ + if( !h->lookahead->ofbuf.i_size ) + return; + int i_frames = h->lookahead->ofbuf.list[0]->i_bframes + 1; + while( i_frames-- ) + { + x264_frame_push( h->frames.current, x264_frame_shift( h->lookahead->ofbuf.list ) ); + h->lookahead->ofbuf.i_size--; + } + x264_pthread_cond_broadcast( &h->lookahead->ofbuf.cv_empty ); +} + +void x264_lookahead_get_frames( x264_t *h ) +{ + if( h->param.i_sync_lookahead ) + { /* We have a lookahead thread, so get frames from there */ + x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex ); + while( !h->lookahead->ofbuf.i_size && h->lookahead->b_thread_active ) + x264_pthread_cond_wait( &h->lookahead->ofbuf.cv_fill, &h->lookahead->ofbuf.mutex ); + x264_lookahead_encoder_shift( h ); + x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex ); + } + else + { /* We are not running a lookahead thread, so perform all the slicetype decide on the fly */ + + if( h->frames.current[0] || !h->lookahead->next.i_size ) + return; + + x264_stack_align( x264_slicetype_decide, h ); + x264_lookahead_update_last_nonb( h, h->lookahead->next.list[0] ); + int shift_frames = h->lookahead->next.list[0]->i_bframes + 1; + x264_lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, shift_frames ); + + /* For MB-tree and VBV lookahead, we have to perform propagation analysis on I-frames too. */ + if( h->lookahead->b_analyse_keyframe && IS_X264_TYPE_I( h->lookahead->last_nonb->i_type ) ) + x264_stack_align( x264_slicetype_analyse, h, shift_frames ); + + x264_lookahead_encoder_shift( h ); + } +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/macroblock.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/macroblock.c new file mode 100644 index 00000000..929fcc8e --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/macroblock.c @@ -0,0 +1,1419 @@ +/***************************************************************************** + * macroblock.c: macroblock encoding + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * Henrik Gramner + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "macroblock.h" + +/* These chroma DC functions don't have assembly versions and are only used here. */ + +#define ZIG(i,y,x) level[i] = dct[x*2+y]; +static inline void zigzag_scan_2x2_dc( dctcoef level[4], dctcoef dct[4] ) +{ + ZIG(0,0,0) + ZIG(1,0,1) + ZIG(2,1,0) + ZIG(3,1,1) +} +#undef ZIG + +static inline void zigzag_scan_2x4_dc( dctcoef level[8], dctcoef dct[8] ) +{ + level[0] = dct[0]; + level[1] = dct[2]; + level[2] = dct[1]; + level[3] = dct[4]; + level[4] = dct[6]; + level[5] = dct[3]; + level[6] = dct[5]; + level[7] = dct[7]; +} + +#define IDCT_DEQUANT_2X2_START \ + int d0 = dct[0] + dct[1]; \ + int d1 = dct[2] + dct[3]; \ + int d2 = dct[0] - dct[1]; \ + int d3 = dct[2] - dct[3]; \ + int dmf = dequant_mf[i_qp%6][0] << i_qp/6; + +static inline void idct_dequant_2x2_dc( dctcoef dct[4], dctcoef dct4x4[4][16], int dequant_mf[6][16], int i_qp ) +{ + IDCT_DEQUANT_2X2_START + dct4x4[0][0] = (d0 + d1) * dmf >> 5; + dct4x4[1][0] = (d0 - d1) * dmf >> 5; + dct4x4[2][0] = (d2 + d3) * dmf >> 5; + dct4x4[3][0] = (d2 - d3) * dmf >> 5; +} + +static inline void idct_dequant_2x2_dconly( dctcoef dct[4], int dequant_mf[6][16], int i_qp ) +{ + IDCT_DEQUANT_2X2_START + dct[0] = (d0 + d1) * dmf >> 5; + dct[1] = (d0 - d1) * dmf >> 5; + dct[2] = (d2 + d3) * dmf >> 5; + dct[3] = (d2 - d3) * dmf >> 5; +} +#undef IDCT_2X2_DEQUANT_START + +static inline void dct2x2dc( dctcoef d[4], dctcoef dct4x4[4][16] ) +{ + int d0 = dct4x4[0][0] + dct4x4[1][0]; + int d1 = dct4x4[2][0] + dct4x4[3][0]; + int d2 = dct4x4[0][0] - dct4x4[1][0]; + int d3 = dct4x4[2][0] - dct4x4[3][0]; + d[0] = d0 + d1; + d[2] = d2 + d3; + d[1] = d0 - d1; + d[3] = d2 - d3; + dct4x4[0][0] = 0; + dct4x4[1][0] = 0; + dct4x4[2][0] = 0; + dct4x4[3][0] = 0; +} + +static ALWAYS_INLINE int array_non_zero( dctcoef *v, int i_count ) +{ + if( WORD_SIZE == 8 ) + { + for( int i = 0; i < i_count; i += 8/sizeof(dctcoef) ) + if( M64( &v[i] ) ) + return 1; + } + else + { + for( int i = 0; i < i_count; i += 4/sizeof(dctcoef) ) + if( M32( &v[i] ) ) + return 1; + } + return 0; +} + +/* All encoding functions must output the correct CBP and NNZ values. + * The entropy coding functions will check CBP first, then NNZ, before + * actually reading the DCT coefficients. NNZ still must be correct even + * if CBP is zero because of the use of NNZ values for context selection. + * "NNZ" need only be 0 or 1 rather than the exact coefficient count because + * that is only needed in CAVLC, and will be calculated by CAVLC's residual + * coding and stored as necessary. */ + +/* This means that decimation can be done merely by adjusting the CBP and NNZ + * rather than memsetting the coefficients. */ + +static void x264_mb_encode_i16x16( x264_t *h, int p, int i_qp ) +{ + pixel *p_src = h->mb.pic.p_fenc[p]; + pixel *p_dst = h->mb.pic.p_fdec[p]; + + ALIGNED_ARRAY_64( dctcoef, dct4x4,[16],[16] ); + ALIGNED_ARRAY_64( dctcoef, dct_dc4x4,[16] ); + + int nz, block_cbp = 0; + int decimate_score = h->mb.b_dct_decimate ? 0 : 9; + int i_quant_cat = p ? CQM_4IC : CQM_4IY; + int i_mode = h->mb.i_intra16x16_pred_mode; + + if( h->mb.b_lossless ) + x264_predict_lossless_16x16( h, p, i_mode ); + else + h->predict_16x16[i_mode]( h->mb.pic.p_fdec[p] ); + + if( h->mb.b_lossless ) + { + for( int i = 0; i < 16; i++ ) + { + int oe = block_idx_xy_fenc[i]; + int od = block_idx_xy_fdec[i]; + nz = h->zigzagf.sub_4x4ac( h->dct.luma4x4[16*p+i], p_src+oe, p_dst+od, &dct_dc4x4[block_idx_yx_1d[i]] ); + h->mb.cache.non_zero_count[x264_scan8[16*p+i]] = nz; + block_cbp |= nz; + } + h->mb.i_cbp_luma |= block_cbp * 0xf; + h->mb.cache.non_zero_count[x264_scan8[LUMA_DC+p]] = array_non_zero( dct_dc4x4, 16 ); + h->zigzagf.scan_4x4( h->dct.luma16x16_dc[p], dct_dc4x4 ); + return; + } + + CLEAR_16x16_NNZ( p ); + + h->dctf.sub16x16_dct( dct4x4, p_src, p_dst ); + + if( h->mb.b_noise_reduction ) + for( int idx = 0; idx < 16; idx++ ) + h->quantf.denoise_dct( dct4x4[idx], h->nr_residual_sum[0], h->nr_offset[0], 16 ); + + for( int idx = 0; idx < 16; idx++ ) + { + dct_dc4x4[block_idx_xy_1d[idx]] = dct4x4[idx][0]; + dct4x4[idx][0] = 0; + } + + if( h->mb.b_trellis ) + { + for( int idx = 0; idx < 16; idx++ ) + if( x264_quant_4x4_trellis( h, dct4x4[idx], i_quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_AC][p], 1, !!p, idx ) ) + { + block_cbp = 0xf; + h->zigzagf.scan_4x4( h->dct.luma4x4[16*p+idx], dct4x4[idx] ); + h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[i_quant_cat], i_qp ); + if( decimate_score < 6 ) decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[16*p+idx] ); + h->mb.cache.non_zero_count[x264_scan8[16*p+idx]] = 1; + } + } + else + { + for( int i8x8 = 0; i8x8 < 4; i8x8++ ) + { + nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias[i_quant_cat][i_qp] ); + if( nz ) + { + block_cbp = 0xf; + FOREACH_BIT( idx, i8x8*4, nz ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[16*p+idx], dct4x4[idx] ); + h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[i_quant_cat], i_qp ); + if( decimate_score < 6 ) decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[16*p+idx] ); + h->mb.cache.non_zero_count[x264_scan8[16*p+idx]] = 1; + } + } + } + } + + /* Writing the 16 CBFs in an i16x16 block is quite costly, so decimation can save many bits. */ + /* More useful with CAVLC, but still useful with CABAC. */ + if( decimate_score < 6 ) + { + CLEAR_16x16_NNZ( p ); + block_cbp = 0; + } + else + h->mb.i_cbp_luma |= block_cbp; + + h->dctf.dct4x4dc( dct_dc4x4 ); + if( h->mb.b_trellis ) + nz = x264_quant_luma_dc_trellis( h, dct_dc4x4, i_quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_DC][p], 1, LUMA_DC+p ); + else + nz = h->quantf.quant_4x4_dc( dct_dc4x4, h->quant4_mf[i_quant_cat][i_qp][0]>>1, h->quant4_bias[i_quant_cat][i_qp][0]<<1 ); + + h->mb.cache.non_zero_count[x264_scan8[LUMA_DC+p]] = nz; + if( nz ) + { + h->zigzagf.scan_4x4( h->dct.luma16x16_dc[p], dct_dc4x4 ); + + /* output samples to fdec */ + h->dctf.idct4x4dc( dct_dc4x4 ); + h->quantf.dequant_4x4_dc( dct_dc4x4, h->dequant4_mf[i_quant_cat], i_qp ); /* XXX not inversed */ + if( block_cbp ) + for( int i = 0; i < 16; i++ ) + dct4x4[i][0] = dct_dc4x4[block_idx_xy_1d[i]]; + } + + /* put pixels to fdec */ + if( block_cbp ) + h->dctf.add16x16_idct( p_dst, dct4x4 ); + else if( nz ) + h->dctf.add16x16_idct_dc( p_dst, dct_dc4x4 ); +} + +/* Round down coefficients losslessly in DC-only chroma blocks. + * Unlike luma blocks, this can't be done with a lookup table or + * other shortcut technique because of the interdependencies + * between the coefficients due to the chroma DC transform. */ +static ALWAYS_INLINE int x264_mb_optimize_chroma_dc( x264_t *h, dctcoef *dct_dc, int dequant_mf[6][16], int i_qp, int chroma422 ) +{ + int dmf = dequant_mf[i_qp%6][0] << i_qp/6; + + /* If the QP is too high, there's no benefit to rounding optimization. */ + if( dmf > 32*64 ) + return 1; + + if( chroma422 ) + return h->quantf.optimize_chroma_2x4_dc( dct_dc, dmf ); + else + return h->quantf.optimize_chroma_2x2_dc( dct_dc, dmf ); +} + +static ALWAYS_INLINE void x264_mb_encode_chroma_internal( x264_t *h, int b_inter, int i_qp, int chroma422 ) +{ + int nz, nz_dc; + int b_decimate = b_inter && h->mb.b_dct_decimate; + int (*dequant_mf)[16] = h->dequant4_mf[CQM_4IC + b_inter]; + ALIGNED_ARRAY_16( dctcoef, dct_dc,[8] ); + h->mb.i_cbp_chroma = 0; + h->nr_count[2] += h->mb.b_noise_reduction * 4; + + M16( &h->mb.cache.non_zero_count[x264_scan8[16]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[18]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[32]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[34]] ) = 0; + if( chroma422 ) + { + M16( &h->mb.cache.non_zero_count[x264_scan8[24]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[26]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[40]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[42]] ) = 0; + } + + /* Early termination: check variance of chroma residual before encoding. + * Don't bother trying early termination at low QPs. + * Values are experimentally derived. */ + if( b_decimate && i_qp >= (h->mb.b_trellis ? 12 : 18) && !h->mb.b_noise_reduction ) + { + int thresh = chroma422 ? (x264_lambda2_tab[i_qp] + 16) >> 5 : (x264_lambda2_tab[i_qp] + 32) >> 6; + ALIGNED_ARRAY_8( int, ssd,[2] ); + int chromapix = chroma422 ? PIXEL_8x16 : PIXEL_8x8; + + if( h->pixf.var2[chromapix]( h->mb.pic.p_fenc[1], h->mb.pic.p_fdec[1], ssd ) < thresh*4 ) + { + h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]] = 0; + h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]] = 0; + + for( int ch = 0; ch < 2; ch++ ) + { + if( ssd[ch] > thresh ) + { + pixel *p_src = h->mb.pic.p_fenc[1+ch]; + pixel *p_dst = h->mb.pic.p_fdec[1+ch]; + + if( chroma422 ) + /* Cannot be replaced by two calls to sub8x8_dct_dc since the hadamard transform is different */ + h->dctf.sub8x16_dct_dc( dct_dc, p_src, p_dst ); + else + h->dctf.sub8x8_dct_dc( dct_dc, p_src, p_dst ); + + if( h->mb.b_trellis ) + nz_dc = x264_quant_chroma_dc_trellis( h, dct_dc, i_qp+3*chroma422, !b_inter, CHROMA_DC+ch ); + else + { + nz_dc = 0; + for( int i = 0; i <= chroma422; i++ ) + nz_dc |= h->quantf.quant_2x2_dc( &dct_dc[4*i], h->quant4_mf[CQM_4IC+b_inter][i_qp+3*chroma422][0] >> 1, + h->quant4_bias[CQM_4IC+b_inter][i_qp+3*chroma422][0] << 1 ); + } + + if( nz_dc ) + { + if( !x264_mb_optimize_chroma_dc( h, dct_dc, dequant_mf, i_qp+3*chroma422, chroma422 ) ) + continue; + h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+ch]] = 1; + if( chroma422 ) + { + zigzag_scan_2x4_dc( h->dct.chroma_dc[ch], dct_dc ); + h->quantf.idct_dequant_2x4_dconly( dct_dc, dequant_mf, i_qp+3 ); + } + else + { + zigzag_scan_2x2_dc( h->dct.chroma_dc[ch], dct_dc ); + idct_dequant_2x2_dconly( dct_dc, dequant_mf, i_qp ); + } + + for( int i = 0; i <= chroma422; i++ ) + h->dctf.add8x8_idct_dc( p_dst + 8*i*FDEC_STRIDE, &dct_dc[4*i] ); + h->mb.i_cbp_chroma = 1; + } + } + } + return; + } + } + + for( int ch = 0; ch < 2; ch++ ) + { + pixel *p_src = h->mb.pic.p_fenc[1+ch]; + pixel *p_dst = h->mb.pic.p_fdec[1+ch]; + int i_decimate_score = b_decimate ? 0 : 7; + int nz_ac = 0; + + ALIGNED_ARRAY_64( dctcoef, dct4x4,[8],[16] ); + + if( h->mb.b_lossless ) + { + static const uint8_t chroma422_scan[8] = { 0, 2, 1, 5, 3, 6, 4, 7 }; + + for( int i = 0; i < (chroma422?8:4); i++ ) + { + int oe = 4*(i&1) + 4*(i>>1)*FENC_STRIDE; + int od = 4*(i&1) + 4*(i>>1)*FDEC_STRIDE; + nz = h->zigzagf.sub_4x4ac( h->dct.luma4x4[16+i+(chroma422?i&4:0)+ch*16], p_src+oe, p_dst+od, + &h->dct.chroma_dc[ch][chroma422?chroma422_scan[i]:i] ); + h->mb.cache.non_zero_count[x264_scan8[16+i+(chroma422?i&4:0)+ch*16]] = nz; + h->mb.i_cbp_chroma |= nz; + } + h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+ch]] = array_non_zero( h->dct.chroma_dc[ch], chroma422?8:4 ); + continue; + } + + for( int i = 0; i <= chroma422; i++ ) + h->dctf.sub8x8_dct( &dct4x4[4*i], p_src + 8*i*FENC_STRIDE, p_dst + 8*i*FDEC_STRIDE ); + + if( h->mb.b_noise_reduction ) + for( int i = 0; i < (chroma422?8:4); i++ ) + h->quantf.denoise_dct( dct4x4[i], h->nr_residual_sum[2], h->nr_offset[2], 16 ); + + if( chroma422 ) + h->dctf.dct2x4dc( dct_dc, dct4x4 ); + else + dct2x2dc( dct_dc, dct4x4 ); + + /* calculate dct coeffs */ + for( int i8x8 = 0; i8x8 < (chroma422?2:1); i8x8++ ) + { + if( h->mb.b_trellis ) + { + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + { + if( x264_quant_4x4_trellis( h, dct4x4[i8x8*4+i4x4], CQM_4IC+b_inter, i_qp, DCT_CHROMA_AC, !b_inter, 1, 0 ) ) + { + int idx = 16+ch*16+i8x8*8+i4x4; + h->zigzagf.scan_4x4( h->dct.luma4x4[idx], dct4x4[i8x8*4+i4x4] ); + h->quantf.dequant_4x4( dct4x4[i8x8*4+i4x4], dequant_mf, i_qp ); + if( i_decimate_score < 7 ) + i_decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[idx] ); + h->mb.cache.non_zero_count[x264_scan8[idx]] = 1; + nz_ac = 1; + } + } + } + else + { + nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[CQM_4IC+b_inter][i_qp], + h->quant4_bias[CQM_4IC+b_inter][i_qp] ); + nz_ac |= nz; + + FOREACH_BIT( i4x4, 0, nz ) + { + int idx = 16+ch*16+i8x8*8+i4x4; + + h->zigzagf.scan_4x4( h->dct.luma4x4[idx], dct4x4[i8x8*4+i4x4] ); + h->quantf.dequant_4x4( dct4x4[i8x8*4+i4x4], dequant_mf, i_qp ); + if( i_decimate_score < 7 ) + i_decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[idx] ); + h->mb.cache.non_zero_count[x264_scan8[idx]] = 1; + } + } + } + + if( h->mb.b_trellis ) + nz_dc = x264_quant_chroma_dc_trellis( h, dct_dc, i_qp+3*chroma422, !b_inter, CHROMA_DC+ch ); + else + { + nz_dc = 0; + for( int i = 0; i <= chroma422; i++ ) + nz_dc |= h->quantf.quant_2x2_dc( &dct_dc[4*i], h->quant4_mf[CQM_4IC+b_inter][i_qp+3*chroma422][0] >> 1, + h->quant4_bias[CQM_4IC+b_inter][i_qp+3*chroma422][0] << 1 ); + } + + h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+ch]] = nz_dc; + + if( i_decimate_score < 7 || !nz_ac ) + { + /* Decimate the block */ + M16( &h->mb.cache.non_zero_count[x264_scan8[16+16*ch]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[18+16*ch]] ) = 0; + if( chroma422 ) + { + M16( &h->mb.cache.non_zero_count[x264_scan8[24+16*ch]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[26+16*ch]] ) = 0; + } + + if( !nz_dc ) /* Whole block is empty */ + continue; + if( !x264_mb_optimize_chroma_dc( h, dct_dc, dequant_mf, i_qp+3*chroma422, chroma422 ) ) + { + h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+ch]] = 0; + continue; + } + /* DC-only */ + if( chroma422 ) + { + zigzag_scan_2x4_dc( h->dct.chroma_dc[ch], dct_dc ); + h->quantf.idct_dequant_2x4_dconly( dct_dc, dequant_mf, i_qp+3 ); + } + else + { + zigzag_scan_2x2_dc( h->dct.chroma_dc[ch], dct_dc ); + idct_dequant_2x2_dconly( dct_dc, dequant_mf, i_qp ); + } + + for( int i = 0; i <= chroma422; i++ ) + h->dctf.add8x8_idct_dc( p_dst + 8*i*FDEC_STRIDE, &dct_dc[4*i] ); + } + else + { + h->mb.i_cbp_chroma = 1; + + if( nz_dc ) + { + if( chroma422 ) + { + zigzag_scan_2x4_dc( h->dct.chroma_dc[ch], dct_dc ); + h->quantf.idct_dequant_2x4_dc( dct_dc, dct4x4, dequant_mf, i_qp+3 ); + } + else + { + zigzag_scan_2x2_dc( h->dct.chroma_dc[ch], dct_dc ); + idct_dequant_2x2_dc( dct_dc, dct4x4, dequant_mf, i_qp ); + } + } + + for( int i = 0; i <= chroma422; i++ ) + h->dctf.add8x8_idct( p_dst + 8*i*FDEC_STRIDE, &dct4x4[4*i] ); + } + } + + /* 0 = none, 1 = DC only, 2 = DC+AC */ + h->mb.i_cbp_chroma += (h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]] | + h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]] | h->mb.i_cbp_chroma); +} + +void x264_mb_encode_chroma( x264_t *h, int b_inter, int i_qp ) +{ + if( CHROMA_FORMAT == CHROMA_420 ) + x264_mb_encode_chroma_internal( h, b_inter, i_qp, 0 ); + else + x264_mb_encode_chroma_internal( h, b_inter, i_qp, 1 ); +} + +static void x264_macroblock_encode_skip( x264_t *h ) +{ + M32( &h->mb.cache.non_zero_count[x264_scan8[ 0]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[ 2]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[ 8]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[10]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[16+ 0]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[16+ 2]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[32+ 0]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[32+ 2]] ) = 0; + if( CHROMA_FORMAT >= CHROMA_422 ) + { + M32( &h->mb.cache.non_zero_count[x264_scan8[16+ 8]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[16+10]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[32+ 8]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[32+10]] ) = 0; + } + h->mb.i_cbp_luma = 0; + h->mb.i_cbp_chroma = 0; + h->mb.cbp[h->mb.i_mb_xy] = 0; +} + +/***************************************************************************** + * Intra prediction for predictive lossless mode. + *****************************************************************************/ + +void x264_predict_lossless_chroma( x264_t *h, int i_mode ) +{ + int height = 16 >> CHROMA_V_SHIFT; + if( i_mode == I_PRED_CHROMA_V ) + { + h->mc.copy[PIXEL_8x8]( h->mb.pic.p_fdec[1], FDEC_STRIDE, h->mb.pic.p_fenc[1]-FENC_STRIDE, FENC_STRIDE, height ); + h->mc.copy[PIXEL_8x8]( h->mb.pic.p_fdec[2], FDEC_STRIDE, h->mb.pic.p_fenc[2]-FENC_STRIDE, FENC_STRIDE, height ); + memcpy( h->mb.pic.p_fdec[1], h->mb.pic.p_fdec[1]-FDEC_STRIDE, 8*sizeof(pixel) ); + memcpy( h->mb.pic.p_fdec[2], h->mb.pic.p_fdec[2]-FDEC_STRIDE, 8*sizeof(pixel) ); + } + else if( i_mode == I_PRED_CHROMA_H ) + { + h->mc.copy[PIXEL_8x8]( h->mb.pic.p_fdec[1], FDEC_STRIDE, h->mb.pic.p_fenc[1]-1, FENC_STRIDE, height ); + h->mc.copy[PIXEL_8x8]( h->mb.pic.p_fdec[2], FDEC_STRIDE, h->mb.pic.p_fenc[2]-1, FENC_STRIDE, height ); + x264_copy_column8( h->mb.pic.p_fdec[1]+4*FDEC_STRIDE, h->mb.pic.p_fdec[1]+4*FDEC_STRIDE-1 ); + x264_copy_column8( h->mb.pic.p_fdec[2]+4*FDEC_STRIDE, h->mb.pic.p_fdec[2]+4*FDEC_STRIDE-1 ); + if( CHROMA_FORMAT == CHROMA_422 ) + { + x264_copy_column8( h->mb.pic.p_fdec[1]+12*FDEC_STRIDE, h->mb.pic.p_fdec[1]+12*FDEC_STRIDE-1 ); + x264_copy_column8( h->mb.pic.p_fdec[2]+12*FDEC_STRIDE, h->mb.pic.p_fdec[2]+12*FDEC_STRIDE-1 ); + } + } + else + { + h->predict_chroma[i_mode]( h->mb.pic.p_fdec[1] ); + h->predict_chroma[i_mode]( h->mb.pic.p_fdec[2] ); + } +} + +void x264_predict_lossless_4x4( x264_t *h, pixel *p_dst, int p, int idx, int i_mode ) +{ + int stride = h->fenc->i_stride[p] << MB_INTERLACED; + pixel *p_src = h->mb.pic.p_fenc_plane[p] + block_idx_x[idx]*4 + block_idx_y[idx]*4 * stride; + + if( i_mode == I_PRED_4x4_V ) + { + h->mc.copy[PIXEL_4x4]( p_dst, FDEC_STRIDE, p_src-stride, stride, 4 ); + memcpy( p_dst, p_dst-FDEC_STRIDE, 4*sizeof(pixel) ); + } + else if( i_mode == I_PRED_4x4_H ) + { + h->mc.copy[PIXEL_4x4]( p_dst, FDEC_STRIDE, p_src-1, stride, 4 ); + for( int i = 0; i < 4; i++ ) + p_dst[i*FDEC_STRIDE] = p_dst[i*FDEC_STRIDE-1]; + } + else + h->predict_4x4[i_mode]( p_dst ); +} + +void x264_predict_lossless_8x8( x264_t *h, pixel *p_dst, int p, int idx, int i_mode, pixel edge[36] ) +{ + int stride = h->fenc->i_stride[p] << MB_INTERLACED; + pixel *p_src = h->mb.pic.p_fenc_plane[p] + (idx&1)*8 + (idx>>1)*8*stride; + + if( i_mode == I_PRED_8x8_V ) + { + h->mc.copy[PIXEL_8x8]( p_dst, FDEC_STRIDE, p_src-stride, stride, 8 ); + memcpy( p_dst, &edge[16], 8*sizeof(pixel) ); + } + else if( i_mode == I_PRED_8x8_H ) + { + h->mc.copy[PIXEL_8x8]( p_dst, FDEC_STRIDE, p_src-1, stride, 8 ); + for( int i = 0; i < 8; i++ ) + p_dst[i*FDEC_STRIDE] = edge[14-i]; + } + else + h->predict_8x8[i_mode]( p_dst, edge ); +} + +void x264_predict_lossless_16x16( x264_t *h, int p, int i_mode ) +{ + int stride = h->fenc->i_stride[p] << MB_INTERLACED; + pixel *p_dst = h->mb.pic.p_fdec[p]; + + if( i_mode == I_PRED_16x16_V ) + { + h->mc.copy[PIXEL_16x16]( p_dst, FDEC_STRIDE, h->mb.pic.p_fenc_plane[p]-stride, stride, 16 ); + memcpy( p_dst, p_dst-FDEC_STRIDE, 16*sizeof(pixel) ); + } + else if( i_mode == I_PRED_16x16_H ) + { + h->mc.copy_16x16_unaligned( p_dst, FDEC_STRIDE, h->mb.pic.p_fenc_plane[p]-1, stride, 16 ); + for( int i = 0; i < 16; i++ ) + p_dst[i*FDEC_STRIDE] = p_dst[i*FDEC_STRIDE-1]; + } + else + h->predict_16x16[i_mode]( p_dst ); +} + +/***************************************************************************** + * x264_macroblock_encode: + *****************************************************************************/ +static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_count, int chroma ) +{ + int i_qp = h->mb.i_qp; + int b_decimate = h->mb.b_dct_decimate; + int b_force_no_skip = 0; + int nz; + h->mb.i_cbp_luma = 0; + for( int p = 0; p < plane_count; p++ ) + h->mb.cache.non_zero_count[x264_scan8[LUMA_DC+p]] = 0; + + if( h->mb.i_type == I_PCM ) + { + /* if PCM is chosen, we need to store reconstructed frame data */ + for( int p = 0; p < plane_count; p++ ) + h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fdec[p], FDEC_STRIDE, h->mb.pic.p_fenc[p], FENC_STRIDE, 16 ); + if( chroma ) + { + int height = 16 >> CHROMA_V_SHIFT; + h->mc.copy[PIXEL_8x8] ( h->mb.pic.p_fdec[1], FDEC_STRIDE, h->mb.pic.p_fenc[1], FENC_STRIDE, height ); + h->mc.copy[PIXEL_8x8] ( h->mb.pic.p_fdec[2], FDEC_STRIDE, h->mb.pic.p_fenc[2], FENC_STRIDE, height ); + } + return; + } + + if( !h->mb.b_allow_skip ) + { + b_force_no_skip = 1; + if( IS_SKIP(h->mb.i_type) ) + { + if( h->mb.i_type == P_SKIP ) + h->mb.i_type = P_L0; + else if( h->mb.i_type == B_SKIP ) + h->mb.i_type = B_DIRECT; + } + } + + if( h->mb.i_type == P_SKIP ) + { + /* don't do pskip motion compensation if it was already done in macroblock_analyse */ + if( !h->mb.b_skip_mc ) + { + int mvx = x264_clip3( h->mb.cache.mv[0][x264_scan8[0]][0], + h->mb.mv_min[0], h->mb.mv_max[0] ); + int mvy = x264_clip3( h->mb.cache.mv[0][x264_scan8[0]][1], + h->mb.mv_min[1], h->mb.mv_max[1] ); + + for( int p = 0; p < plane_count; p++ ) + h->mc.mc_luma( h->mb.pic.p_fdec[p], FDEC_STRIDE, + &h->mb.pic.p_fref[0][0][p*4], h->mb.pic.i_stride[p], + mvx, mvy, 16, 16, &h->sh.weight[0][p] ); + + if( chroma ) + { + int v_shift = CHROMA_V_SHIFT; + int height = 16 >> v_shift; + + /* Special case for mv0, which is (of course) very common in P-skip mode. */ + if( mvx | mvy ) + h->mc.mc_chroma( h->mb.pic.p_fdec[1], h->mb.pic.p_fdec[2], FDEC_STRIDE, + h->mb.pic.p_fref[0][0][4], h->mb.pic.i_stride[1], + mvx, 2*mvy>>v_shift, 8, height ); + else + h->mc.load_deinterleave_chroma_fdec( h->mb.pic.p_fdec[1], h->mb.pic.p_fref[0][0][4], + h->mb.pic.i_stride[1], height ); + + if( h->sh.weight[0][1].weightfn ) + h->sh.weight[0][1].weightfn[8>>2]( h->mb.pic.p_fdec[1], FDEC_STRIDE, + h->mb.pic.p_fdec[1], FDEC_STRIDE, + &h->sh.weight[0][1], height ); + if( h->sh.weight[0][2].weightfn ) + h->sh.weight[0][2].weightfn[8>>2]( h->mb.pic.p_fdec[2], FDEC_STRIDE, + h->mb.pic.p_fdec[2], FDEC_STRIDE, + &h->sh.weight[0][2], height ); + } + } + + x264_macroblock_encode_skip( h ); + return; + } + if( h->mb.i_type == B_SKIP ) + { + /* don't do bskip motion compensation if it was already done in macroblock_analyse */ + if( !h->mb.b_skip_mc ) + x264_mb_mc( h ); + x264_macroblock_encode_skip( h ); + return; + } + + if( h->mb.i_type == I_16x16 ) + { + h->mb.b_transform_8x8 = 0; + + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + x264_mb_encode_i16x16( h, p, i_qp ); + } + else if( h->mb.i_type == I_8x8 ) + { + h->mb.b_transform_8x8 = 1; + /* If we already encoded 3 of the 4 i8x8 blocks, we don't have to do them again. */ + if( h->mb.i_skip_intra ) + { + h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fdec[0], FDEC_STRIDE, h->mb.pic.i8x8_fdec_buf, 16, 16 ); + M32( &h->mb.cache.non_zero_count[x264_scan8[ 0]] ) = h->mb.pic.i8x8_nnz_buf[0]; + M32( &h->mb.cache.non_zero_count[x264_scan8[ 2]] ) = h->mb.pic.i8x8_nnz_buf[1]; + M32( &h->mb.cache.non_zero_count[x264_scan8[ 8]] ) = h->mb.pic.i8x8_nnz_buf[2]; + M32( &h->mb.cache.non_zero_count[x264_scan8[10]] ) = h->mb.pic.i8x8_nnz_buf[3]; + h->mb.i_cbp_luma = h->mb.pic.i8x8_cbp; + /* In RD mode, restore the now-overwritten DCT data. */ + if( h->mb.i_skip_intra == 2 ) + h->mc.memcpy_aligned( h->dct.luma8x8, h->mb.pic.i8x8_dct_buf, sizeof(h->mb.pic.i8x8_dct_buf) ); + } + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + { + for( int i = (p == 0 && h->mb.i_skip_intra) ? 3 : 0; i < 4; i++ ) + { + int i_mode = h->mb.cache.intra4x4_pred_mode[x264_scan8[4*i]]; + x264_mb_encode_i8x8( h, p, i, i_qp, i_mode, NULL, 1 ); + } + } + } + else if( h->mb.i_type == I_4x4 ) + { + h->mb.b_transform_8x8 = 0; + /* If we already encoded 15 of the 16 i4x4 blocks, we don't have to do them again. */ + if( h->mb.i_skip_intra ) + { + h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fdec[0], FDEC_STRIDE, h->mb.pic.i4x4_fdec_buf, 16, 16 ); + M32( &h->mb.cache.non_zero_count[x264_scan8[ 0]] ) = h->mb.pic.i4x4_nnz_buf[0]; + M32( &h->mb.cache.non_zero_count[x264_scan8[ 2]] ) = h->mb.pic.i4x4_nnz_buf[1]; + M32( &h->mb.cache.non_zero_count[x264_scan8[ 8]] ) = h->mb.pic.i4x4_nnz_buf[2]; + M32( &h->mb.cache.non_zero_count[x264_scan8[10]] ) = h->mb.pic.i4x4_nnz_buf[3]; + h->mb.i_cbp_luma = h->mb.pic.i4x4_cbp; + /* In RD mode, restore the now-overwritten DCT data. */ + if( h->mb.i_skip_intra == 2 ) + h->mc.memcpy_aligned( h->dct.luma4x4, h->mb.pic.i4x4_dct_buf, sizeof(h->mb.pic.i4x4_dct_buf) ); + } + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + { + for( int i = (p == 0 && h->mb.i_skip_intra) ? 15 : 0; i < 16; i++ ) + { + pixel *p_dst = &h->mb.pic.p_fdec[p][block_idx_xy_fdec[i]]; + int i_mode = h->mb.cache.intra4x4_pred_mode[x264_scan8[i]]; + + if( (h->mb.i_neighbour4[i] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP ) + /* emulate missing topright samples */ + MPIXEL_X4( &p_dst[4-FDEC_STRIDE] ) = PIXEL_SPLAT_X4( p_dst[3-FDEC_STRIDE] ); + + x264_mb_encode_i4x4( h, p, i, i_qp, i_mode, 1 ); + } + } + } + else /* Inter MB */ + { + int i_decimate_mb = 0; + + /* Don't repeat motion compensation if it was already done in non-RD transform analysis */ + if( !h->mb.b_skip_mc ) + x264_mb_mc( h ); + + if( h->mb.b_lossless ) + { + if( h->mb.b_transform_8x8 ) + for( int p = 0; p < plane_count; p++ ) + for( int i8x8 = 0; i8x8 < 4; i8x8++ ) + { + int x = i8x8&1; + int y = i8x8>>1; + nz = h->zigzagf.sub_8x8( h->dct.luma8x8[p*4+i8x8], h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE, + h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE ); + STORE_8x8_NNZ( p, i8x8, nz ); + h->mb.i_cbp_luma |= nz << i8x8; + } + else + for( int p = 0; p < plane_count; p++ ) + for( int i4x4 = 0; i4x4 < 16; i4x4++ ) + { + nz = h->zigzagf.sub_4x4( h->dct.luma4x4[p*16+i4x4], + h->mb.pic.p_fenc[p]+block_idx_xy_fenc[i4x4], + h->mb.pic.p_fdec[p]+block_idx_xy_fdec[i4x4] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+i4x4]] = nz; + h->mb.i_cbp_luma |= nz << (i4x4>>2); + } + } + else if( h->mb.b_transform_8x8 ) + { + ALIGNED_ARRAY_64( dctcoef, dct8x8,[4],[64] ); + b_decimate &= !h->mb.b_trellis || !h->param.b_cabac; // 8x8 trellis is inherently optimal decimation for CABAC + + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + { + int quant_cat = p ? CQM_8PC : CQM_8PY; + CLEAR_16x16_NNZ( p ); + h->dctf.sub16x16_dct8( dct8x8, h->mb.pic.p_fenc[p], h->mb.pic.p_fdec[p] ); + h->nr_count[1+!!p*2] += h->mb.b_noise_reduction * 4; + + int plane_cbp = 0; + for( int idx = 0; idx < 4; idx++ ) + { + nz = x264_quant_8x8( h, dct8x8[idx], i_qp, ctx_cat_plane[DCT_LUMA_8x8][p], 0, p, idx ); + + if( nz ) + { + h->zigzagf.scan_8x8( h->dct.luma8x8[p*4+idx], dct8x8[idx] ); + if( b_decimate ) + { + int i_decimate_8x8 = h->quantf.decimate_score64( h->dct.luma8x8[p*4+idx] ); + i_decimate_mb += i_decimate_8x8; + if( i_decimate_8x8 >= 4 ) + plane_cbp |= 1<= 6 || !b_decimate ) + { + h->mb.i_cbp_luma |= plane_cbp; + FOREACH_BIT( idx, 0, plane_cbp ) + { + h->quantf.dequant_8x8( dct8x8[idx], h->dequant8_mf[quant_cat], i_qp ); + h->dctf.add8x8_idct8( &h->mb.pic.p_fdec[p][8*(idx&1) + 8*(idx>>1)*FDEC_STRIDE], dct8x8[idx] ); + STORE_8x8_NNZ( p, idx, 1 ); + } + } + } + } + else + { + ALIGNED_ARRAY_64( dctcoef, dct4x4,[16],[16] ); + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + { + int quant_cat = p ? CQM_4PC : CQM_4PY; + CLEAR_16x16_NNZ( p ); + h->dctf.sub16x16_dct( dct4x4, h->mb.pic.p_fenc[p], h->mb.pic.p_fdec[p] ); + + if( h->mb.b_noise_reduction ) + { + h->nr_count[0+!!p*2] += 16; + for( int idx = 0; idx < 16; idx++ ) + h->quantf.denoise_dct( dct4x4[idx], h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 ); + } + + int plane_cbp = 0; + for( int i8x8 = 0; i8x8 < 4; i8x8++ ) + { + int i_decimate_8x8 = b_decimate ? 0 : 6; + int nnz8x8 = 0; + if( h->mb.b_trellis ) + { + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + { + int idx = i8x8*4+i4x4; + if( x264_quant_4x4_trellis( h, dct4x4[idx], quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, !!p, p*16+idx ) ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4[idx] ); + h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[quant_cat], i_qp ); + if( i_decimate_8x8 < 6 ) + i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+idx] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = 1; + nnz8x8 = 1; + } + } + } + else + { + nnz8x8 = nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[quant_cat][i_qp], h->quant4_bias[quant_cat][i_qp] ); + if( nz ) + { + FOREACH_BIT( idx, i8x8*4, nz ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4[idx] ); + h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[quant_cat], i_qp ); + if( i_decimate_8x8 < 6 ) + i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+idx] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = 1; + } + } + } + if( nnz8x8 ) + { + i_decimate_mb += i_decimate_8x8; + if( i_decimate_8x8 < 4 ) + STORE_8x8_NNZ( p, i8x8, 0 ); + else + plane_cbp |= 1<mb.i_cbp_luma |= plane_cbp; + FOREACH_BIT( i8x8, 0, plane_cbp ) + { + h->dctf.add8x8_idct( &h->mb.pic.p_fdec[p][(i8x8&1)*8 + (i8x8>>1)*8*FDEC_STRIDE], &dct4x4[i8x8*4] ); + } + } + } + } + } + + /* encode chroma */ + if( chroma ) + { + if( IS_INTRA( h->mb.i_type ) ) + { + int i_mode = h->mb.i_chroma_pred_mode; + if( h->mb.b_lossless ) + x264_predict_lossless_chroma( h, i_mode ); + else + { + h->predict_chroma[i_mode]( h->mb.pic.p_fdec[1] ); + h->predict_chroma[i_mode]( h->mb.pic.p_fdec[2] ); + } + } + + /* encode the 8x8 blocks */ + x264_mb_encode_chroma( h, !IS_INTRA( h->mb.i_type ), h->mb.i_chroma_qp ); + } + else + h->mb.i_cbp_chroma = 0; + + /* store cbp */ + int cbp = h->mb.i_cbp_chroma << 4 | h->mb.i_cbp_luma; + if( h->param.b_cabac ) + cbp |= h->mb.cache.non_zero_count[x264_scan8[LUMA_DC ]] << 8 + | h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]] << 9 + | h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]] << 10; + h->mb.cbp[h->mb.i_mb_xy] = cbp; + + /* Check for P_SKIP + * XXX: in the me perhaps we should take x264_mb_predict_mv_pskip into account + * (if multiple mv give same result)*/ + if( !b_force_no_skip ) + { + if( h->mb.i_type == P_L0 && h->mb.i_partition == D_16x16 && + !(h->mb.i_cbp_luma | h->mb.i_cbp_chroma) && + M32( h->mb.cache.mv[0][x264_scan8[0]] ) == M32( h->mb.cache.pskip_mv ) + && h->mb.cache.ref[0][x264_scan8[0]] == 0 ) + { + h->mb.i_type = P_SKIP; + } + + /* Check for B_SKIP */ + if( h->mb.i_type == B_DIRECT && !(h->mb.i_cbp_luma | h->mb.i_cbp_chroma) ) + { + h->mb.i_type = B_SKIP; + } + } +} + +void x264_macroblock_encode( x264_t *h ) +{ + if( CHROMA444 ) + x264_macroblock_encode_internal( h, 3, 0 ); + else + x264_macroblock_encode_internal( h, 1, 1 ); +} + +/***************************************************************************** + * x264_macroblock_probe_skip: + * Check if the current MB could be encoded as a [PB]_SKIP + *****************************************************************************/ +static ALWAYS_INLINE int x264_macroblock_probe_skip_internal( x264_t *h, int b_bidir, int plane_count, int chroma ) +{ + ALIGNED_ARRAY_64( dctcoef, dct4x4,[8],[16] ); + ALIGNED_ARRAY_64( dctcoef, dctscan,[16] ); + ALIGNED_4( int16_t mvp[2] ); + int i_qp = h->mb.i_qp; + + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + { + int quant_cat = p ? CQM_4PC : CQM_4PY; + if( !b_bidir ) + { + /* Get the MV */ + mvp[0] = x264_clip3( h->mb.cache.pskip_mv[0], h->mb.mv_min[0], h->mb.mv_max[0] ); + mvp[1] = x264_clip3( h->mb.cache.pskip_mv[1], h->mb.mv_min[1], h->mb.mv_max[1] ); + + /* Motion compensation */ + h->mc.mc_luma( h->mb.pic.p_fdec[p], FDEC_STRIDE, + &h->mb.pic.p_fref[0][0][p*4], h->mb.pic.i_stride[p], + mvp[0], mvp[1], 16, 16, &h->sh.weight[0][p] ); + } + + for( int i8x8 = 0, i_decimate_mb = 0; i8x8 < 4; i8x8++ ) + { + int fenc_offset = (i8x8&1) * 8 + (i8x8>>1) * FENC_STRIDE * 8; + int fdec_offset = (i8x8&1) * 8 + (i8x8>>1) * FDEC_STRIDE * 8; + + h->dctf.sub8x8_dct( dct4x4, h->mb.pic.p_fenc[p] + fenc_offset, + h->mb.pic.p_fdec[p] + fdec_offset ); + + if( h->mb.b_noise_reduction ) + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + h->quantf.denoise_dct( dct4x4[i4x4], h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 ); + + int nz = h->quantf.quant_4x4x4( dct4x4, h->quant4_mf[quant_cat][i_qp], h->quant4_bias[quant_cat][i_qp] ); + FOREACH_BIT( idx, 0, nz ) + { + h->zigzagf.scan_4x4( dctscan, dct4x4[idx] ); + i_decimate_mb += h->quantf.decimate_score16( dctscan ); + if( i_decimate_mb >= 6 ) + return 0; + } + } + } + + if( chroma == CHROMA_420 || chroma == CHROMA_422 ) + { + i_qp = h->mb.i_chroma_qp; + int chroma422 = chroma == CHROMA_422; + int thresh = chroma422 ? (x264_lambda2_tab[i_qp] + 16) >> 5 : (x264_lambda2_tab[i_qp] + 32) >> 6; + int ssd; + ALIGNED_ARRAY_16( dctcoef, dct_dc,[8] ); + + if( !b_bidir ) + { + /* Special case for mv0, which is (of course) very common in P-skip mode. */ + if( M32( mvp ) ) + h->mc.mc_chroma( h->mb.pic.p_fdec[1], h->mb.pic.p_fdec[2], FDEC_STRIDE, + h->mb.pic.p_fref[0][0][4], h->mb.pic.i_stride[1], + mvp[0], mvp[1]<mc.load_deinterleave_chroma_fdec( h->mb.pic.p_fdec[1], h->mb.pic.p_fref[0][0][4], + h->mb.pic.i_stride[1], chroma422?16:8 ); + } + + for( int ch = 0; ch < 2; ch++ ) + { + pixel *p_src = h->mb.pic.p_fenc[1+ch]; + pixel *p_dst = h->mb.pic.p_fdec[1+ch]; + + if( !b_bidir && h->sh.weight[0][1+ch].weightfn ) + h->sh.weight[0][1+ch].weightfn[8>>2]( h->mb.pic.p_fdec[1+ch], FDEC_STRIDE, + h->mb.pic.p_fdec[1+ch], FDEC_STRIDE, + &h->sh.weight[0][1+ch], chroma422?16:8 ); + + /* there is almost never a termination during chroma, but we can't avoid the check entirely */ + /* so instead we check SSD and skip the actual check if the score is low enough. */ + ssd = h->pixf.ssd[chroma422?PIXEL_8x16:PIXEL_8x8]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ); + if( ssd < thresh ) + continue; + + /* The vast majority of chroma checks will terminate during the DC check or the higher + * threshold check, so we can save time by doing a DC-only DCT. */ + if( h->mb.b_noise_reduction ) + { + for( int i = 0; i <= chroma422; i++ ) + h->dctf.sub8x8_dct( &dct4x4[4*i], p_src + 8*i*FENC_STRIDE, p_dst + 8*i*FDEC_STRIDE ); + + for( int i4x4 = 0; i4x4 < (chroma422?8:4); i4x4++ ) + { + h->quantf.denoise_dct( dct4x4[i4x4], h->nr_residual_sum[2], h->nr_offset[2], 16 ); + dct_dc[i4x4] = dct4x4[i4x4][0]; + dct4x4[i4x4][0] = 0; + } + } + else + { + if( chroma422 ) + h->dctf.sub8x16_dct_dc( dct_dc, p_src, p_dst ); + else + h->dctf.sub8x8_dct_dc( dct_dc, p_src, p_dst ); + } + + for( int i = 0; i <= chroma422; i++ ) + if( h->quantf.quant_2x2_dc( &dct_dc[4*i], h->quant4_mf[CQM_4PC][i_qp+3*chroma422][0] >> 1, + h->quant4_bias[CQM_4PC][i_qp+3*chroma422][0] << 1 ) ) + return 0; + + /* If there wasn't a termination in DC, we can check against a much higher threshold. */ + if( ssd < thresh*4 ) + continue; + + if( !h->mb.b_noise_reduction ) + for( int i = 0; i <= chroma422; i++ ) + { + h->dctf.sub8x8_dct( &dct4x4[4*i], p_src + 8*i*FENC_STRIDE, p_dst + 8*i*FDEC_STRIDE ); + dct4x4[i*4+0][0] = 0; + dct4x4[i*4+1][0] = 0; + dct4x4[i*4+2][0] = 0; + dct4x4[i*4+3][0] = 0; + } + + /* calculate dct coeffs */ + for( int i8x8 = 0, i_decimate_mb = 0; i8x8 < (chroma422?2:1); i8x8++ ) + { + int nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[CQM_4PC][i_qp], h->quant4_bias[CQM_4PC][i_qp] ); + FOREACH_BIT( idx, i8x8*4, nz ) + { + h->zigzagf.scan_4x4( dctscan, dct4x4[idx] ); + i_decimate_mb += h->quantf.decimate_score15( dctscan ); + if( i_decimate_mb >= 7 ) + return 0; + } + } + } + } + + h->mb.b_skip_mc = 1; + return 1; +} + +int x264_macroblock_probe_skip( x264_t *h, int b_bidir ) +{ + if( CHROMA_FORMAT == CHROMA_444 ) + return x264_macroblock_probe_skip_internal( h, b_bidir, 3, CHROMA_444 ); + else if( CHROMA_FORMAT == CHROMA_422 ) + return x264_macroblock_probe_skip_internal( h, b_bidir, 1, CHROMA_422 ); + else + return x264_macroblock_probe_skip_internal( h, b_bidir, 1, CHROMA_420 ); +} + +/**************************************************************************** + * DCT-domain noise reduction / adaptive deadzone + * from libavcodec + ****************************************************************************/ + +void x264_noise_reduction_update( x264_t *h ) +{ + h->nr_offset = h->nr_offset_denoise; + h->nr_residual_sum = h->nr_residual_sum_buf[0]; + h->nr_count = h->nr_count_buf[0]; + for( int cat = 0; cat < 3 + CHROMA444; cat++ ) + { + int dct8x8 = cat&1; + int size = dct8x8 ? 64 : 16; + const uint32_t *weight = dct8x8 ? x264_dct8_weight2_tab : x264_dct4_weight2_tab; + + if( h->nr_count[cat] > (dct8x8 ? (1<<16) : (1<<18)) ) + { + for( int i = 0; i < size; i++ ) + h->nr_residual_sum[cat][i] >>= 1; + h->nr_count[cat] >>= 1; + } + + for( int i = 0; i < size; i++ ) + h->nr_offset[cat][i] = + ((uint64_t)h->param.analyse.i_noise_reduction * h->nr_count[cat] + + h->nr_residual_sum[cat][i]/2) + / ((uint64_t)h->nr_residual_sum[cat][i] * weight[i]/256 + 1); + + /* Don't denoise DC coefficients */ + h->nr_offset[cat][0] = 0; + } +} + +/***************************************************************************** + * RD only; 4 calls to this do not make up for one macroblock_encode. + * doesn't transform chroma dc. + *****************************************************************************/ +static ALWAYS_INLINE void x264_macroblock_encode_p8x8_internal( x264_t *h, int i8, int plane_count, int chroma ) +{ + int b_decimate = h->mb.b_dct_decimate; + int i_qp = h->mb.i_qp; + int x = i8&1; + int y = i8>>1; + int nz; + int chroma422 = chroma == CHROMA_422; + + h->mb.i_cbp_chroma = 0; + h->mb.i_cbp_luma &= ~(1 << i8); + + if( !h->mb.b_skip_mc ) + x264_mb_mc_8x8( h, i8 ); + + if( h->mb.b_lossless ) + { + for( int p = 0; p < plane_count; p++ ) + { + pixel *p_fenc = h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE; + pixel *p_fdec = h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE; + int nnz8x8 = 0; + if( h->mb.b_transform_8x8 ) + { + nnz8x8 = h->zigzagf.sub_8x8( h->dct.luma8x8[4*p+i8], p_fenc, p_fdec ); + STORE_8x8_NNZ( p, i8, nnz8x8 ); + } + else + { + for( int i4 = i8*4; i4 < i8*4+4; i4++ ) + { + nz = h->zigzagf.sub_4x4( h->dct.luma4x4[16*p+i4], + h->mb.pic.p_fenc[p]+block_idx_xy_fenc[i4], + h->mb.pic.p_fdec[p]+block_idx_xy_fdec[i4] ); + h->mb.cache.non_zero_count[x264_scan8[16*p+i4]] = nz; + nnz8x8 |= nz; + } + } + h->mb.i_cbp_luma |= nnz8x8 << i8; + } + if( chroma == CHROMA_420 || chroma == CHROMA_422 ) + { + for( int ch = 0; ch < 2; ch++ ) + { + dctcoef dc; + pixel *p_fenc = h->mb.pic.p_fenc[1+ch] + 4*x + (chroma422?8:4)*y*FENC_STRIDE; + pixel *p_fdec = h->mb.pic.p_fdec[1+ch] + 4*x + (chroma422?8:4)*y*FDEC_STRIDE; + + for( int i4x4 = 0; i4x4 <= chroma422; i4x4++ ) + { + int offset = chroma422 ? 8*y + 2*i4x4 + x : i8; + nz = h->zigzagf.sub_4x4ac( h->dct.luma4x4[16+offset+ch*16], p_fenc+4*i4x4*FENC_STRIDE, p_fdec+4*i4x4*FDEC_STRIDE, &dc ); + h->mb.cache.non_zero_count[x264_scan8[16+offset+ch*16]] = nz; + } + } + h->mb.i_cbp_chroma = 0x02; + } + } + else + { + if( h->mb.b_transform_8x8 ) + { + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + { + int quant_cat = p ? CQM_8PC : CQM_8PY; + pixel *p_fenc = h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE; + pixel *p_fdec = h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE; + ALIGNED_ARRAY_64( dctcoef, dct8x8,[64] ); + + h->dctf.sub8x8_dct8( dct8x8, p_fenc, p_fdec ); + int nnz8x8 = x264_quant_8x8( h, dct8x8, i_qp, ctx_cat_plane[DCT_LUMA_8x8][p], 0, p, i8 ); + if( nnz8x8 ) + { + h->zigzagf.scan_8x8( h->dct.luma8x8[4*p+i8], dct8x8 ); + + if( b_decimate && !h->mb.b_trellis ) + nnz8x8 = 4 <= h->quantf.decimate_score64( h->dct.luma8x8[4*p+i8] ); + + if( nnz8x8 ) + { + h->quantf.dequant_8x8( dct8x8, h->dequant8_mf[quant_cat], i_qp ); + h->dctf.add8x8_idct8( p_fdec, dct8x8 ); + STORE_8x8_NNZ( p, i8, 1 ); + h->mb.i_cbp_luma |= 1 << i8; + } + else + STORE_8x8_NNZ( p, i8, 0 ); + } + else + STORE_8x8_NNZ( p, i8, 0 ); + } + } + else + { + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + { + int quant_cat = p ? CQM_4PC : CQM_4PY; + pixel *p_fenc = h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE; + pixel *p_fdec = h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE; + int i_decimate_8x8 = b_decimate ? 0 : 4; + ALIGNED_ARRAY_64( dctcoef, dct4x4,[4],[16] ); + int nnz8x8 = 0; + + h->dctf.sub8x8_dct( dct4x4, p_fenc, p_fdec ); + STORE_8x8_NNZ( p, i8, 0 ); + + if( h->mb.b_noise_reduction ) + for( int idx = 0; idx < 4; idx++ ) + h->quantf.denoise_dct( dct4x4[idx], h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 ); + + if( h->mb.b_trellis ) + { + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + { + if( x264_quant_4x4_trellis( h, dct4x4[i4x4], quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, !!p, i8*4+i4x4+p*16 ) ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+i8*4+i4x4], dct4x4[i4x4] ); + h->quantf.dequant_4x4( dct4x4[i4x4], h->dequant4_mf[quant_cat], i_qp ); + if( i_decimate_8x8 < 4 ) + i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+i8*4+i4x4] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4+i4x4]] = 1; + nnz8x8 = 1; + } + } + } + else + { + nnz8x8 = nz = h->quantf.quant_4x4x4( dct4x4, h->quant4_mf[quant_cat][i_qp], h->quant4_bias[quant_cat][i_qp] ); + if( nz ) + { + FOREACH_BIT( i4x4, 0, nz ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+i8*4+i4x4], dct4x4[i4x4] ); + h->quantf.dequant_4x4( dct4x4[i4x4], h->dequant4_mf[quant_cat], i_qp ); + if( i_decimate_8x8 < 4 ) + i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+i8*4+i4x4] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4+i4x4]] = 1; + } + } + } + if( nnz8x8 ) + { + /* decimate this 8x8 block */ + if( i_decimate_8x8 < 4 ) + STORE_8x8_NNZ( p, i8, 0 ); + else + { + h->dctf.add8x8_idct( p_fdec, dct4x4 ); + h->mb.i_cbp_luma |= 1 << i8; + } + } + } + } + + if( chroma == CHROMA_420 || chroma == CHROMA_422 ) + { + i_qp = h->mb.i_chroma_qp; + for( int ch = 0; ch < 2; ch++ ) + { + ALIGNED_ARRAY_64( dctcoef, dct4x4,[2],[16] ); + pixel *p_fenc = h->mb.pic.p_fenc[1+ch] + 4*x + (chroma422?8:4)*y*FENC_STRIDE; + pixel *p_fdec = h->mb.pic.p_fdec[1+ch] + 4*x + (chroma422?8:4)*y*FDEC_STRIDE; + + for( int i4x4 = 0; i4x4 <= chroma422; i4x4++ ) + { + h->dctf.sub4x4_dct( dct4x4[i4x4], p_fenc + 4*i4x4*FENC_STRIDE, p_fdec + 4*i4x4*FDEC_STRIDE ); + + if( h->mb.b_noise_reduction ) + h->quantf.denoise_dct( dct4x4[i4x4], h->nr_residual_sum[2], h->nr_offset[2], 16 ); + dct4x4[i4x4][0] = 0; + + if( h->mb.b_trellis ) + nz = x264_quant_4x4_trellis( h, dct4x4[i4x4], CQM_4PC, i_qp, DCT_CHROMA_AC, 0, 1, 0 ); + else + nz = h->quantf.quant_4x4( dct4x4[i4x4], h->quant4_mf[CQM_4PC][i_qp], h->quant4_bias[CQM_4PC][i_qp] ); + + int offset = chroma422 ? ((5*i8) & 0x09) + 2*i4x4 : i8; + h->mb.cache.non_zero_count[x264_scan8[16+offset+ch*16]] = nz; + if( nz ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[16+offset+ch*16], dct4x4[i4x4] ); + h->quantf.dequant_4x4( dct4x4[i4x4], h->dequant4_mf[CQM_4PC], i_qp ); + h->dctf.add4x4_idct( p_fdec + 4*i4x4*FDEC_STRIDE, dct4x4[i4x4] ); + } + } + } + h->mb.i_cbp_chroma = 0x02; + } + } +} + +void x264_macroblock_encode_p8x8( x264_t *h, int i8 ) +{ + if( CHROMA444 ) + x264_macroblock_encode_p8x8_internal( h, i8, 3, CHROMA_444 ); + else if( CHROMA_FORMAT == CHROMA_422 ) + x264_macroblock_encode_p8x8_internal( h, i8, 1, CHROMA_422 ); + else + x264_macroblock_encode_p8x8_internal( h, i8, 1, CHROMA_420 ); +} + +/***************************************************************************** + * RD only, luma only (for 4:2:0) + *****************************************************************************/ +static ALWAYS_INLINE void x264_macroblock_encode_p4x4_internal( x264_t *h, int i4, int plane_count ) +{ + int i_qp = h->mb.i_qp; + + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) + { + int quant_cat = p ? CQM_4PC : CQM_4PY; + pixel *p_fenc = &h->mb.pic.p_fenc[p][block_idx_xy_fenc[i4]]; + pixel *p_fdec = &h->mb.pic.p_fdec[p][block_idx_xy_fdec[i4]]; + int nz; + + /* Don't need motion compensation as this function is only used in qpel-RD, which caches pixel data. */ + + if( h->mb.b_lossless ) + { + nz = h->zigzagf.sub_4x4( h->dct.luma4x4[p*16+i4], p_fenc, p_fdec ); + h->mb.cache.non_zero_count[x264_scan8[p*16+i4]] = nz; + } + else + { + ALIGNED_ARRAY_64( dctcoef, dct4x4,[16] ); + h->dctf.sub4x4_dct( dct4x4, p_fenc, p_fdec ); + nz = x264_quant_4x4( h, dct4x4, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, p, i4 ); + h->mb.cache.non_zero_count[x264_scan8[p*16+i4]] = nz; + if( nz ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+i4], dct4x4 ); + h->quantf.dequant_4x4( dct4x4, h->dequant4_mf[quant_cat], i_qp ); + h->dctf.add4x4_idct( p_fdec, dct4x4 ); + } + } + } +} + +void x264_macroblock_encode_p4x4( x264_t *h, int i8 ) +{ + if( CHROMA444 ) + x264_macroblock_encode_p4x4_internal( h, i8, 3 ); + else + x264_macroblock_encode_p4x4_internal( h, i8, 1 ); +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/macroblock.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/macroblock.h new file mode 100644 index 00000000..1c901a89 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/macroblock.h @@ -0,0 +1,198 @@ +/***************************************************************************** + * macroblock.h: macroblock encoding + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ENCODER_MACROBLOCK_H +#define X264_ENCODER_MACROBLOCK_H + +#include "common/macroblock.h" + +extern const int x264_lambda2_tab[QP_MAX_MAX+1]; +extern const uint16_t x264_lambda_tab[QP_MAX_MAX+1]; + +void x264_rdo_init( void ); + +int x264_macroblock_probe_skip( x264_t *h, int b_bidir ); + +#define x264_macroblock_probe_pskip( h )\ + x264_macroblock_probe_skip( h, 0 ) +#define x264_macroblock_probe_bskip( h )\ + x264_macroblock_probe_skip( h, 1 ) + +void x264_predict_lossless_4x4( x264_t *h, pixel *p_dst, int p, int idx, int i_mode ); +void x264_predict_lossless_8x8( x264_t *h, pixel *p_dst, int p, int idx, int i_mode, pixel edge[36] ); +void x264_predict_lossless_16x16( x264_t *h, int p, int i_mode ); +void x264_predict_lossless_chroma( x264_t *h, int i_mode ); + +void x264_macroblock_encode ( x264_t *h ); +void x264_macroblock_write_cabac ( x264_t *h, x264_cabac_t *cb ); +void x264_macroblock_write_cavlc ( x264_t *h ); + +void x264_macroblock_encode_p8x8( x264_t *h, int i8 ); +void x264_macroblock_encode_p4x4( x264_t *h, int i4 ); +void x264_mb_encode_chroma( x264_t *h, int b_inter, int i_qp ); + +void x264_cabac_mb_skip( x264_t *h, int b_skip ); +void x264_cabac_block_residual_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ); +void x264_cabac_block_residual_8x8_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ); +void x264_cabac_block_residual_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l ); + +int x264_quant_luma_dc_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, int i_qp, + int ctx_block_cat, int b_intra, int idx ); +int x264_quant_chroma_dc_trellis( x264_t *h, dctcoef *dct, int i_qp, int b_intra, int idx ); +int x264_quant_4x4_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, + int i_qp, int ctx_block_cat, int b_intra, int b_chroma, int idx ); +int x264_quant_8x8_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, + int i_qp, int ctx_block_cat, int b_intra, int b_chroma, int idx ); + +void x264_noise_reduction_update( x264_t *h ); + +static ALWAYS_INLINE int x264_quant_4x4( x264_t *h, dctcoef dct[16], int i_qp, int ctx_block_cat, int b_intra, int p, int idx ) +{ + int i_quant_cat = b_intra ? (p?CQM_4IC:CQM_4IY) : (p?CQM_4PC:CQM_4PY); + if( h->mb.b_noise_reduction ) + h->quantf.denoise_dct( dct, h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 ); + if( h->mb.b_trellis ) + return x264_quant_4x4_trellis( h, dct, i_quant_cat, i_qp, ctx_block_cat, b_intra, !!p, idx+p*16 ); + else + return h->quantf.quant_4x4( dct, h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias[i_quant_cat][i_qp] ); +} + +static ALWAYS_INLINE int x264_quant_8x8( x264_t *h, dctcoef dct[64], int i_qp, int ctx_block_cat, int b_intra, int p, int idx ) +{ + int i_quant_cat = b_intra ? (p?CQM_8IC:CQM_8IY) : (p?CQM_8PC:CQM_8PY); + if( h->mb.b_noise_reduction ) + h->quantf.denoise_dct( dct, h->nr_residual_sum[1+!!p*2], h->nr_offset[1+!!p*2], 64 ); + if( h->mb.b_trellis ) + return x264_quant_8x8_trellis( h, dct, i_quant_cat, i_qp, ctx_block_cat, b_intra, !!p, idx+p*4 ); + else + return h->quantf.quant_8x8( dct, h->quant8_mf[i_quant_cat][i_qp], h->quant8_bias[i_quant_cat][i_qp] ); +} + +#define STORE_8x8_NNZ( p, idx, nz )\ +do\ +{\ + M16( &h->mb.cache.non_zero_count[x264_scan8[p*16+idx*4]+0] ) = (nz) * 0x0101;\ + M16( &h->mb.cache.non_zero_count[x264_scan8[p*16+idx*4]+8] ) = (nz) * 0x0101;\ +} while( 0 ) + +#define CLEAR_16x16_NNZ( p ) \ +do\ +{\ + M32( &h->mb.cache.non_zero_count[x264_scan8[16*p] + 0*8] ) = 0;\ + M32( &h->mb.cache.non_zero_count[x264_scan8[16*p] + 1*8] ) = 0;\ + M32( &h->mb.cache.non_zero_count[x264_scan8[16*p] + 2*8] ) = 0;\ + M32( &h->mb.cache.non_zero_count[x264_scan8[16*p] + 3*8] ) = 0;\ +} while( 0 ) + +/* A special for loop that iterates branchlessly over each set + * bit in a 4-bit input. */ +#define FOREACH_BIT(idx,start,mask) for( int idx = start, msk = mask, skip; msk && (skip = x264_ctz_4bit(msk), idx += skip, msk >>= skip+1, 1); idx++ ) + +static ALWAYS_INLINE void x264_mb_encode_i4x4( x264_t *h, int p, int idx, int i_qp, int i_mode, int b_predict ) +{ + int nz; + pixel *p_src = &h->mb.pic.p_fenc[p][block_idx_xy_fenc[idx]]; + pixel *p_dst = &h->mb.pic.p_fdec[p][block_idx_xy_fdec[idx]]; + ALIGNED_ARRAY_64( dctcoef, dct4x4,[16] ); + + if( b_predict ) + { + if( h->mb.b_lossless ) + x264_predict_lossless_4x4( h, p_dst, p, idx, i_mode ); + else + h->predict_4x4[i_mode]( p_dst ); + } + + if( h->mb.b_lossless ) + { + nz = h->zigzagf.sub_4x4( h->dct.luma4x4[p*16+idx], p_src, p_dst ); + h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = nz; + h->mb.i_cbp_luma |= nz<<(idx>>2); + return; + } + + h->dctf.sub4x4_dct( dct4x4, p_src, p_dst ); + + nz = x264_quant_4x4( h, dct4x4, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 1, p, idx ); + h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = nz; + if( nz ) + { + h->mb.i_cbp_luma |= 1<<(idx>>2); + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4 ); + h->quantf.dequant_4x4( dct4x4, h->dequant4_mf[p?CQM_4IC:CQM_4IY], i_qp ); + h->dctf.add4x4_idct( p_dst, dct4x4 ); + } +} + +static ALWAYS_INLINE void x264_mb_encode_i8x8( x264_t *h, int p, int idx, int i_qp, int i_mode, pixel *edge, int b_predict ) +{ + int x = idx&1; + int y = idx>>1; + int nz; + pixel *p_src = &h->mb.pic.p_fenc[p][8*x + 8*y*FENC_STRIDE]; + pixel *p_dst = &h->mb.pic.p_fdec[p][8*x + 8*y*FDEC_STRIDE]; + ALIGNED_ARRAY_64( dctcoef, dct8x8,[64] ); + ALIGNED_ARRAY_32( pixel, edge_buf,[36] ); + + if( b_predict ) + { + if( !edge ) + { + h->predict_8x8_filter( p_dst, edge_buf, h->mb.i_neighbour8[idx], x264_pred_i4x4_neighbors[i_mode] ); + edge = edge_buf; + } + + if( h->mb.b_lossless ) + x264_predict_lossless_8x8( h, p_dst, p, idx, i_mode, edge ); + else + h->predict_8x8[i_mode]( p_dst, edge ); + } + + if( h->mb.b_lossless ) + { + nz = h->zigzagf.sub_8x8( h->dct.luma8x8[p*4+idx], p_src, p_dst ); + STORE_8x8_NNZ( p, idx, nz ); + h->mb.i_cbp_luma |= nz<dctf.sub8x8_dct8( dct8x8, p_src, p_dst ); + + nz = x264_quant_8x8( h, dct8x8, i_qp, ctx_cat_plane[DCT_LUMA_8x8][p], 1, p, idx ); + if( nz ) + { + h->mb.i_cbp_luma |= 1<zigzagf.scan_8x8( h->dct.luma8x8[p*4+idx], dct8x8 ); + h->quantf.dequant_8x8( dct8x8, h->dequant8_mf[p?CQM_8IC:CQM_8IY], i_qp ); + h->dctf.add8x8_idct8( p_dst, dct8x8 ); + STORE_8x8_NNZ( p, idx, 1 ); + } + else + STORE_8x8_NNZ( p, idx, 0 ); +} + +#endif + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/me.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/me.c new file mode 100644 index 00000000..094fc5da --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/me.c @@ -0,0 +1,1350 @@ +/***************************************************************************** + * me.c: motion estimation + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "macroblock.h" +#include "me.h" + +/* presets selected from good points on the speed-vs-quality curve of several test videos + * subpel_iters[i_subpel_refine] = { refine_hpel, refine_qpel, me_hpel, me_qpel } + * where me_* are the number of EPZS iterations run on all candidate block types, + * and refine_* are run only on the winner. + * the subme=8,9 values are much higher because any amount of satd search makes + * up its time by reducing the number of qpel-rd iterations. */ +static const uint8_t subpel_iterations[][4] = + {{0,0,0,0}, + {1,1,0,0}, + {0,1,1,0}, + {0,2,1,0}, + {0,2,1,1}, + {0,2,1,2}, + {0,0,2,2}, + {0,0,2,2}, + {0,0,4,10}, + {0,0,4,10}, + {0,0,4,10}, + {0,0,4,10}}; + +/* (x-1)%6 */ +static const uint8_t mod6m1[8] = {5,0,1,2,3,4,5,0}; +/* radius 2 hexagon. repeated entries are to avoid having to compute mod6 every time. */ +static const int8_t hex2[8][2] = {{-1,-2}, {-2,0}, {-1,2}, {1,2}, {2,0}, {1,-2}, {-1,-2}, {-2,0}}; +static const int8_t square1[9][2] = {{0,0}, {0,-1}, {0,1}, {-1,0}, {1,0}, {-1,-1}, {-1,1}, {1,-1}, {1,1}}; + +static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_iters, int *p_halfpel_thresh, int b_refine_qpel ); + +#define BITS_MVD( mx, my )\ + (p_cost_mvx[(mx)<<2] + p_cost_mvy[(my)<<2]) + +#define COST_MV( mx, my )\ +do\ +{\ + int cost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE,\ + &p_fref_w[(my)*stride+(mx)], stride )\ + + BITS_MVD(mx,my);\ + COPY3_IF_LT( bcost, cost, bmx, mx, bmy, my );\ +} while( 0 ) + +#define COST_MV_HPEL( mx, my, cost )\ +do\ +{\ + intptr_t stride2 = 16;\ + pixel *src = h->mc.get_ref( pix, &stride2, m->p_fref, stride, mx, my, bw, bh, &m->weight[0] );\ + cost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE, src, stride2 )\ + + p_cost_mvx[ mx ] + p_cost_mvy[ my ];\ +} while( 0 ) + +#define COST_MV_X3_DIR( m0x, m0y, m1x, m1y, m2x, m2y, costs )\ +{\ + pixel *pix_base = p_fref_w + bmx + bmy*stride;\ + h->pixf.fpelcmp_x3[i_pixel]( p_fenc,\ + pix_base + (m0x) + (m0y)*stride,\ + pix_base + (m1x) + (m1y)*stride,\ + pix_base + (m2x) + (m2y)*stride,\ + stride, costs );\ + (costs)[0] += BITS_MVD( bmx+(m0x), bmy+(m0y) );\ + (costs)[1] += BITS_MVD( bmx+(m1x), bmy+(m1y) );\ + (costs)[2] += BITS_MVD( bmx+(m2x), bmy+(m2y) );\ +} + +#define COST_MV_X4_DIR( m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, costs )\ +{\ + pixel *pix_base = p_fref_w + bmx + bmy*stride;\ + h->pixf.fpelcmp_x4[i_pixel]( p_fenc,\ + pix_base + (m0x) + (m0y)*stride,\ + pix_base + (m1x) + (m1y)*stride,\ + pix_base + (m2x) + (m2y)*stride,\ + pix_base + (m3x) + (m3y)*stride,\ + stride, costs );\ + (costs)[0] += BITS_MVD( bmx+(m0x), bmy+(m0y) );\ + (costs)[1] += BITS_MVD( bmx+(m1x), bmy+(m1y) );\ + (costs)[2] += BITS_MVD( bmx+(m2x), bmy+(m2y) );\ + (costs)[3] += BITS_MVD( bmx+(m3x), bmy+(m3y) );\ +} + +#define COST_MV_X4( m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y )\ +{\ + pixel *pix_base = p_fref_w + omx + omy*stride;\ + h->pixf.fpelcmp_x4[i_pixel]( p_fenc,\ + pix_base + (m0x) + (m0y)*stride,\ + pix_base + (m1x) + (m1y)*stride,\ + pix_base + (m2x) + (m2y)*stride,\ + pix_base + (m3x) + (m3y)*stride,\ + stride, costs );\ + costs[0] += BITS_MVD( omx+(m0x), omy+(m0y) );\ + costs[1] += BITS_MVD( omx+(m1x), omy+(m1y) );\ + costs[2] += BITS_MVD( omx+(m2x), omy+(m2y) );\ + costs[3] += BITS_MVD( omx+(m3x), omy+(m3y) );\ + COPY3_IF_LT( bcost, costs[0], bmx, omx+(m0x), bmy, omy+(m0y) );\ + COPY3_IF_LT( bcost, costs[1], bmx, omx+(m1x), bmy, omy+(m1y) );\ + COPY3_IF_LT( bcost, costs[2], bmx, omx+(m2x), bmy, omy+(m2y) );\ + COPY3_IF_LT( bcost, costs[3], bmx, omx+(m3x), bmy, omy+(m3y) );\ +} + +#define COST_MV_X3_ABS( m0x, m0y, m1x, m1y, m2x, m2y )\ +{\ + h->pixf.fpelcmp_x3[i_pixel]( p_fenc,\ + p_fref_w + (m0x) + (m0y)*stride,\ + p_fref_w + (m1x) + (m1y)*stride,\ + p_fref_w + (m2x) + (m2y)*stride,\ + stride, costs );\ + costs[0] += p_cost_mvx[(m0x)<<2]; /* no cost_mvy */\ + costs[1] += p_cost_mvx[(m1x)<<2];\ + costs[2] += p_cost_mvx[(m2x)<<2];\ + COPY3_IF_LT( bcost, costs[0], bmx, m0x, bmy, m0y );\ + COPY3_IF_LT( bcost, costs[1], bmx, m1x, bmy, m1y );\ + COPY3_IF_LT( bcost, costs[2], bmx, m2x, bmy, m2y );\ +} + +/* 1 */ +/* 101 */ +/* 1 */ +#define DIA1_ITER( mx, my )\ +{\ + omx = mx; omy = my;\ + COST_MV_X4( 0,-1, 0,1, -1,0, 1,0 );\ +} + +#define CROSS( start, x_max, y_max )\ +{\ + int i = start;\ + if( (x_max) <= X264_MIN(mv_x_max-omx, omx-mv_x_min) )\ + for( ; i < (x_max)-2; i+=4 )\ + COST_MV_X4( i,0, -i,0, i+2,0, -i-2,0 );\ + for( ; i < (x_max); i+=2 )\ + {\ + if( omx+i <= mv_x_max )\ + COST_MV( omx+i, omy );\ + if( omx-i >= mv_x_min )\ + COST_MV( omx-i, omy );\ + }\ + i = start;\ + if( (y_max) <= X264_MIN(mv_y_max-omy, omy-mv_y_min) )\ + for( ; i < (y_max)-2; i+=4 )\ + COST_MV_X4( 0,i, 0,-i, 0,i+2, 0,-i-2 );\ + for( ; i < (y_max); i+=2 )\ + {\ + if( omy+i <= mv_y_max )\ + COST_MV( omx, omy+i );\ + if( omy-i >= mv_y_min )\ + COST_MV( omx, omy-i );\ + }\ +} + +#define FPEL(mv) (((mv)+2)>>2) /* Convert subpel MV to fullpel with rounding... */ +#define SPEL(mv) ((mv)<<2) /* ... and the reverse. */ +#define SPELx2(mv) (SPEL(mv)&0xFFFCFFFC) /* for two packed MVs */ + +void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, int *p_halfpel_thresh ) +{ + const int bw = x264_pixel_size[m->i_pixel].w; + const int bh = x264_pixel_size[m->i_pixel].h; + const int i_pixel = m->i_pixel; + const int stride = m->i_stride[0]; + int i_me_range = h->param.analyse.i_me_range; + int bmx, bmy, bcost = COST_MAX; + int bpred_cost = COST_MAX; + int omx, omy, pmx, pmy; + pixel *p_fenc = m->p_fenc[0]; + pixel *p_fref_w = m->p_fref_w; + ALIGNED_ARRAY_32( pixel, pix,[16*16] ); + ALIGNED_ARRAY_8( int16_t, mvc_temp,[16],[2] ); + + ALIGNED_ARRAY_16( int, costs,[16] ); + + int mv_x_min = h->mb.mv_limit_fpel[0][0]; + int mv_y_min = h->mb.mv_limit_fpel[0][1]; + int mv_x_max = h->mb.mv_limit_fpel[1][0]; + int mv_y_max = h->mb.mv_limit_fpel[1][1]; +/* Special version of pack to allow shortcuts in CHECK_MVRANGE */ +#define pack16to32_mask2(mx,my) ((mx<<16)|(my&0x7FFF)) + uint32_t mv_min = pack16to32_mask2( -mv_x_min, -mv_y_min ); + uint32_t mv_max = pack16to32_mask2( mv_x_max, mv_y_max )|0x8000; + uint32_t pmv, bpred_mv = 0; + +#define CHECK_MVRANGE(mx,my) (!(((pack16to32_mask2(mx,my) + mv_min) | (mv_max - pack16to32_mask2(mx,my))) & 0x80004000)) + + const uint16_t *p_cost_mvx = m->p_cost_mv - m->mvp[0]; + const uint16_t *p_cost_mvy = m->p_cost_mv - m->mvp[1]; + + /* Try extra predictors if provided. If subme >= 3, check subpel predictors, + * otherwise round them to fullpel. */ + if( h->mb.i_subpel_refine >= 3 ) + { + /* Calculate and check the MVP first */ + int bpred_mx = x264_clip3( m->mvp[0], SPEL(mv_x_min), SPEL(mv_x_max) ); + int bpred_my = x264_clip3( m->mvp[1], SPEL(mv_y_min), SPEL(mv_y_max) ); + pmv = pack16to32_mask( bpred_mx, bpred_my ); + pmx = FPEL( bpred_mx ); + pmy = FPEL( bpred_my ); + + COST_MV_HPEL( bpred_mx, bpred_my, bpred_cost ); + int pmv_cost = bpred_cost; + + if( i_mvc > 0 ) + { + /* Clip MV candidates and eliminate those equal to zero and pmv. */ + int valid_mvcs = x264_predictor_clip( mvc_temp+2, mvc, i_mvc, h->mb.mv_limit_fpel, pmv ); + if( valid_mvcs > 0 ) + { + int i = 1, cost; + /* We stuff pmv here to branchlessly pick between pmv and the various + * MV candidates. [0] gets skipped in order to maintain alignment for + * x264_predictor_clip. */ + M32( mvc_temp[1] ) = pmv; + bpred_cost <<= 4; + do + { + int mx = mvc_temp[i+1][0]; + int my = mvc_temp[i+1][1]; + COST_MV_HPEL( mx, my, cost ); + COPY1_IF_LT( bpred_cost, (cost << 4) + i ); + } while( ++i <= valid_mvcs ); + bpred_mx = mvc_temp[(bpred_cost&15)+1][0]; + bpred_my = mvc_temp[(bpred_cost&15)+1][1]; + bpred_cost >>= 4; + } + } + + /* Round the best predictor back to fullpel and get the cost, since this is where + * we'll be starting the fullpel motion search. */ + bmx = FPEL( bpred_mx ); + bmy = FPEL( bpred_my ); + bpred_mv = pack16to32_mask(bpred_mx, bpred_my); + if( bpred_mv&0x00030003 ) /* Only test if the tested predictor is actually subpel... */ + COST_MV( bmx, bmy ); + else /* Otherwise just copy the cost (we already know it) */ + bcost = bpred_cost; + + /* Test the zero vector if it hasn't been tested yet. */ + if( pmv ) + { + if( bmx|bmy ) COST_MV( 0, 0 ); + } + /* If a subpel mv candidate was better than the zero vector, the previous + * fullpel check won't have gotten it even if the pmv was zero. So handle + * that possibility here. */ + else + { + COPY3_IF_LT( bcost, pmv_cost, bmx, 0, bmy, 0 ); + } + } + else + { + /* Calculate and check the fullpel MVP first */ + bmx = pmx = x264_clip3( FPEL(m->mvp[0]), mv_x_min, mv_x_max ); + bmy = pmy = x264_clip3( FPEL(m->mvp[1]), mv_y_min, mv_y_max ); + pmv = pack16to32_mask( bmx, bmy ); + + /* Because we are rounding the predicted motion vector to fullpel, there will be + * an extra MV cost in 15 out of 16 cases. However, when the predicted MV is + * chosen as the best predictor, it is often the case that the subpel search will + * result in a vector at or next to the predicted motion vector. Therefore, we omit + * the cost of the MV from the rounded MVP to avoid unfairly biasing against use of + * the predicted motion vector. + * + * Disclaimer: this is a post-hoc rationalization for why this hack works. */ + bcost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE, &p_fref_w[bmy*stride+bmx], stride ); + + if( i_mvc > 0 ) + { + /* Like in subme>=3, except we also round the candidates to fullpel. */ + int valid_mvcs = x264_predictor_roundclip( mvc_temp+2, mvc, i_mvc, h->mb.mv_limit_fpel, pmv ); + if( valid_mvcs > 0 ) + { + int i = 1, cost; + M32( mvc_temp[1] ) = pmv; + bcost <<= 4; + do + { + int mx = mvc_temp[i+1][0]; + int my = mvc_temp[i+1][1]; + cost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE, &p_fref_w[my*stride+mx], stride ) + BITS_MVD( mx, my ); + COPY1_IF_LT( bcost, (cost << 4) + i ); + } while( ++i <= valid_mvcs ); + bmx = mvc_temp[(bcost&15)+1][0]; + bmy = mvc_temp[(bcost&15)+1][1]; + bcost >>= 4; + } + } + + /* Same as above, except the condition is simpler. */ + if( pmv ) + COST_MV( 0, 0 ); + } + + switch( h->mb.i_me_method ) + { + case X264_ME_DIA: + { + /* diamond search, radius 1 */ + bcost <<= 4; + int i = i_me_range; + do + { + COST_MV_X4_DIR( 0,-1, 0,1, -1,0, 1,0, costs ); + COPY1_IF_LT( bcost, (costs[0]<<4)+1 ); + COPY1_IF_LT( bcost, (costs[1]<<4)+3 ); + COPY1_IF_LT( bcost, (costs[2]<<4)+4 ); + COPY1_IF_LT( bcost, (costs[3]<<4)+12 ); + if( !(bcost&15) ) + break; + bmx -= (bcost<<28)>>30; + bmy -= (bcost<<30)>>30; + bcost &= ~15; + } while( --i && CHECK_MVRANGE(bmx, bmy) ); + bcost >>= 4; + break; + } + + case X264_ME_HEX: + { + me_hex2: + /* hexagon search, radius 2 */ + #if 0 + for( int i = 0; i < i_me_range/2; i++ ) + { + omx = bmx; omy = bmy; + COST_MV( omx-2, omy ); + COST_MV( omx-1, omy+2 ); + COST_MV( omx+1, omy+2 ); + COST_MV( omx+2, omy ); + COST_MV( omx+1, omy-2 ); + COST_MV( omx-1, omy-2 ); + if( bmx == omx && bmy == omy ) + break; + if( !CHECK_MVRANGE(bmx, bmy) ) + break; + } + #else + /* equivalent to the above, but eliminates duplicate candidates */ + + /* hexagon */ + COST_MV_X3_DIR( -2,0, -1, 2, 1, 2, costs ); + COST_MV_X3_DIR( 2,0, 1,-2, -1,-2, costs+4 ); /* +4 for 16-byte alignment */ + bcost <<= 3; + COPY1_IF_LT( bcost, (costs[0]<<3)+2 ); + COPY1_IF_LT( bcost, (costs[1]<<3)+3 ); + COPY1_IF_LT( bcost, (costs[2]<<3)+4 ); + COPY1_IF_LT( bcost, (costs[4]<<3)+5 ); + COPY1_IF_LT( bcost, (costs[5]<<3)+6 ); + COPY1_IF_LT( bcost, (costs[6]<<3)+7 ); + + if( bcost&7 ) + { + int dir = (bcost&7)-2; + bmx += hex2[dir+1][0]; + bmy += hex2[dir+1][1]; + + /* half hexagon, not overlapping the previous iteration */ + for( int i = (i_me_range>>1) - 1; i > 0 && CHECK_MVRANGE(bmx, bmy); i-- ) + { + COST_MV_X3_DIR( hex2[dir+0][0], hex2[dir+0][1], + hex2[dir+1][0], hex2[dir+1][1], + hex2[dir+2][0], hex2[dir+2][1], + costs ); + bcost &= ~7; + COPY1_IF_LT( bcost, (costs[0]<<3)+1 ); + COPY1_IF_LT( bcost, (costs[1]<<3)+2 ); + COPY1_IF_LT( bcost, (costs[2]<<3)+3 ); + if( !(bcost&7) ) + break; + dir += (bcost&7)-2; + dir = mod6m1[dir+1]; + bmx += hex2[dir+1][0]; + bmy += hex2[dir+1][1]; + } + } + bcost >>= 3; + #endif + /* square refine */ + bcost <<= 4; + COST_MV_X4_DIR( 0,-1, 0,1, -1,0, 1,0, costs ); + COPY1_IF_LT( bcost, (costs[0]<<4)+1 ); + COPY1_IF_LT( bcost, (costs[1]<<4)+2 ); + COPY1_IF_LT( bcost, (costs[2]<<4)+3 ); + COPY1_IF_LT( bcost, (costs[3]<<4)+4 ); + COST_MV_X4_DIR( -1,-1, -1,1, 1,-1, 1,1, costs ); + COPY1_IF_LT( bcost, (costs[0]<<4)+5 ); + COPY1_IF_LT( bcost, (costs[1]<<4)+6 ); + COPY1_IF_LT( bcost, (costs[2]<<4)+7 ); + COPY1_IF_LT( bcost, (costs[3]<<4)+8 ); + bmx += square1[bcost&15][0]; + bmy += square1[bcost&15][1]; + bcost >>= 4; + break; + } + + case X264_ME_UMH: + { + /* Uneven-cross Multi-Hexagon-grid Search + * as in JM, except with different early termination */ + + static const uint8_t x264_pixel_size_shift[7] = { 0, 1, 1, 2, 3, 3, 4 }; + + int ucost1, ucost2; + int cross_start = 1; + + /* refine predictors */ + ucost1 = bcost; + DIA1_ITER( pmx, pmy ); + if( pmx | pmy ) + DIA1_ITER( 0, 0 ); + + if( i_pixel == PIXEL_4x4 ) + goto me_hex2; + + ucost2 = bcost; + if( (bmx | bmy) && ((bmx-pmx) | (bmy-pmy)) ) + DIA1_ITER( bmx, bmy ); + if( bcost == ucost2 ) + cross_start = 3; + omx = bmx; omy = bmy; + + /* early termination */ +#define SAD_THRESH(v) ( bcost < ( v >> x264_pixel_size_shift[i_pixel] ) ) + if( bcost == ucost2 && SAD_THRESH(2000) ) + { + COST_MV_X4( 0,-2, -1,-1, 1,-1, -2,0 ); + COST_MV_X4( 2, 0, -1, 1, 1, 1, 0,2 ); + if( bcost == ucost1 && SAD_THRESH(500) ) + break; + if( bcost == ucost2 ) + { + int range = (i_me_range>>1) | 1; + CROSS( 3, range, range ); + COST_MV_X4( -1,-2, 1,-2, -2,-1, 2,-1 ); + COST_MV_X4( -2, 1, 2, 1, -1, 2, 1, 2 ); + if( bcost == ucost2 ) + break; + cross_start = range + 2; + } + } + + /* adaptive search range */ + if( i_mvc ) + { + /* range multipliers based on casual inspection of some statistics of + * average distance between current predictor and final mv found by ESA. + * these have not been tuned much by actual encoding. */ + static const uint8_t range_mul[4][4] = + { + { 3, 3, 4, 4 }, + { 3, 4, 4, 4 }, + { 4, 4, 4, 5 }, + { 4, 4, 5, 6 }, + }; + int mvd; + int sad_ctx, mvd_ctx; + int denom = 1; + + if( i_mvc == 1 ) + { + if( i_pixel == PIXEL_16x16 ) + /* mvc is probably the same as mvp, so the difference isn't meaningful. + * but prediction usually isn't too bad, so just use medium range */ + mvd = 25; + else + mvd = abs( m->mvp[0] - mvc[0][0] ) + + abs( m->mvp[1] - mvc[0][1] ); + } + else + { + /* calculate the degree of agreement between predictors. */ + /* in 16x16, mvc includes all the neighbors used to make mvp, + * so don't count mvp separately. */ + denom = i_mvc - 1; + mvd = 0; + if( i_pixel != PIXEL_16x16 ) + { + mvd = abs( m->mvp[0] - mvc[0][0] ) + + abs( m->mvp[1] - mvc[0][1] ); + denom++; + } + mvd += x264_predictor_difference( mvc, i_mvc ); + } + + sad_ctx = SAD_THRESH(1000) ? 0 + : SAD_THRESH(2000) ? 1 + : SAD_THRESH(4000) ? 2 : 3; + mvd_ctx = mvd < 10*denom ? 0 + : mvd < 20*denom ? 1 + : mvd < 40*denom ? 2 : 3; + + i_me_range = i_me_range * range_mul[mvd_ctx][sad_ctx] >> 2; + } + + /* FIXME if the above DIA2/OCT2/CROSS found a new mv, it has not updated omx/omy. + * we are still centered on the same place as the DIA2. is this desirable? */ + CROSS( cross_start, i_me_range, i_me_range>>1 ); + + COST_MV_X4( -2,-2, -2,2, 2,-2, 2,2 ); + + /* hexagon grid */ + omx = bmx; omy = bmy; + const uint16_t *p_cost_omvx = p_cost_mvx + omx*4; + const uint16_t *p_cost_omvy = p_cost_mvy + omy*4; + int i = 1; + do + { + static const int8_t hex4[16][2] = { + { 0,-4}, { 0, 4}, {-2,-3}, { 2,-3}, + {-4,-2}, { 4,-2}, {-4,-1}, { 4,-1}, + {-4, 0}, { 4, 0}, {-4, 1}, { 4, 1}, + {-4, 2}, { 4, 2}, {-2, 3}, { 2, 3}, + }; + + if( 4*i > X264_MIN4( mv_x_max-omx, omx-mv_x_min, + mv_y_max-omy, omy-mv_y_min ) ) + { + for( int j = 0; j < 16; j++ ) + { + int mx = omx + hex4[j][0]*i; + int my = omy + hex4[j][1]*i; + if( CHECK_MVRANGE(mx, my) ) + COST_MV( mx, my ); + } + } + else + { + int dir = 0; + pixel *pix_base = p_fref_w + omx + (omy-4*i)*stride; + int dy = i*stride; +#define SADS(k,x0,y0,x1,y1,x2,y2,x3,y3)\ + h->pixf.fpelcmp_x4[i_pixel]( p_fenc,\ + pix_base x0*i+(y0-2*k+4)*dy,\ + pix_base x1*i+(y1-2*k+4)*dy,\ + pix_base x2*i+(y2-2*k+4)*dy,\ + pix_base x3*i+(y3-2*k+4)*dy,\ + stride, costs+4*k );\ + pix_base += 2*dy; +#define ADD_MVCOST(k,x,y) costs[k] += p_cost_omvx[x*4*i] + p_cost_omvy[y*4*i] +#define MIN_MV(k,x,y) COPY2_IF_LT( bcost, costs[k], dir, x*16+(y&15) ) + SADS( 0, +0,-4, +0,+4, -2,-3, +2,-3 ); + SADS( 1, -4,-2, +4,-2, -4,-1, +4,-1 ); + SADS( 2, -4,+0, +4,+0, -4,+1, +4,+1 ); + SADS( 3, -4,+2, +4,+2, -2,+3, +2,+3 ); + ADD_MVCOST( 0, 0,-4 ); + ADD_MVCOST( 1, 0, 4 ); + ADD_MVCOST( 2,-2,-3 ); + ADD_MVCOST( 3, 2,-3 ); + ADD_MVCOST( 4,-4,-2 ); + ADD_MVCOST( 5, 4,-2 ); + ADD_MVCOST( 6,-4,-1 ); + ADD_MVCOST( 7, 4,-1 ); + ADD_MVCOST( 8,-4, 0 ); + ADD_MVCOST( 9, 4, 0 ); + ADD_MVCOST( 10,-4, 1 ); + ADD_MVCOST( 11, 4, 1 ); + ADD_MVCOST( 12,-4, 2 ); + ADD_MVCOST( 13, 4, 2 ); + ADD_MVCOST( 14,-2, 3 ); + ADD_MVCOST( 15, 2, 3 ); + MIN_MV( 0, 0,-4 ); + MIN_MV( 1, 0, 4 ); + MIN_MV( 2,-2,-3 ); + MIN_MV( 3, 2,-3 ); + MIN_MV( 4,-4,-2 ); + MIN_MV( 5, 4,-2 ); + MIN_MV( 6,-4,-1 ); + MIN_MV( 7, 4,-1 ); + MIN_MV( 8,-4, 0 ); + MIN_MV( 9, 4, 0 ); + MIN_MV( 10,-4, 1 ); + MIN_MV( 11, 4, 1 ); + MIN_MV( 12,-4, 2 ); + MIN_MV( 13, 4, 2 ); + MIN_MV( 14,-2, 3 ); + MIN_MV( 15, 2, 3 ); +#undef SADS +#undef ADD_MVCOST +#undef MIN_MV + if( dir ) + { + bmx = omx + i*(dir>>4); + bmy = omy + i*((dir<<28)>>28); + } + } + } while( ++i <= i_me_range>>2 ); + if( bmy <= mv_y_max && bmy >= mv_y_min && bmx <= mv_x_max && bmx >= mv_x_min ) + goto me_hex2; + break; + } + + case X264_ME_ESA: + case X264_ME_TESA: + { + const int min_x = X264_MAX( bmx - i_me_range, mv_x_min ); + const int min_y = X264_MAX( bmy - i_me_range, mv_y_min ); + const int max_x = X264_MIN( bmx + i_me_range, mv_x_max ); + const int max_y = X264_MIN( bmy + i_me_range, mv_y_max ); + /* SEA is fastest in multiples of 4 */ + const int width = (max_x - min_x + 3) & ~3; +#if 0 + /* plain old exhaustive search */ + for( int my = min_y; my <= max_y; my++ ) + for( int mx = min_x; mx < min_x + width; mx++ ) + COST_MV( mx, my ); +#else + /* successive elimination by comparing DC before a full SAD, + * because sum(abs(diff)) >= abs(diff(sum)). */ + uint16_t *sums_base = m->integral; + ALIGNED_16( static pixel zero[8*FENC_STRIDE] ) = {0}; + ALIGNED_ARRAY_16( int, enc_dc,[4] ); + int sad_size = i_pixel <= PIXEL_8x8 ? PIXEL_8x8 : PIXEL_4x4; + int delta = x264_pixel_size[sad_size].w; + int16_t *xs = h->scratch_buffer; + int xn; + uint16_t *cost_fpel_mvx = h->cost_mv_fpel[h->mb.i_qp][-m->mvp[0]&3] + (-m->mvp[0]>>2); + + h->pixf.sad_x4[sad_size]( zero, p_fenc, p_fenc+delta, + p_fenc+delta*FENC_STRIDE, p_fenc+delta+delta*FENC_STRIDE, + FENC_STRIDE, enc_dc ); + if( delta == 4 ) + sums_base += stride * (h->fenc->i_lines[0] + PADV*2); + if( i_pixel == PIXEL_16x16 || i_pixel == PIXEL_8x16 || i_pixel == PIXEL_4x8 ) + delta *= stride; + if( i_pixel == PIXEL_8x16 || i_pixel == PIXEL_4x8 ) + enc_dc[1] = enc_dc[2]; + + if( h->mb.i_me_method == X264_ME_TESA ) + { + // ADS threshold, then SAD threshold, then keep the best few SADs, then SATD + mvsad_t *mvsads = (mvsad_t *)(xs + ((width+31)&~31) + 4); + int nmvsad = 0, limit; + int sad_thresh = i_me_range <= 16 ? 10 : i_me_range <= 24 ? 11 : 12; + int bsad = h->pixf.sad[i_pixel]( p_fenc, FENC_STRIDE, p_fref_w+bmy*stride+bmx, stride ) + + BITS_MVD( bmx, bmy ); + for( int my = min_y; my <= max_y; my++ ) + { + int i; + int ycost = p_cost_mvy[my<<2]; + if( bsad <= ycost ) + continue; + bsad -= ycost; + xn = h->pixf.ads[i_pixel]( enc_dc, sums_base + min_x + my * stride, delta, + cost_fpel_mvx+min_x, xs, width, bsad * 17 >> 4 ); + for( i = 0; i < xn-2; i += 3 ) + { + pixel *ref = p_fref_w+min_x+my*stride; + ALIGNED_ARRAY_16( int, sads,[4] ); /* padded to [4] for asm */ + h->pixf.sad_x3[i_pixel]( p_fenc, ref+xs[i], ref+xs[i+1], ref+xs[i+2], stride, sads ); + for( int j = 0; j < 3; j++ ) + { + int sad = sads[j] + cost_fpel_mvx[xs[i+j]]; + if( sad < bsad*sad_thresh>>3 ) + { + COPY1_IF_LT( bsad, sad ); + mvsads[nmvsad].sad = sad + ycost; + mvsads[nmvsad].mv[0] = min_x+xs[i+j]; + mvsads[nmvsad].mv[1] = my; + nmvsad++; + } + } + } + for( ; i < xn; i++ ) + { + int mx = min_x+xs[i]; + int sad = h->pixf.sad[i_pixel]( p_fenc, FENC_STRIDE, p_fref_w+mx+my*stride, stride ) + + cost_fpel_mvx[xs[i]]; + if( sad < bsad*sad_thresh>>3 ) + { + COPY1_IF_LT( bsad, sad ); + mvsads[nmvsad].sad = sad + ycost; + mvsads[nmvsad].mv[0] = mx; + mvsads[nmvsad].mv[1] = my; + nmvsad++; + } + } + bsad += ycost; + } + + limit = i_me_range >> 1; + sad_thresh = bsad*sad_thresh>>3; + while( nmvsad > limit*2 && sad_thresh > bsad ) + { + int i = 0; + // halve the range if the domain is too large... eh, close enough + sad_thresh = (sad_thresh + bsad) >> 1; + while( i < nmvsad && mvsads[i].sad <= sad_thresh ) + i++; + for( int j = i; j < nmvsad; j++ ) + { + uint32_t sad; + if( WORD_SIZE == 8 && sizeof(mvsad_t) == 8 ) + { + uint64_t mvsad = M64( &mvsads[i] ) = M64( &mvsads[j] ); +#if WORDS_BIGENDIAN + mvsad >>= 32; +#endif + sad = mvsad; + } + else + { + sad = mvsads[j].sad; + CP32( mvsads[i].mv, mvsads[j].mv ); + mvsads[i].sad = sad; + } + i += (sad - (sad_thresh+1)) >> 31; + } + nmvsad = i; + } + while( nmvsad > limit ) + { + int bi = 0; + for( int i = 1; i < nmvsad; i++ ) + if( mvsads[i].sad > mvsads[bi].sad ) + bi = i; + nmvsad--; + if( sizeof( mvsad_t ) == sizeof( uint64_t ) ) + CP64( &mvsads[bi], &mvsads[nmvsad] ); + else + mvsads[bi] = mvsads[nmvsad]; + } + for( int i = 0; i < nmvsad; i++ ) + COST_MV( mvsads[i].mv[0], mvsads[i].mv[1] ); + } + else + { + // just ADS and SAD + for( int my = min_y; my <= max_y; my++ ) + { + int i; + int ycost = p_cost_mvy[my<<2]; + if( bcost <= ycost ) + continue; + bcost -= ycost; + xn = h->pixf.ads[i_pixel]( enc_dc, sums_base + min_x + my * stride, delta, + cost_fpel_mvx+min_x, xs, width, bcost ); + for( i = 0; i < xn-2; i += 3 ) + COST_MV_X3_ABS( min_x+xs[i],my, min_x+xs[i+1],my, min_x+xs[i+2],my ); + bcost += ycost; + for( ; i < xn; i++ ) + COST_MV( min_x+xs[i], my ); + } + } +#endif + } + break; + } + + /* -> qpel mv */ + uint32_t bmv = pack16to32_mask(bmx,bmy); + uint32_t bmv_spel = SPELx2(bmv); + if( h->mb.i_subpel_refine < 3 ) + { + m->cost_mv = p_cost_mvx[bmx<<2] + p_cost_mvy[bmy<<2]; + m->cost = bcost; + /* compute the real cost */ + if( bmv == pmv ) m->cost += m->cost_mv; + M32( m->mv ) = bmv_spel; + } + else + { + M32(m->mv) = bpred_cost < bcost ? bpred_mv : bmv_spel; + m->cost = X264_MIN( bpred_cost, bcost ); + } + + /* subpel refine */ + if( h->mb.i_subpel_refine >= 2 ) + { + int hpel = subpel_iterations[h->mb.i_subpel_refine][2]; + int qpel = subpel_iterations[h->mb.i_subpel_refine][3]; + refine_subpel( h, m, hpel, qpel, p_halfpel_thresh, 0 ); + } +} +#undef COST_MV + +void x264_me_refine_qpel( x264_t *h, x264_me_t *m ) +{ + int hpel = subpel_iterations[h->mb.i_subpel_refine][0]; + int qpel = subpel_iterations[h->mb.i_subpel_refine][1]; + + if( m->i_pixel <= PIXEL_8x8 ) + m->cost -= m->i_ref_cost; + + refine_subpel( h, m, hpel, qpel, NULL, 1 ); +} + +void x264_me_refine_qpel_refdupe( x264_t *h, x264_me_t *m, int *p_halfpel_thresh ) +{ + refine_subpel( h, m, 0, X264_MIN( 2, subpel_iterations[h->mb.i_subpel_refine][3] ), p_halfpel_thresh, 0 ); +} + +#define COST_MV_SAD( mx, my ) \ +{ \ + intptr_t stride = 16; \ + pixel *src = h->mc.get_ref( pix, &stride, m->p_fref, m->i_stride[0], mx, my, bw, bh, &m->weight[0] ); \ + int cost = h->pixf.fpelcmp[i_pixel]( m->p_fenc[0], FENC_STRIDE, src, stride ) \ + + p_cost_mvx[ mx ] + p_cost_mvy[ my ]; \ + COPY3_IF_LT( bcost, cost, bmx, mx, bmy, my ); \ +} + +#define COST_MV_SATD( mx, my, dir ) \ +if( b_refine_qpel || (dir^1) != odir ) \ +{ \ + intptr_t stride = 16; \ + pixel *src = h->mc.get_ref( pix, &stride, &m->p_fref[0], m->i_stride[0], mx, my, bw, bh, &m->weight[0] ); \ + int cost = h->pixf.mbcmp_unaligned[i_pixel]( m->p_fenc[0], FENC_STRIDE, src, stride ) \ + + p_cost_mvx[ mx ] + p_cost_mvy[ my ]; \ + if( b_chroma_me && cost < bcost ) \ + { \ + if( CHROMA444 ) \ + { \ + stride = 16; \ + src = h->mc.get_ref( pix, &stride, &m->p_fref[4], m->i_stride[1], mx, my, bw, bh, &m->weight[1] ); \ + cost += h->pixf.mbcmp_unaligned[i_pixel]( m->p_fenc[1], FENC_STRIDE, src, stride ); \ + if( cost < bcost ) \ + { \ + stride = 16; \ + src = h->mc.get_ref( pix, &stride, &m->p_fref[8], m->i_stride[2], mx, my, bw, bh, &m->weight[2] ); \ + cost += h->pixf.mbcmp_unaligned[i_pixel]( m->p_fenc[2], FENC_STRIDE, src, stride ); \ + } \ + } \ + else \ + { \ + h->mc.mc_chroma( pix, pix+8, 16, m->p_fref[4], m->i_stride[1], \ + mx, 2*(my+mvy_offset)>>chroma_v_shift, bw>>1, bh>>chroma_v_shift ); \ + if( m->weight[1].weightfn ) \ + m->weight[1].weightfn[bw>>3]( pix, 16, pix, 16, &m->weight[1], bh>>chroma_v_shift ); \ + cost += h->pixf.mbcmp[chromapix]( m->p_fenc[1], FENC_STRIDE, pix, 16 ); \ + if( cost < bcost ) \ + { \ + if( m->weight[2].weightfn ) \ + m->weight[2].weightfn[bw>>3]( pix+8, 16, pix+8, 16, &m->weight[2], bh>>chroma_v_shift ); \ + cost += h->pixf.mbcmp[chromapix]( m->p_fenc[2], FENC_STRIDE, pix+8, 16 ); \ + } \ + } \ + } \ + COPY4_IF_LT( bcost, cost, bmx, mx, bmy, my, bdir, dir ); \ +} + +static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_iters, int *p_halfpel_thresh, int b_refine_qpel ) +{ + const int bw = x264_pixel_size[m->i_pixel].w; + const int bh = x264_pixel_size[m->i_pixel].h; + const uint16_t *p_cost_mvx = m->p_cost_mv - m->mvp[0]; + const uint16_t *p_cost_mvy = m->p_cost_mv - m->mvp[1]; + const int i_pixel = m->i_pixel; + const int b_chroma_me = h->mb.b_chroma_me && (i_pixel <= PIXEL_8x8 || CHROMA444); + int chromapix = h->luma2chroma_pixel[i_pixel]; + int chroma_v_shift = CHROMA_V_SHIFT; + int mvy_offset = chroma_v_shift & MB_INTERLACED & m->i_ref ? (h->mb.i_mb_y & 1)*4 - 2 : 0; + + ALIGNED_ARRAY_32( pixel, pix,[64*18] ); // really 17x17x2, but round up for alignment + ALIGNED_ARRAY_16( int, costs,[4] ); + + int bmx = m->mv[0]; + int bmy = m->mv[1]; + int bcost = m->cost; + int odir = -1, bdir; + + /* halfpel diamond search */ + if( hpel_iters ) + { + /* try the subpel component of the predicted mv */ + if( h->mb.i_subpel_refine < 3 ) + { + int mx = x264_clip3( m->mvp[0], h->mb.mv_min_spel[0]+2, h->mb.mv_max_spel[0]-2 ); + int my = x264_clip3( m->mvp[1], h->mb.mv_min_spel[1]+2, h->mb.mv_max_spel[1]-2 ); + if( (mx-bmx)|(my-bmy) ) + COST_MV_SAD( mx, my ); + } + + bcost <<= 6; + for( int i = hpel_iters; i > 0; i-- ) + { + int omx = bmx, omy = bmy; + intptr_t stride = 64; // candidates are either all hpel or all qpel, so one stride is enough + pixel *src0, *src1, *src2, *src3; + src0 = h->mc.get_ref( pix, &stride, m->p_fref, m->i_stride[0], omx, omy-2, bw, bh+1, &m->weight[0] ); + src2 = h->mc.get_ref( pix+32, &stride, m->p_fref, m->i_stride[0], omx-2, omy, bw+4, bh, &m->weight[0] ); + src1 = src0 + stride; + src3 = src2 + 1; + h->pixf.fpelcmp_x4[i_pixel]( m->p_fenc[0], src0, src1, src2, src3, stride, costs ); + costs[0] += p_cost_mvx[omx ] + p_cost_mvy[omy-2]; + costs[1] += p_cost_mvx[omx ] + p_cost_mvy[omy+2]; + costs[2] += p_cost_mvx[omx-2] + p_cost_mvy[omy ]; + costs[3] += p_cost_mvx[omx+2] + p_cost_mvy[omy ]; + COPY1_IF_LT( bcost, (costs[0]<<6)+2 ); + COPY1_IF_LT( bcost, (costs[1]<<6)+6 ); + COPY1_IF_LT( bcost, (costs[2]<<6)+16 ); + COPY1_IF_LT( bcost, (costs[3]<<6)+48 ); + if( !(bcost&63) ) + break; + bmx -= (bcost<<26)>>29; + bmy -= (bcost<<29)>>29; + bcost &= ~63; + } + bcost >>= 6; + } + + if( !b_refine_qpel && (h->pixf.mbcmp_unaligned[0] != h->pixf.fpelcmp[0] || b_chroma_me) ) + { + bcost = COST_MAX; + COST_MV_SATD( bmx, bmy, -1 ); + } + + /* early termination when examining multiple reference frames */ + if( p_halfpel_thresh ) + { + if( (bcost*7)>>3 > *p_halfpel_thresh ) + { + m->cost = bcost; + m->mv[0] = bmx; + m->mv[1] = bmy; + // don't need cost_mv + return; + } + else if( bcost < *p_halfpel_thresh ) + *p_halfpel_thresh = bcost; + } + + /* quarterpel diamond search */ + if( h->mb.i_subpel_refine != 1 ) + { + bdir = -1; + for( int i = qpel_iters; i > 0; i-- ) + { + if( bmy <= h->mb.mv_min_spel[1] || bmy >= h->mb.mv_max_spel[1] || bmx <= h->mb.mv_min_spel[0] || bmx >= h->mb.mv_max_spel[0] ) + break; + odir = bdir; + int omx = bmx, omy = bmy; + COST_MV_SATD( omx, omy - 1, 0 ); + COST_MV_SATD( omx, omy + 1, 1 ); + COST_MV_SATD( omx - 1, omy, 2 ); + COST_MV_SATD( omx + 1, omy, 3 ); + if( (bmx == omx) & (bmy == omy) ) + break; + } + } + /* Special simplified case for subme=1 */ + else if( bmy > h->mb.mv_min_spel[1] && bmy < h->mb.mv_max_spel[1] && bmx > h->mb.mv_min_spel[0] && bmx < h->mb.mv_max_spel[0] ) + { + int omx = bmx, omy = bmy; + /* We have to use mc_luma because all strides must be the same to use fpelcmp_x4 */ + h->mc.mc_luma( pix , 64, m->p_fref, m->i_stride[0], omx, omy-1, bw, bh, &m->weight[0] ); + h->mc.mc_luma( pix+16, 64, m->p_fref, m->i_stride[0], omx, omy+1, bw, bh, &m->weight[0] ); + h->mc.mc_luma( pix+32, 64, m->p_fref, m->i_stride[0], omx-1, omy, bw, bh, &m->weight[0] ); + h->mc.mc_luma( pix+48, 64, m->p_fref, m->i_stride[0], omx+1, omy, bw, bh, &m->weight[0] ); + h->pixf.fpelcmp_x4[i_pixel]( m->p_fenc[0], pix, pix+16, pix+32, pix+48, 64, costs ); + costs[0] += p_cost_mvx[omx ] + p_cost_mvy[omy-1]; + costs[1] += p_cost_mvx[omx ] + p_cost_mvy[omy+1]; + costs[2] += p_cost_mvx[omx-1] + p_cost_mvy[omy ]; + costs[3] += p_cost_mvx[omx+1] + p_cost_mvy[omy ]; + bcost <<= 4; + COPY1_IF_LT( bcost, (costs[0]<<4)+1 ); + COPY1_IF_LT( bcost, (costs[1]<<4)+3 ); + COPY1_IF_LT( bcost, (costs[2]<<4)+4 ); + COPY1_IF_LT( bcost, (costs[3]<<4)+12 ); + bmx -= (bcost<<28)>>30; + bmy -= (bcost<<30)>>30; + bcost >>= 4; + } + + m->cost = bcost; + m->mv[0] = bmx; + m->mv[1] = bmy; + m->cost_mv = p_cost_mvx[bmx] + p_cost_mvy[bmy]; +} + +#define BIME_CACHE( dx, dy, list )\ +{\ + x264_me_t *m = m##list;\ + int i = 4 + 3*dx + dy;\ + int mvx = bm##list##x+dx;\ + int mvy = bm##list##y+dy;\ + stride[0][list][i] = bw;\ + src[0][list][i] = h->mc.get_ref( pixy_buf[list][i], &stride[0][list][i], &m->p_fref[0],\ + m->i_stride[0], mvx, mvy, bw, bh, x264_weight_none );\ + if( rd )\ + {\ + if( CHROMA444 )\ + {\ + stride[1][list][i] = bw;\ + src[1][list][i] = h->mc.get_ref( pixu_buf[list][i], &stride[1][list][i], &m->p_fref[4],\ + m->i_stride[1], mvx, mvy, bw, bh, x264_weight_none );\ + stride[2][list][i] = bw;\ + src[2][list][i] = h->mc.get_ref( pixv_buf[list][i], &stride[2][list][i], &m->p_fref[8],\ + m->i_stride[2], mvx, mvy, bw, bh, x264_weight_none );\ + }\ + else\ + h->mc.mc_chroma( pixu_buf[list][i], pixv_buf[list][i], 8, m->p_fref[4], m->i_stride[1],\ + mvx, 2*(mvy+mv##list##y_offset)>>chroma_v_shift, bw>>1, bh>>chroma_v_shift );\ + }\ +} + +#define SATD_THRESH(cost) (cost+(cost>>4)) + +/* Don't unroll the BIME_CACHE loop. I couldn't find any way to force this + * other than making its iteration count not a compile-time constant. */ +int x264_iter_kludge = 0; + +static void ALWAYS_INLINE x264_me_refine_bidir( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight, int i8, int i_lambda2, int rd ) +{ + int x = i8&1; + int y = i8>>1; + int s8 = X264_SCAN8_0 + 2*x + 16*y; + int16_t *cache0_mv = h->mb.cache.mv[0][s8]; + int16_t *cache1_mv = h->mb.cache.mv[1][s8]; + const int i_pixel = m0->i_pixel; + const int bw = x264_pixel_size[i_pixel].w; + const int bh = x264_pixel_size[i_pixel].h; + ALIGNED_ARRAY_32( pixel, pixy_buf,[2],[9][16*16] ); + ALIGNED_ARRAY_32( pixel, pixu_buf,[2],[9][16*16] ); + ALIGNED_ARRAY_32( pixel, pixv_buf,[2],[9][16*16] ); + pixel *src[3][2][9]; + int chromapix = h->luma2chroma_pixel[i_pixel]; + int chroma_v_shift = CHROMA_V_SHIFT; + int chroma_x = (8 >> CHROMA_H_SHIFT) * x; + int chroma_y = (8 >> chroma_v_shift) * y; + pixel *pix = &h->mb.pic.p_fdec[0][8*x + 8*y*FDEC_STRIDE]; + pixel *pixu = &h->mb.pic.p_fdec[1][chroma_x + chroma_y*FDEC_STRIDE]; + pixel *pixv = &h->mb.pic.p_fdec[2][chroma_x + chroma_y*FDEC_STRIDE]; + int ref0 = h->mb.cache.ref[0][s8]; + int ref1 = h->mb.cache.ref[1][s8]; + const int mv0y_offset = chroma_v_shift & MB_INTERLACED & ref0 ? (h->mb.i_mb_y & 1)*4 - 2 : 0; + const int mv1y_offset = chroma_v_shift & MB_INTERLACED & ref1 ? (h->mb.i_mb_y & 1)*4 - 2 : 0; + intptr_t stride[3][2][9]; + int bm0x = m0->mv[0]; + int bm0y = m0->mv[1]; + int bm1x = m1->mv[0]; + int bm1y = m1->mv[1]; + int bcost = COST_MAX; + int mc_list0 = 1, mc_list1 = 1; + uint64_t bcostrd = COST_MAX64; + uint16_t amvd; + /* each byte of visited represents 8 possible m1y positions, so a 4D array isn't needed */ + ALIGNED_ARRAY_64( uint8_t, visited,[8],[8][8] ); + /* all permutations of an offset in up to 2 of the dimensions */ + ALIGNED_4( static const int8_t dia4d[33][4] ) = + { + {0,0,0,0}, + {0,0,0,1}, {0,0,0,-1}, {0,0,1,0}, {0,0,-1,0}, + {0,1,0,0}, {0,-1,0,0}, {1,0,0,0}, {-1,0,0,0}, + {0,0,1,1}, {0,0,-1,-1},{0,1,1,0}, {0,-1,-1,0}, + {1,1,0,0}, {-1,-1,0,0},{1,0,0,1}, {-1,0,0,-1}, + {0,1,0,1}, {0,-1,0,-1},{1,0,1,0}, {-1,0,-1,0}, + {0,0,-1,1},{0,0,1,-1}, {0,-1,1,0},{0,1,-1,0}, + {-1,1,0,0},{1,-1,0,0}, {1,0,0,-1},{-1,0,0,1}, + {0,-1,0,1},{0,1,0,-1}, {-1,0,1,0},{1,0,-1,0}, + }; + + if( bm0y < h->mb.mv_min_spel[1] + 8 || bm1y < h->mb.mv_min_spel[1] + 8 || + bm0y > h->mb.mv_max_spel[1] - 8 || bm1y > h->mb.mv_max_spel[1] - 8 || + bm0x < h->mb.mv_min_spel[0] + 8 || bm1x < h->mb.mv_min_spel[0] + 8 || + bm0x > h->mb.mv_max_spel[0] - 8 || bm1x > h->mb.mv_max_spel[0] - 8 ) + return; + + if( rd && m0->i_pixel != PIXEL_16x16 && i8 != 0 ) + { + x264_mb_predict_mv( h, 0, i8<<2, bw>>2, m0->mvp ); + x264_mb_predict_mv( h, 1, i8<<2, bw>>2, m1->mvp ); + } + + const uint16_t *p_cost_m0x = m0->p_cost_mv - m0->mvp[0]; + const uint16_t *p_cost_m0y = m0->p_cost_mv - m0->mvp[1]; + const uint16_t *p_cost_m1x = m1->p_cost_mv - m1->mvp[0]; + const uint16_t *p_cost_m1y = m1->p_cost_mv - m1->mvp[1]; + + h->mc.memzero_aligned( visited, sizeof(uint8_t[8][8][8]) ); + + for( int pass = 0; pass < 8; pass++ ) + { + int bestj = 0; + /* check all mv pairs that differ in at most 2 components from the current mvs. */ + /* doesn't do chroma ME. this probably doesn't matter, as the gains + * from bidir ME are the same with and without chroma ME. */ + + if( mc_list0 ) + for( int j = x264_iter_kludge; j < 9; j++ ) + BIME_CACHE( square1[j][0], square1[j][1], 0 ); + + if( mc_list1 ) + for( int j = x264_iter_kludge; j < 9; j++ ) + BIME_CACHE( square1[j][0], square1[j][1], 1 ); + + for( int j = !!pass; j < 33; j++ ) + { + int m0x = dia4d[j][0] + bm0x; + int m0y = dia4d[j][1] + bm0y; + int m1x = dia4d[j][2] + bm1x; + int m1y = dia4d[j][3] + bm1y; + if( !pass || !((visited[(m0x)&7][(m0y)&7][(m1x)&7] & (1<<((m1y)&7)))) ) + { + int i0 = 4 + 3*dia4d[j][0] + dia4d[j][1]; + int i1 = 4 + 3*dia4d[j][2] + dia4d[j][3]; + visited[(m0x)&7][(m0y)&7][(m1x)&7] |= (1<<((m1y)&7)); + h->mc.avg[i_pixel]( pix, FDEC_STRIDE, src[0][0][i0], stride[0][0][i0], src[0][1][i1], stride[0][1][i1], i_weight ); + int cost = h->pixf.mbcmp[i_pixel]( m0->p_fenc[0], FENC_STRIDE, pix, FDEC_STRIDE ) + + p_cost_m0x[m0x] + p_cost_m0y[m0y] + p_cost_m1x[m1x] + p_cost_m1y[m1y]; + if( rd ) + { + if( cost < SATD_THRESH(bcost) ) + { + bcost = X264_MIN( cost, bcost ); + M32( cache0_mv ) = pack16to32_mask(m0x,m0y); + M32( cache1_mv ) = pack16to32_mask(m1x,m1y); + if( CHROMA444 ) + { + h->mc.avg[i_pixel]( pixu, FDEC_STRIDE, src[1][0][i0], stride[1][0][i0], src[1][1][i1], stride[1][1][i1], i_weight ); + h->mc.avg[i_pixel]( pixv, FDEC_STRIDE, src[2][0][i0], stride[2][0][i0], src[2][1][i1], stride[2][1][i1], i_weight ); + } + else + { + h->mc.avg[chromapix]( pixu, FDEC_STRIDE, pixu_buf[0][i0], 8, pixu_buf[1][i1], 8, i_weight ); + h->mc.avg[chromapix]( pixv, FDEC_STRIDE, pixv_buf[0][i0], 8, pixv_buf[1][i1], 8, i_weight ); + } + uint64_t costrd = x264_rd_cost_part( h, i_lambda2, i8*4, m0->i_pixel ); + COPY2_IF_LT( bcostrd, costrd, bestj, j ); + } + } + else + COPY2_IF_LT( bcost, cost, bestj, j ); + } + } + + if( !bestj ) + break; + + bm0x += dia4d[bestj][0]; + bm0y += dia4d[bestj][1]; + bm1x += dia4d[bestj][2]; + bm1y += dia4d[bestj][3]; + + mc_list0 = M16( &dia4d[bestj][0] ); + mc_list1 = M16( &dia4d[bestj][2] ); + } + + if( rd ) + { + x264_macroblock_cache_mv ( h, 2*x, 2*y, bw>>2, bh>>2, 0, pack16to32_mask(bm0x, bm0y) ); + amvd = pack8to16( X264_MIN(abs(bm0x - m0->mvp[0]),33), X264_MIN(abs(bm0y - m0->mvp[1]),33) ); + x264_macroblock_cache_mvd( h, 2*x, 2*y, bw>>2, bh>>2, 0, amvd ); + + x264_macroblock_cache_mv ( h, 2*x, 2*y, bw>>2, bh>>2, 1, pack16to32_mask(bm1x, bm1y) ); + amvd = pack8to16( X264_MIN(abs(bm1x - m1->mvp[0]),33), X264_MIN(abs(bm1y - m1->mvp[1]),33) ); + x264_macroblock_cache_mvd( h, 2*x, 2*y, bw>>2, bh>>2, 1, amvd ); + } + + m0->mv[0] = bm0x; + m0->mv[1] = bm0y; + m1->mv[0] = bm1x; + m1->mv[1] = bm1y; +} + +void x264_me_refine_bidir_satd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight ) +{ + x264_me_refine_bidir( h, m0, m1, i_weight, 0, 0, 0 ); +} + +void x264_me_refine_bidir_rd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight, int i8, int i_lambda2 ) +{ + /* Motion compensation is done as part of bidir_rd; don't repeat + * it in encoding. */ + h->mb.b_skip_mc = 1; + x264_me_refine_bidir( h, m0, m1, i_weight, i8, i_lambda2, 1 ); + h->mb.b_skip_mc = 0; +} + +#undef COST_MV_SATD +#define COST_MV_SATD( mx, my, dst, avoid_mvp ) \ +{ \ + if( !avoid_mvp || !(mx == pmx && my == pmy) ) \ + { \ + h->mc.mc_luma( pix, FDEC_STRIDE, m->p_fref, m->i_stride[0], mx, my, bw, bh, &m->weight[0] ); \ + dst = h->pixf.mbcmp[i_pixel]( m->p_fenc[0], FENC_STRIDE, pix, FDEC_STRIDE ) \ + + p_cost_mvx[mx] + p_cost_mvy[my]; \ + COPY1_IF_LT( bsatd, dst ); \ + } \ + else \ + dst = COST_MAX; \ +} + +#define COST_MV_RD( mx, my, satd, do_dir, mdir ) \ +{ \ + if( satd <= SATD_THRESH(bsatd) ) \ + { \ + uint64_t cost; \ + M32( cache_mv ) = pack16to32_mask(mx,my); \ + if( CHROMA444 ) \ + { \ + h->mc.mc_luma( pixu, FDEC_STRIDE, &m->p_fref[4], m->i_stride[1], mx, my, bw, bh, &m->weight[1] ); \ + h->mc.mc_luma( pixv, FDEC_STRIDE, &m->p_fref[8], m->i_stride[2], mx, my, bw, bh, &m->weight[2] ); \ + } \ + else if( m->i_pixel <= PIXEL_8x8 ) \ + { \ + h->mc.mc_chroma( pixu, pixv, FDEC_STRIDE, m->p_fref[4], m->i_stride[1], \ + mx, 2*(my+mvy_offset)>>chroma_v_shift, bw>>1, bh>>chroma_v_shift ); \ + if( m->weight[1].weightfn ) \ + m->weight[1].weightfn[bw>>3]( pixu, FDEC_STRIDE, pixu, FDEC_STRIDE, &m->weight[1], bh>>chroma_v_shift ); \ + if( m->weight[2].weightfn ) \ + m->weight[2].weightfn[bw>>3]( pixv, FDEC_STRIDE, pixv, FDEC_STRIDE, &m->weight[2], bh>>chroma_v_shift ); \ + } \ + cost = x264_rd_cost_part( h, i_lambda2, i4, m->i_pixel ); \ + COPY4_IF_LT( bcost, cost, bmx, mx, bmy, my, dir, do_dir?mdir:dir ); \ + } \ +} + +void x264_me_refine_qpel_rd( x264_t *h, x264_me_t *m, int i_lambda2, int i4, int i_list ) +{ + int16_t *cache_mv = h->mb.cache.mv[i_list][x264_scan8[i4]]; + const uint16_t *p_cost_mvx, *p_cost_mvy; + const int bw = x264_pixel_size[m->i_pixel].w; + const int bh = x264_pixel_size[m->i_pixel].h; + const int i_pixel = m->i_pixel; + int chroma_v_shift = CHROMA_V_SHIFT; + int mvy_offset = chroma_v_shift & MB_INTERLACED & m->i_ref ? (h->mb.i_mb_y & 1)*4 - 2 : 0; + + uint64_t bcost = COST_MAX64; + int bmx = m->mv[0]; + int bmy = m->mv[1]; + int omx, omy, pmx, pmy; + int satd, bsatd; + int dir = -2; + int i8 = i4>>2; + uint16_t amvd; + + pixel *pix = &h->mb.pic.p_fdec[0][block_idx_xy_fdec[i4]]; + pixel *pixu, *pixv; + if( CHROMA444 ) + { + pixu = &h->mb.pic.p_fdec[1][block_idx_xy_fdec[i4]]; + pixv = &h->mb.pic.p_fdec[2][block_idx_xy_fdec[i4]]; + } + else + { + pixu = &h->mb.pic.p_fdec[1][(i8>>1)*(8*FDEC_STRIDE>>chroma_v_shift)+(i8&1)*4]; + pixv = &h->mb.pic.p_fdec[2][(i8>>1)*(8*FDEC_STRIDE>>chroma_v_shift)+(i8&1)*4]; + } + + h->mb.b_skip_mc = 1; + + if( m->i_pixel != PIXEL_16x16 && i4 != 0 ) + x264_mb_predict_mv( h, i_list, i4, bw>>2, m->mvp ); + pmx = m->mvp[0]; + pmy = m->mvp[1]; + p_cost_mvx = m->p_cost_mv - pmx; + p_cost_mvy = m->p_cost_mv - pmy; + COST_MV_SATD( bmx, bmy, bsatd, 0 ); + if( m->i_pixel != PIXEL_16x16 ) + COST_MV_RD( bmx, bmy, 0, 0, 0 ) + else + bcost = m->cost; + + /* check the predicted mv */ + if( (bmx != pmx || bmy != pmy) + && pmx >= h->mb.mv_min_spel[0] && pmx <= h->mb.mv_max_spel[0] + && pmy >= h->mb.mv_min_spel[1] && pmy <= h->mb.mv_max_spel[1] ) + { + COST_MV_SATD( pmx, pmy, satd, 0 ); + COST_MV_RD ( pmx, pmy, satd, 0, 0 ); + /* The hex motion search is guaranteed to not repeat the center candidate, + * so if pmv is chosen, set the "MV to avoid checking" to bmv instead. */ + if( bmx == pmx && bmy == pmy ) + { + pmx = m->mv[0]; + pmy = m->mv[1]; + } + } + + if( bmy < h->mb.mv_min_spel[1] + 3 || bmy > h->mb.mv_max_spel[1] - 3 || + bmx < h->mb.mv_min_spel[0] + 3 || bmx > h->mb.mv_max_spel[0] - 3 ) + { + h->mb.b_skip_mc = 0; + return; + } + + /* subpel hex search, same pattern as ME HEX. */ + dir = -2; + omx = bmx; + omy = bmy; + for( int j = 0; j < 6; j++ ) + { + COST_MV_SATD( omx + hex2[j+1][0], omy + hex2[j+1][1], satd, 1 ); + COST_MV_RD ( omx + hex2[j+1][0], omy + hex2[j+1][1], satd, 1, j ); + } + + if( dir != -2 ) + { + /* half hexagon, not overlapping the previous iteration */ + for( int i = 1; i < 10; i++ ) + { + const int odir = mod6m1[dir+1]; + if( bmy < h->mb.mv_min_spel[1] + 3 || + bmy > h->mb.mv_max_spel[1] - 3 ) + break; + dir = -2; + omx = bmx; + omy = bmy; + for( int j = 0; j < 3; j++ ) + { + COST_MV_SATD( omx + hex2[odir+j][0], omy + hex2[odir+j][1], satd, 1 ); + COST_MV_RD ( omx + hex2[odir+j][0], omy + hex2[odir+j][1], satd, 1, odir-1+j ); + } + if( dir == -2 ) + break; + } + } + + /* square refine, same pattern as ME HEX. */ + omx = bmx; + omy = bmy; + for( int i = 0; i < 8; i++ ) + { + COST_MV_SATD( omx + square1[i+1][0], omy + square1[i+1][1], satd, 1 ); + COST_MV_RD ( omx + square1[i+1][0], omy + square1[i+1][1], satd, 0, 0 ); + } + + m->cost = bcost; + m->mv[0] = bmx; + m->mv[1] = bmy; + x264_macroblock_cache_mv ( h, block_idx_x[i4], block_idx_y[i4], bw>>2, bh>>2, i_list, pack16to32_mask(bmx, bmy) ); + amvd = pack8to16( X264_MIN(abs(bmx - m->mvp[0]),66), X264_MIN(abs(bmy - m->mvp[1]),66) ); + x264_macroblock_cache_mvd( h, block_idx_x[i4], block_idx_y[i4], bw>>2, bh>>2, i_list, amvd ); + h->mb.b_skip_mc = 0; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/me.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/me.h new file mode 100644 index 00000000..505e3ce1 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/me.h @@ -0,0 +1,104 @@ +/***************************************************************************** + * me.h: motion estimation + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ME_H +#define X264_ME_H + +#define COST_MAX (1<<28) +#define COST_MAX64 (1ULL<<60) + +typedef struct +{ + /* aligning the first member is a gcc hack to force the struct to be aligned, + * as well as force sizeof(struct) to be a multiple of the alignment. */ + /* input */ + ALIGNED_64( int i_pixel ); /* PIXEL_WxH */ + uint16_t *p_cost_mv; /* lambda * nbits for each possible mv */ + int i_ref_cost; + int i_ref; + const x264_weight_t *weight; + + pixel *p_fref[12]; + pixel *p_fref_w; + pixel *p_fenc[3]; + uint16_t *integral; + int i_stride[3]; + + ALIGNED_4( int16_t mvp[2] ); + + /* output */ + int cost_mv; /* lambda * nbits for the chosen mv */ + int cost; /* satd + lambda * nbits */ + ALIGNED_4( int16_t mv[2] ); +} ALIGNED_64( x264_me_t ); + +void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, int *p_fullpel_thresh ); +#define x264_me_search( h, m, mvc, i_mvc )\ + x264_me_search_ref( h, m, mvc, i_mvc, NULL ) + +void x264_me_refine_qpel( x264_t *h, x264_me_t *m ); +void x264_me_refine_qpel_refdupe( x264_t *h, x264_me_t *m, int *p_halfpel_thresh ); +void x264_me_refine_qpel_rd( x264_t *h, x264_me_t *m, int i_lambda2, int i4, int i_list ); +void x264_me_refine_bidir_rd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight, int i8, int i_lambda2 ); +void x264_me_refine_bidir_satd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight ); +uint64_t x264_rd_cost_part( x264_t *h, int i_lambda2, int i8, int i_pixel ); + +#define COPY1_IF_LT(x,y)\ +if( (y) < (x) )\ + (x) = (y); + +#define COPY2_IF_LT(x,y,a,b)\ +if( (y) < (x) )\ +{\ + (x) = (y);\ + (a) = (b);\ +} + +#define COPY3_IF_LT(x,y,a,b,c,d)\ +if( (y) < (x) )\ +{\ + (x) = (y);\ + (a) = (b);\ + (c) = (d);\ +} + +#define COPY4_IF_LT(x,y,a,b,c,d,e,f)\ +if( (y) < (x) )\ +{\ + (x) = (y);\ + (a) = (b);\ + (c) = (d);\ + (e) = (f);\ +} + +#define COPY2_IF_GT(x,y,a,b)\ +if( (y) > (x) )\ +{\ + (x) = (y);\ + (a) = (b);\ +} + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/ratecontrol.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/ratecontrol.c new file mode 100644 index 00000000..5289316b --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/ratecontrol.c @@ -0,0 +1,3104 @@ +/***************************************************************************** + * ratecontrol.c: ratecontrol + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: Loren Merritt + * Michael Niedermayer + * Gabriel Bouvigne + * Fiona Glaser + * Måns Rullgård + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#undef NDEBUG // always check asserts, the speed effect is far too small to disable them + +#include "common/common.h" +#include "ratecontrol.h" +#include "me.h" + +typedef struct +{ + int pict_type; + int frame_type; + int kept_as_ref; + double qscale; + int mv_bits; + int tex_bits; + int misc_bits; + double expected_bits; /* total expected bits up to the current frame (current one excluded) */ + double expected_vbv; + double new_qscale; + float new_qp; + int i_count; + int p_count; + int s_count; + float blurred_complexity; + char direct_mode; + int16_t weight[3][2]; + int16_t i_weight_denom[2]; + int refcount[16]; + int refs; + int64_t i_duration; + int64_t i_cpb_duration; + int out_num; +} ratecontrol_entry_t; + +typedef struct +{ + float coeff_min; + float coeff; + float count; + float decay; + float offset; +} predictor_t; + +struct x264_ratecontrol_t +{ + /* constants */ + int b_abr; + int b_2pass; + int b_vbv; + int b_vbv_min_rate; + double fps; + double bitrate; + double rate_tolerance; + double qcompress; + int nmb; /* number of macroblocks in a frame */ + int qp_constant[3]; + + /* current frame */ + ratecontrol_entry_t *rce; + float qpm; /* qp for current macroblock: precise float for AQ */ + float qpa_rc; /* average of macroblocks' qp before aq */ + float qpa_rc_prev; + int qpa_aq; /* average of macroblocks' qp after aq */ + int qpa_aq_prev; + float qp_novbv; /* QP for the current frame if 1-pass VBV was disabled. */ + + /* VBV stuff */ + double buffer_size; + int64_t buffer_fill_final; + int64_t buffer_fill_final_min; + double buffer_fill; /* planned buffer, if all in-progress frames hit their bit budget */ + double buffer_rate; /* # of bits added to buffer_fill after each frame */ + double vbv_max_rate; /* # of bits added to buffer_fill per second */ + predictor_t *pred; /* predict frame size from satd */ + int single_frame_vbv; + float rate_factor_max_increment; /* Don't allow RF above (CRF + this value). */ + + /* ABR stuff */ + int last_satd; + double last_rceq; + double cplxr_sum; /* sum of bits*qscale/rceq */ + double expected_bits_sum; /* sum of qscale2bits after rceq, ratefactor, and overflow, only includes finished frames */ + int64_t filler_bits_sum; /* sum in bits of finished frames' filler data */ + double wanted_bits_window; /* target bitrate * window */ + double cbr_decay; + double short_term_cplxsum; + double short_term_cplxcount; + double rate_factor_constant; + double ip_offset; + double pb_offset; + + /* 2pass stuff */ + FILE *p_stat_file_out; + char *psz_stat_file_tmpname; + FILE *p_mbtree_stat_file_out; + char *psz_mbtree_stat_file_tmpname; + char *psz_mbtree_stat_file_name; + FILE *p_mbtree_stat_file_in; + + int num_entries; /* number of ratecontrol_entry_ts */ + ratecontrol_entry_t *entry; /* FIXME: copy needed data and free this once init is done */ + ratecontrol_entry_t **entry_out; + double last_qscale; + double last_qscale_for[3]; /* last qscale for a specific pict type, used for max_diff & ipb factor stuff */ + int last_non_b_pict_type; + double accum_p_qp; /* for determining I-frame quant */ + double accum_p_norm; + double last_accum_p_norm; + double lmin[3]; /* min qscale by frame type */ + double lmax[3]; + double lstep; /* max change (multiply) in qscale per frame */ + struct + { + uint16_t *qp_buffer[2]; /* Global buffers for converting MB-tree quantizer data. */ + int qpbuf_pos; /* In order to handle pyramid reordering, QP buffer acts as a stack. + * This value is the current position (0 or 1). */ + int src_mb_count; + + /* For rescaling */ + int rescale_enabled; + float *scale_buffer[2]; /* Intermediate buffers */ + int filtersize[2]; /* filter size (H/V) */ + float *coeffs[2]; + int *pos[2]; + int srcdim[2]; /* Source dimensions (W/H) */ + } mbtree; + + /* MBRC stuff */ + float frame_size_estimated; /* Access to this variable must be atomic: double is + * not atomic on all arches we care about */ + double frame_size_maximum; /* Maximum frame size due to MinCR */ + double frame_size_planned; + double slice_size_planned; + predictor_t *row_pred; + predictor_t row_preds[3][2]; + predictor_t *pred_b_from_p; /* predict B-frame size from P-frame satd */ + int bframes; /* # consecutive B-frames before this P-frame */ + int bframe_bits; /* total cost of those frames */ + + int i_zones; + x264_zone_t *zones; + x264_zone_t *prev_zone; + + /* hrd stuff */ + int initial_cpb_removal_delay; + int initial_cpb_removal_delay_offset; + double nrt_first_access_unit; /* nominal removal time */ + double previous_cpb_final_arrival_time; + uint64_t hrd_multiply_denom; +}; + + +static int parse_zones( x264_t *h ); +static int init_pass2(x264_t *); +static float rate_estimate_qscale( x264_t *h ); +static int update_vbv( x264_t *h, int bits ); +static void update_vbv_plan( x264_t *h, int overhead ); +static float predict_size( predictor_t *p, float q, float var ); +static void update_predictor( predictor_t *p, float q, float var, float bits ); + +#define CMP_OPT_FIRST_PASS( opt, param_val )\ +{\ + if( ( p = strstr( opts, opt "=" ) ) && sscanf( p, opt "=%d" , &i ) && param_val != i )\ + {\ + x264_log( h, X264_LOG_ERROR, "different " opt " setting than first pass (%d vs %d)\n", param_val, i );\ + return -1;\ + }\ +} + +/* Terminology: + * qp = h.264's quantizer + * qscale = linearized quantizer = Lagrange multiplier + */ +static inline float qp2qscale( float qp ) +{ + return 0.85f * powf( 2.0f, ( qp - (12.0f + QP_BD_OFFSET) ) / 6.0f ); +} +static inline float qscale2qp( float qscale ) +{ + return (12.0f + QP_BD_OFFSET) + 6.0f * log2f( qscale/0.85f ); +} + +/* Texture bitrate is not quite inversely proportional to qscale, + * probably due the the changing number of SKIP blocks. + * MV bits level off at about qp<=12, because the lambda used + * for motion estimation is constant there. */ +static inline double qscale2bits( ratecontrol_entry_t *rce, double qscale ) +{ + if( qscale<0.1 ) + qscale = 0.1; + return (rce->tex_bits + .1) * pow( rce->qscale / qscale, 1.1 ) + + rce->mv_bits * pow( X264_MAX(rce->qscale, 1) / X264_MAX(qscale, 1), 0.5 ) + + rce->misc_bits; +} + +static ALWAYS_INLINE uint32_t ac_energy_var( uint64_t sum_ssd, int shift, x264_frame_t *frame, int i, int b_store ) +{ + uint32_t sum = sum_ssd; + uint32_t ssd = sum_ssd >> 32; + if( b_store ) + { + frame->i_pixel_sum[i] += sum; + frame->i_pixel_ssd[i] += ssd; + } + return ssd - ((uint64_t)sum * sum >> shift); +} + +static ALWAYS_INLINE uint32_t ac_energy_plane( x264_t *h, int mb_x, int mb_y, x264_frame_t *frame, int i, int b_chroma, int b_field, int b_store ) +{ + int height = b_chroma ? 16>>CHROMA_V_SHIFT : 16; + int stride = frame->i_stride[i]; + int offset = b_field + ? 16 * mb_x + height * (mb_y&~1) * stride + (mb_y&1) * stride + : 16 * mb_x + height * mb_y * stride; + stride <<= b_field; + if( b_chroma ) + { + ALIGNED_ARRAY_32( pixel, pix,[FENC_STRIDE*16] ); + int chromapix = h->luma2chroma_pixel[PIXEL_16x16]; + int shift = 7 - CHROMA_V_SHIFT; + + h->mc.load_deinterleave_chroma_fenc( pix, frame->plane[1] + offset, stride, height ); + return ac_energy_var( h->pixf.var[chromapix]( pix, FENC_STRIDE ), shift, frame, 1, b_store ) + + ac_energy_var( h->pixf.var[chromapix]( pix+FENC_STRIDE/2, FENC_STRIDE ), shift, frame, 2, b_store ); + } + else + return ac_energy_var( h->pixf.var[PIXEL_16x16]( frame->plane[i] + offset, stride ), 8, frame, i, b_store ); +} + +// Find the total AC energy of the block in all planes. +static NOINLINE uint32_t x264_ac_energy_mb( x264_t *h, int mb_x, int mb_y, x264_frame_t *frame ) +{ + /* This function contains annoying hacks because GCC has a habit of reordering emms + * and putting it after floating point ops. As a result, we put the emms at the end of the + * function and make sure that its always called before the float math. Noinline makes + * sure no reordering goes on. */ + uint32_t var; + x264_prefetch_fenc( h, frame, mb_x, mb_y ); + if( h->mb.b_adaptive_mbaff ) + { + /* We don't know the super-MB mode we're going to pick yet, so + * simply try both and pick the lower of the two. */ + uint32_t var_interlaced, var_progressive; + var_interlaced = ac_energy_plane( h, mb_x, mb_y, frame, 0, 0, 1, 1 ); + var_progressive = ac_energy_plane( h, mb_x, mb_y, frame, 0, 0, 0, 0 ); + if( CHROMA444 ) + { + var_interlaced += ac_energy_plane( h, mb_x, mb_y, frame, 1, 0, 1, 1 ); + var_progressive += ac_energy_plane( h, mb_x, mb_y, frame, 1, 0, 0, 0 ); + var_interlaced += ac_energy_plane( h, mb_x, mb_y, frame, 2, 0, 1, 1 ); + var_progressive += ac_energy_plane( h, mb_x, mb_y, frame, 2, 0, 0, 0 ); + } + else + { + var_interlaced += ac_energy_plane( h, mb_x, mb_y, frame, 1, 1, 1, 1 ); + var_progressive += ac_energy_plane( h, mb_x, mb_y, frame, 1, 1, 0, 0 ); + } + var = X264_MIN( var_interlaced, var_progressive ); + } + else + { + var = ac_energy_plane( h, mb_x, mb_y, frame, 0, 0, PARAM_INTERLACED, 1 ); + if( CHROMA444 ) + { + var += ac_energy_plane( h, mb_x, mb_y, frame, 1, 0, PARAM_INTERLACED, 1 ); + var += ac_energy_plane( h, mb_x, mb_y, frame, 2, 0, PARAM_INTERLACED, 1 ); + } + else + var += ac_energy_plane( h, mb_x, mb_y, frame, 1, 1, PARAM_INTERLACED, 1 ); + } + x264_emms(); + return var; +} + +void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_offsets ) +{ + /* Initialize frame stats */ + for( int i = 0; i < 3; i++ ) + { + frame->i_pixel_sum[i] = 0; + frame->i_pixel_ssd[i] = 0; + } + + /* Degenerate cases */ + if( h->param.rc.i_aq_mode == X264_AQ_NONE || h->param.rc.f_aq_strength == 0 ) + { + /* Need to init it anyways for MB tree */ + if( h->param.rc.i_aq_mode && h->param.rc.f_aq_strength == 0 ) + { + if( quant_offsets ) + { + for( int mb_xy = 0; mb_xy < h->mb.i_mb_count; mb_xy++ ) + frame->f_qp_offset[mb_xy] = frame->f_qp_offset_aq[mb_xy] = quant_offsets[mb_xy]; + if( h->frames.b_have_lowres ) + for( int mb_xy = 0; mb_xy < h->mb.i_mb_count; mb_xy++ ) + frame->i_inv_qscale_factor[mb_xy] = x264_exp2fix8( frame->f_qp_offset[mb_xy] ); + } + else + { + memset( frame->f_qp_offset, 0, h->mb.i_mb_count * sizeof(float) ); + memset( frame->f_qp_offset_aq, 0, h->mb.i_mb_count * sizeof(float) ); + if( h->frames.b_have_lowres ) + for( int mb_xy = 0; mb_xy < h->mb.i_mb_count; mb_xy++ ) + frame->i_inv_qscale_factor[mb_xy] = 256; + } + } + /* Need variance data for weighted prediction */ + if( h->param.analyse.i_weighted_pred ) + { + for( int mb_y = 0; mb_y < h->mb.i_mb_height; mb_y++ ) + for( int mb_x = 0; mb_x < h->mb.i_mb_width; mb_x++ ) + x264_ac_energy_mb( h, mb_x, mb_y, frame ); + } + else + return; + } + /* Actual adaptive quantization */ + else + { + /* constants chosen to result in approximately the same overall bitrate as without AQ. + * FIXME: while they're written in 5 significant digits, they're only tuned to 2. */ + float strength; + float avg_adj = 0.f; + float bias_strength = 0.f; + + if( h->param.rc.i_aq_mode == X264_AQ_AUTOVARIANCE || h->param.rc.i_aq_mode == X264_AQ_AUTOVARIANCE_BIASED ) + { + float bit_depth_correction = 1.f / (1 << (2*(BIT_DEPTH-8))); + float avg_adj_pow2 = 0.f; + for( int mb_y = 0; mb_y < h->mb.i_mb_height; mb_y++ ) + for( int mb_x = 0; mb_x < h->mb.i_mb_width; mb_x++ ) + { + uint32_t energy = x264_ac_energy_mb( h, mb_x, mb_y, frame ); + float qp_adj = powf( energy * bit_depth_correction + 1, 0.125f ); + frame->f_qp_offset[mb_x + mb_y*h->mb.i_mb_stride] = qp_adj; + avg_adj += qp_adj; + avg_adj_pow2 += qp_adj * qp_adj; + } + avg_adj /= h->mb.i_mb_count; + avg_adj_pow2 /= h->mb.i_mb_count; + strength = h->param.rc.f_aq_strength * avg_adj; + avg_adj = avg_adj - 0.5f * (avg_adj_pow2 - 14.f) / avg_adj; + bias_strength = h->param.rc.f_aq_strength; + } + else + strength = h->param.rc.f_aq_strength * 1.0397f; + + for( int mb_y = 0; mb_y < h->mb.i_mb_height; mb_y++ ) + for( int mb_x = 0; mb_x < h->mb.i_mb_width; mb_x++ ) + { + float qp_adj; + int mb_xy = mb_x + mb_y*h->mb.i_mb_stride; + if( h->param.rc.i_aq_mode == X264_AQ_AUTOVARIANCE_BIASED ) + { + qp_adj = frame->f_qp_offset[mb_xy]; + qp_adj = strength * (qp_adj - avg_adj) + bias_strength * (1.f - 14.f / (qp_adj * qp_adj)); + } + else if( h->param.rc.i_aq_mode == X264_AQ_AUTOVARIANCE ) + { + qp_adj = frame->f_qp_offset[mb_xy]; + qp_adj = strength * (qp_adj - avg_adj); + } + else + { + uint32_t energy = x264_ac_energy_mb( h, mb_x, mb_y, frame ); + qp_adj = strength * (x264_log2( X264_MAX(energy, 1) ) - (14.427f + 2*(BIT_DEPTH-8))); + } + if( quant_offsets ) + qp_adj += quant_offsets[mb_xy]; + frame->f_qp_offset[mb_xy] = + frame->f_qp_offset_aq[mb_xy] = qp_adj; + if( h->frames.b_have_lowres ) + frame->i_inv_qscale_factor[mb_xy] = x264_exp2fix8(qp_adj); + } + } + + /* Remove mean from SSD calculation */ + for( int i = 0; i < 3; i++ ) + { + uint64_t ssd = frame->i_pixel_ssd[i]; + uint64_t sum = frame->i_pixel_sum[i]; + int width = 16*h->mb.i_mb_width >> (i && CHROMA_H_SHIFT); + int height = 16*h->mb.i_mb_height >> (i && CHROMA_V_SHIFT); + frame->i_pixel_ssd[i] = ssd - (sum * sum + width * height / 2) / (width * height); + } +} + +static int x264_macroblock_tree_rescale_init( x264_t *h, x264_ratecontrol_t *rc ) +{ + /* Use fractional QP array dimensions to compensate for edge padding */ + float srcdim[2] = {rc->mbtree.srcdim[0] / 16.f, rc->mbtree.srcdim[1] / 16.f}; + float dstdim[2] = { h->param.i_width / 16.f, h->param.i_height / 16.f}; + int srcdimi[2] = {ceil(srcdim[0]), ceil(srcdim[1])}; + int dstdimi[2] = {ceil(dstdim[0]), ceil(dstdim[1])}; + if( h->param.b_interlaced || h->param.b_fake_interlaced ) + { + srcdimi[1] = (srcdimi[1]+1)&~1; + dstdimi[1] = (dstdimi[1]+1)&~1; + } + + rc->mbtree.src_mb_count = srcdimi[0] * srcdimi[1]; + + CHECKED_MALLOC( rc->mbtree.qp_buffer[0], rc->mbtree.src_mb_count * sizeof(uint16_t) ); + if( h->param.i_bframe_pyramid && h->param.rc.b_stat_read ) + CHECKED_MALLOC( rc->mbtree.qp_buffer[1], rc->mbtree.src_mb_count * sizeof(uint16_t) ); + rc->mbtree.qpbuf_pos = -1; + + /* No rescaling to do */ + if( srcdimi[0] == dstdimi[0] && srcdimi[1] == dstdimi[1] ) + return 0; + + rc->mbtree.rescale_enabled = 1; + + /* Allocate intermediate scaling buffers */ + CHECKED_MALLOC( rc->mbtree.scale_buffer[0], srcdimi[0] * srcdimi[1] * sizeof(float) ); + CHECKED_MALLOC( rc->mbtree.scale_buffer[1], dstdimi[0] * srcdimi[1] * sizeof(float) ); + + /* Allocate and calculate resize filter parameters and coefficients */ + for( int i = 0; i < 2; i++ ) + { + if( srcdim[i] > dstdim[i] ) // downscale + rc->mbtree.filtersize[i] = 1 + (2 * srcdimi[i] + dstdimi[i] - 1) / dstdimi[i]; + else // upscale + rc->mbtree.filtersize[i] = 3; + + CHECKED_MALLOC( rc->mbtree.coeffs[i], rc->mbtree.filtersize[i] * dstdimi[i] * sizeof(float) ); + CHECKED_MALLOC( rc->mbtree.pos[i], dstdimi[i] * sizeof(int) ); + + /* Initialize filter coefficients */ + float inc = srcdim[i] / dstdim[i]; + float dmul = inc > 1.f ? dstdim[i] / srcdim[i] : 1.f; + float dstinsrc = 0.5f * inc - 0.5f; + int filtersize = rc->mbtree.filtersize[i]; + for( int j = 0; j < dstdimi[i]; j++ ) + { + int pos = dstinsrc - (filtersize - 2.f) * 0.5f; + float sum = 0.0; + rc->mbtree.pos[i][j] = pos; + for( int k = 0; k < filtersize; k++ ) + { + float d = fabs( pos + k - dstinsrc ) * dmul; + float coeff = X264_MAX( 1.f - d, 0 ); + rc->mbtree.coeffs[i][j * filtersize + k] = coeff; + sum += coeff; + } + sum = 1.0f / sum; + for( int k = 0; k < filtersize; k++ ) + rc->mbtree.coeffs[i][j * filtersize + k] *= sum; + dstinsrc += inc; + } + } + + /* Write back actual qp array dimensions */ + rc->mbtree.srcdim[0] = srcdimi[0]; + rc->mbtree.srcdim[1] = srcdimi[1]; + return 0; +fail: + return -1; +} + +static void x264_macroblock_tree_rescale_destroy( x264_ratecontrol_t *rc ) +{ + for( int i = 0; i < 2; i++ ) + { + x264_free( rc->mbtree.qp_buffer[i] ); + x264_free( rc->mbtree.scale_buffer[i] ); + x264_free( rc->mbtree.coeffs[i] ); + x264_free( rc->mbtree.pos[i] ); + } +} + +static ALWAYS_INLINE float tapfilter( float *src, int pos, int max, int stride, float *coeff, int filtersize ) +{ + float sum = 0.f; + for( int i = 0; i < filtersize; i++, pos++ ) + sum += src[x264_clip3( pos, 0, max-1 )*stride] * coeff[i]; + return sum; +} + +static void x264_macroblock_tree_rescale( x264_t *h, x264_ratecontrol_t *rc, float *dst ) +{ + float *input, *output; + int filtersize, stride, height; + + /* H scale first */ + input = rc->mbtree.scale_buffer[0]; + output = rc->mbtree.scale_buffer[1]; + filtersize = rc->mbtree.filtersize[0]; + stride = rc->mbtree.srcdim[0]; + height = rc->mbtree.srcdim[1]; + for( int y = 0; y < height; y++, input += stride, output += h->mb.i_mb_width ) + { + float *coeff = rc->mbtree.coeffs[0]; + for( int x = 0; x < h->mb.i_mb_width; x++, coeff+=filtersize ) + output[x] = tapfilter( input, rc->mbtree.pos[0][x], stride, 1, coeff, filtersize ); + } + + /* V scale next */ + input = rc->mbtree.scale_buffer[1]; + output = dst; + filtersize = rc->mbtree.filtersize[1]; + stride = h->mb.i_mb_width; + height = rc->mbtree.srcdim[1]; + for( int x = 0; x < h->mb.i_mb_width; x++, input++, output++ ) + { + float *coeff = rc->mbtree.coeffs[1]; + for( int y = 0; y < h->mb.i_mb_height; y++, coeff+=filtersize ) + output[y*stride] = tapfilter( input, rc->mbtree.pos[1][y], height, stride, coeff, filtersize ); + } +} + +int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets ) +{ + x264_ratecontrol_t *rc = h->rc; + uint8_t i_type_actual = rc->entry[frame->i_frame].pict_type; + + if( rc->entry[frame->i_frame].kept_as_ref ) + { + uint8_t i_type; + if( rc->mbtree.qpbuf_pos < 0 ) + { + do + { + rc->mbtree.qpbuf_pos++; + + if( !fread( &i_type, 1, 1, rc->p_mbtree_stat_file_in ) ) + goto fail; + if( fread( rc->mbtree.qp_buffer[rc->mbtree.qpbuf_pos], sizeof(uint16_t), rc->mbtree.src_mb_count, rc->p_mbtree_stat_file_in ) != rc->mbtree.src_mb_count ) + goto fail; + + if( i_type != i_type_actual && rc->mbtree.qpbuf_pos == 1 ) + { + x264_log( h, X264_LOG_ERROR, "MB-tree frametype %d doesn't match actual frametype %d.\n", i_type, i_type_actual ); + return -1; + } + } while( i_type != i_type_actual ); + } + + float *dst = rc->mbtree.rescale_enabled ? rc->mbtree.scale_buffer[0] : frame->f_qp_offset; + h->mc.mbtree_fix8_unpack( dst, rc->mbtree.qp_buffer[rc->mbtree.qpbuf_pos], rc->mbtree.src_mb_count ); + if( rc->mbtree.rescale_enabled ) + x264_macroblock_tree_rescale( h, rc, frame->f_qp_offset ); + if( h->frames.b_have_lowres ) + for( int i = 0; i < h->mb.i_mb_count; i++ ) + frame->i_inv_qscale_factor[i] = x264_exp2fix8( frame->f_qp_offset[i] ); + rc->mbtree.qpbuf_pos--; + } + else + x264_stack_align( x264_adaptive_quant_frame, h, frame, quant_offsets ); + return 0; +fail: + x264_log( h, X264_LOG_ERROR, "Incomplete MB-tree stats file.\n" ); + return -1; +} + +int x264_reference_build_list_optimal( x264_t *h ) +{ + ratecontrol_entry_t *rce = h->rc->rce; + x264_frame_t *frames[16]; + x264_weight_t weights[16][3]; + int refcount[16]; + + if( rce->refs != h->i_ref[0] ) + return -1; + + memcpy( frames, h->fref[0], sizeof(frames) ); + memcpy( refcount, rce->refcount, sizeof(refcount) ); + memcpy( weights, h->fenc->weight, sizeof(weights) ); + memset( &h->fenc->weight[1][0], 0, sizeof(x264_weight_t[15][3]) ); + + /* For now don't reorder ref 0; it seems to lower quality + in most cases due to skips. */ + for( int ref = 1; ref < h->i_ref[0]; ref++ ) + { + int max = -1; + int bestref = 1; + + for( int i = 1; i < h->i_ref[0]; i++ ) + /* Favor lower POC as a tiebreaker. */ + COPY2_IF_GT( max, refcount[i], bestref, i ); + + /* FIXME: If there are duplicates from frames other than ref0 then it is possible + * that the optimal ordering doesnt place every duplicate. */ + + refcount[bestref] = -1; + h->fref[0][ref] = frames[bestref]; + memcpy( h->fenc->weight[ref], weights[bestref], sizeof(weights[bestref]) ); + } + + return 0; +} + +static char *x264_strcat_filename( char *input, char *suffix ) +{ + char *output = x264_malloc( strlen( input ) + strlen( suffix ) + 1 ); + if( !output ) + return NULL; + strcpy( output, input ); + strcat( output, suffix ); + return output; +} + +void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) +{ + x264_ratecontrol_t *rc = h->rc; + if( !b_init && rc->b_2pass ) + return; + + if( h->param.rc.i_rc_method == X264_RC_CRF ) + { + /* Arbitrary rescaling to make CRF somewhat similar to QP. + * Try to compensate for MB-tree's effects as well. */ + double base_cplx = h->mb.i_mb_count * (h->param.i_bframe ? 120 : 80); + double mbtree_offset = h->param.rc.b_mb_tree ? (1.0-h->param.rc.f_qcompress)*13.5 : 0; + rc->rate_factor_constant = pow( base_cplx, 1 - rc->qcompress ) + / qp2qscale( h->param.rc.f_rf_constant + mbtree_offset + QP_BD_OFFSET ); + } + + if( h->param.rc.i_vbv_max_bitrate > 0 && h->param.rc.i_vbv_buffer_size > 0 ) + { + /* We don't support changing the ABR bitrate right now, + so if the stream starts as CBR, keep it CBR. */ + if( rc->b_vbv_min_rate ) + h->param.rc.i_vbv_max_bitrate = h->param.rc.i_bitrate; + + if( h->param.rc.i_vbv_buffer_size < (int)(h->param.rc.i_vbv_max_bitrate / rc->fps) ) + { + h->param.rc.i_vbv_buffer_size = h->param.rc.i_vbv_max_bitrate / rc->fps; + x264_log( h, X264_LOG_WARNING, "VBV buffer size cannot be smaller than one frame, using %d kbit\n", + h->param.rc.i_vbv_buffer_size ); + } + + int kilobit_size = h->param.i_avcintra_class ? 1024 : 1000; + int vbv_buffer_size = h->param.rc.i_vbv_buffer_size * kilobit_size; + int vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate * kilobit_size; + + /* Init HRD */ + if( h->param.i_nal_hrd && b_init ) + { + h->sps->vui.hrd.i_cpb_cnt = 1; + h->sps->vui.hrd.b_cbr_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR; + h->sps->vui.hrd.i_time_offset_length = 0; + + #define BR_SHIFT 6 + #define CPB_SHIFT 4 + + // normalize HRD size and rate to the value / scale notation + h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( vbv_max_bitrate ) - BR_SHIFT, 0, 15 ); + h->sps->vui.hrd.i_bit_rate_value = vbv_max_bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); + h->sps->vui.hrd.i_bit_rate_unscaled = h->sps->vui.hrd.i_bit_rate_value << ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); + h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( vbv_buffer_size ) - CPB_SHIFT, 0, 15 ); + h->sps->vui.hrd.i_cpb_size_value = vbv_buffer_size >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); + h->sps->vui.hrd.i_cpb_size_unscaled = h->sps->vui.hrd.i_cpb_size_value << ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); + + #undef CPB_SHIFT + #undef BR_SHIFT + + // arbitrary + #define MAX_DURATION 0.5 + + int max_cpb_output_delay = X264_MIN( h->param.i_keyint_max * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick, INT_MAX ); + int max_dpb_output_delay = h->sps->vui.i_max_dec_frame_buffering * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick; + int max_delay = (int)(90000.0 * (double)h->sps->vui.hrd.i_cpb_size_unscaled / h->sps->vui.hrd.i_bit_rate_unscaled + 0.5); + + h->sps->vui.hrd.i_initial_cpb_removal_delay_length = 2 + x264_clip3( 32 - x264_clz( max_delay ), 4, 22 ); + h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb_output_delay ), 4, 31 ); + h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb_output_delay ), 4, 31 ); + + #undef MAX_DURATION + + vbv_buffer_size = h->sps->vui.hrd.i_cpb_size_unscaled; + vbv_max_bitrate = h->sps->vui.hrd.i_bit_rate_unscaled; + } + else if( h->param.i_nal_hrd && !b_init ) + { + x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" ); + return; + } + h->sps->vui.hrd.i_bit_rate_unscaled = vbv_max_bitrate; + h->sps->vui.hrd.i_cpb_size_unscaled = vbv_buffer_size; + + if( rc->b_vbv_min_rate ) + rc->bitrate = (double)h->param.rc.i_bitrate * kilobit_size; + rc->buffer_rate = vbv_max_bitrate / rc->fps; + rc->vbv_max_rate = vbv_max_bitrate; + rc->buffer_size = vbv_buffer_size; + rc->single_frame_vbv = rc->buffer_rate * 1.1 > rc->buffer_size; + rc->cbr_decay = 1.0 - rc->buffer_rate / rc->buffer_size + * 0.5 * X264_MAX(0, 1.5 - rc->buffer_rate * rc->fps / rc->bitrate); + if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.f_rf_constant_max ) + { + rc->rate_factor_max_increment = h->param.rc.f_rf_constant_max - h->param.rc.f_rf_constant; + if( rc->rate_factor_max_increment <= 0 ) + { + x264_log( h, X264_LOG_WARNING, "CRF max must be greater than CRF\n" ); + rc->rate_factor_max_increment = 0; + } + } + if( b_init ) + { + if( h->param.rc.f_vbv_buffer_init > 1. ) + h->param.rc.f_vbv_buffer_init = x264_clip3f( h->param.rc.f_vbv_buffer_init / h->param.rc.i_vbv_buffer_size, 0, 1 ); + h->param.rc.f_vbv_buffer_init = x264_clip3f( X264_MAX( h->param.rc.f_vbv_buffer_init, rc->buffer_rate / rc->buffer_size ), 0, 1); + rc->buffer_fill_final = + rc->buffer_fill_final_min = rc->buffer_size * h->param.rc.f_vbv_buffer_init * h->sps->vui.i_time_scale; + rc->b_vbv = 1; + rc->b_vbv_min_rate = !rc->b_2pass + && h->param.rc.i_rc_method == X264_RC_ABR + && h->param.rc.i_vbv_max_bitrate <= h->param.rc.i_bitrate; + } + } +} + +int x264_ratecontrol_new( x264_t *h ) +{ + x264_ratecontrol_t *rc; + + x264_emms(); + + CHECKED_MALLOCZERO( h->rc, h->param.i_threads * sizeof(x264_ratecontrol_t) ); + rc = h->rc; + + rc->b_abr = h->param.rc.i_rc_method != X264_RC_CQP && !h->param.rc.b_stat_read; + rc->b_2pass = h->param.rc.i_rc_method == X264_RC_ABR && h->param.rc.b_stat_read; + + /* FIXME: use integers */ + if( h->param.i_fps_num > 0 && h->param.i_fps_den > 0 ) + rc->fps = (float) h->param.i_fps_num / h->param.i_fps_den; + else + rc->fps = 25.0; + + if( h->param.rc.b_mb_tree ) + { + h->param.rc.f_pb_factor = 1; + rc->qcompress = 1; + } + else + rc->qcompress = h->param.rc.f_qcompress; + + rc->bitrate = h->param.rc.i_bitrate * (h->param.i_avcintra_class ? 1024. : 1000.); + rc->rate_tolerance = h->param.rc.f_rate_tolerance; + rc->nmb = h->mb.i_mb_count; + rc->last_non_b_pict_type = -1; + rc->cbr_decay = 1.0; + + if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.b_stat_read ) + { + x264_log( h, X264_LOG_ERROR, "constant rate-factor is incompatible with 2pass.\n" ); + return -1; + } + + x264_ratecontrol_init_reconfigurable( h, 1 ); + + if( h->param.i_nal_hrd ) + { + uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale; + uint64_t num = 90000; + x264_reduce_fraction64( &num, &denom ); + rc->hrd_multiply_denom = 90000 / num; + + double bits_required = log2( num ) + + log2( h->sps->vui.i_time_scale ) + + log2( h->sps->vui.hrd.i_cpb_size_unscaled ); + if( bits_required >= 63 ) + { + x264_log( h, X264_LOG_ERROR, "HRD with very large timescale and bufsize not supported\n" ); + return -1; + } + } + + if( rc->rate_tolerance < 0.01 ) + { + x264_log( h, X264_LOG_WARNING, "bitrate tolerance too small, using .01\n" ); + rc->rate_tolerance = 0.01; + } + + h->mb.b_variable_qp = rc->b_vbv || h->param.rc.i_aq_mode; + + if( rc->b_abr ) + { + /* FIXME ABR_INIT_QP is actually used only in CRF */ +#define ABR_INIT_QP (( h->param.rc.i_rc_method == X264_RC_CRF ? h->param.rc.f_rf_constant : 24 ) + QP_BD_OFFSET) + rc->accum_p_norm = .01; + rc->accum_p_qp = ABR_INIT_QP * rc->accum_p_norm; + /* estimated ratio that produces a reasonable QP for the first I-frame */ + rc->cplxr_sum = .01 * pow( 7.0e5, rc->qcompress ) * pow( h->mb.i_mb_count, 0.5 ); + rc->wanted_bits_window = 1.0 * rc->bitrate / rc->fps; + rc->last_non_b_pict_type = SLICE_TYPE_I; + } + + rc->ip_offset = 6.0 * log2f( h->param.rc.f_ip_factor ); + rc->pb_offset = 6.0 * log2f( h->param.rc.f_pb_factor ); + rc->qp_constant[SLICE_TYPE_P] = h->param.rc.i_qp_constant; + rc->qp_constant[SLICE_TYPE_I] = x264_clip3( h->param.rc.i_qp_constant - rc->ip_offset + 0.5, 0, QP_MAX ); + rc->qp_constant[SLICE_TYPE_B] = x264_clip3( h->param.rc.i_qp_constant + rc->pb_offset + 0.5, 0, QP_MAX ); + h->mb.ip_offset = rc->ip_offset + 0.5; + + rc->lstep = pow( 2, h->param.rc.i_qp_step / 6.0 ); + rc->last_qscale = qp2qscale( 26 + QP_BD_OFFSET ); + int num_preds = h->param.b_sliced_threads * h->param.i_threads + 1; + CHECKED_MALLOC( rc->pred, 5 * sizeof(predictor_t) * num_preds ); + CHECKED_MALLOC( rc->pred_b_from_p, sizeof(predictor_t) ); + static const float pred_coeff_table[3] = { 1.0, 1.0, 1.5 }; + for( int i = 0; i < 3; i++ ) + { + rc->last_qscale_for[i] = qp2qscale( ABR_INIT_QP ); + rc->lmin[i] = qp2qscale( h->param.rc.i_qp_min ); + rc->lmax[i] = qp2qscale( h->param.rc.i_qp_max ); + for( int j = 0; j < num_preds; j++ ) + { + rc->pred[i+j*5].coeff_min = pred_coeff_table[i] / 2; + rc->pred[i+j*5].coeff = pred_coeff_table[i]; + rc->pred[i+j*5].count = 1.0; + rc->pred[i+j*5].decay = 0.5; + rc->pred[i+j*5].offset = 0.0; + } + for( int j = 0; j < 2; j++ ) + { + rc->row_preds[i][j].coeff_min = .25 / 4; + rc->row_preds[i][j].coeff = .25; + rc->row_preds[i][j].count = 1.0; + rc->row_preds[i][j].decay = 0.5; + rc->row_preds[i][j].offset = 0.0; + } + } + rc->pred_b_from_p->coeff_min = 0.5 / 2; + rc->pred_b_from_p->coeff = 0.5; + rc->pred_b_from_p->count = 1.0; + rc->pred_b_from_p->decay = 0.5; + rc->pred_b_from_p->offset = 0.0; + + if( parse_zones( h ) < 0 ) + { + x264_log( h, X264_LOG_ERROR, "failed to parse zones\n" ); + return -1; + } + + /* Load stat file and init 2pass algo */ + if( h->param.rc.b_stat_read ) + { + char *p, *stats_in, *stats_buf; + + /* read 1st pass stats */ + assert( h->param.rc.psz_stat_in ); + stats_buf = stats_in = x264_slurp_file( h->param.rc.psz_stat_in ); + if( !stats_buf ) + { + x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open stats file\n" ); + return -1; + } + if( h->param.rc.b_mb_tree ) + { + char *mbtree_stats_in = x264_strcat_filename( h->param.rc.psz_stat_in, ".mbtree" ); + if( !mbtree_stats_in ) + return -1; + rc->p_mbtree_stat_file_in = x264_fopen( mbtree_stats_in, "rb" ); + x264_free( mbtree_stats_in ); + if( !rc->p_mbtree_stat_file_in ) + { + x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open mbtree stats file\n" ); + return -1; + } + } + + /* check whether 1st pass options were compatible with current options */ + if( strncmp( stats_buf, "#options:", 9 ) ) + { + x264_log( h, X264_LOG_ERROR, "options list in stats file not valid\n" ); + return -1; + } + + float res_factor, res_factor_bits; + { + int i, j; + uint32_t k, l; + char *opts = stats_buf; + stats_in = strchr( stats_buf, '\n' ); + if( !stats_in ) + return -1; + *stats_in = '\0'; + stats_in++; + if( sscanf( opts, "#options: %dx%d", &i, &j ) != 2 ) + { + x264_log( h, X264_LOG_ERROR, "resolution specified in stats file not valid\n" ); + return -1; + } + else if( h->param.rc.b_mb_tree ) + { + rc->mbtree.srcdim[0] = i; + rc->mbtree.srcdim[1] = j; + } + res_factor = (float)h->param.i_width * h->param.i_height / (i*j); + /* Change in bits relative to resolution isn't quite linear on typical sources, + * so we'll at least try to roughly approximate this effect. */ + res_factor_bits = powf( res_factor, 0.7 ); + + if( !( p = strstr( opts, "timebase=" ) ) || sscanf( p, "timebase=%u/%u", &k, &l ) != 2 ) + { + x264_log( h, X264_LOG_ERROR, "timebase specified in stats file not valid\n" ); + return -1; + } + if( k != h->param.i_timebase_num || l != h->param.i_timebase_den ) + { + x264_log( h, X264_LOG_ERROR, "timebase mismatch with 1st pass (%u/%u vs %u/%u)\n", + h->param.i_timebase_num, h->param.i_timebase_den, k, l ); + return -1; + } + + CMP_OPT_FIRST_PASS( "bitdepth", BIT_DEPTH ); + CMP_OPT_FIRST_PASS( "weightp", X264_MAX( 0, h->param.analyse.i_weighted_pred ) ); + CMP_OPT_FIRST_PASS( "bframes", h->param.i_bframe ); + CMP_OPT_FIRST_PASS( "b_pyramid", h->param.i_bframe_pyramid ); + CMP_OPT_FIRST_PASS( "intra_refresh", h->param.b_intra_refresh ); + CMP_OPT_FIRST_PASS( "open_gop", h->param.b_open_gop ); + CMP_OPT_FIRST_PASS( "bluray_compat", h->param.b_bluray_compat ); + + if( (p = strstr( opts, "interlaced=" )) ) + { + char *current = h->param.b_interlaced ? h->param.b_tff ? "tff" : "bff" : h->param.b_fake_interlaced ? "fake" : "0"; + char buf[5]; + sscanf( p, "interlaced=%4s", buf ); + if( strcmp( current, buf ) ) + { + x264_log( h, X264_LOG_ERROR, "different interlaced setting than first pass (%s vs %s)\n", current, buf ); + return -1; + } + } + + if( (p = strstr( opts, "keyint=" )) ) + { + p += 7; + char buf[13] = "infinite "; + if( h->param.i_keyint_max != X264_KEYINT_MAX_INFINITE ) + sprintf( buf, "%d ", h->param.i_keyint_max ); + if( strncmp( p, buf, strlen(buf) ) ) + { + x264_log( h, X264_LOG_ERROR, "different keyint setting than first pass (%.*s vs %.*s)\n", + strlen(buf)-1, buf, strcspn(p, " "), p ); + return -1; + } + } + + if( strstr( opts, "qp=0" ) && h->param.rc.i_rc_method == X264_RC_ABR ) + x264_log( h, X264_LOG_WARNING, "1st pass was lossless, bitrate prediction will be inaccurate\n" ); + + if( !strstr( opts, "direct=3" ) && h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO ) + { + x264_log( h, X264_LOG_WARNING, "direct=auto not used on the first pass\n" ); + h->mb.b_direct_auto_write = 1; + } + + if( ( p = strstr( opts, "b_adapt=" ) ) && sscanf( p, "b_adapt=%d", &i ) && i >= X264_B_ADAPT_NONE && i <= X264_B_ADAPT_TRELLIS ) + h->param.i_bframe_adaptive = i; + else if( h->param.i_bframe ) + { + x264_log( h, X264_LOG_ERROR, "b_adapt method specified in stats file not valid\n" ); + return -1; + } + + if( (h->param.rc.b_mb_tree || h->param.rc.i_vbv_buffer_size) && ( p = strstr( opts, "rc_lookahead=" ) ) && sscanf( p, "rc_lookahead=%d", &i ) ) + h->param.rc.i_lookahead = i; + } + + /* find number of pics */ + p = stats_in; + int num_entries; + for( num_entries = -1; p; num_entries++ ) + p = strchr( p + 1, ';' ); + if( !num_entries ) + { + x264_log( h, X264_LOG_ERROR, "empty stats file\n" ); + return -1; + } + rc->num_entries = num_entries; + + if( h->param.i_frame_total < rc->num_entries && h->param.i_frame_total > 0 ) + { + x264_log( h, X264_LOG_WARNING, "2nd pass has fewer frames than 1st pass (%d vs %d)\n", + h->param.i_frame_total, rc->num_entries ); + } + if( h->param.i_frame_total > rc->num_entries ) + { + x264_log( h, X264_LOG_ERROR, "2nd pass has more frames than 1st pass (%d vs %d)\n", + h->param.i_frame_total, rc->num_entries ); + return -1; + } + + CHECKED_MALLOCZERO( rc->entry, rc->num_entries * sizeof(ratecontrol_entry_t) ); + CHECKED_MALLOC( rc->entry_out, rc->num_entries * sizeof(ratecontrol_entry_t*) ); + + /* init all to skipped p frames */ + for( int i = 0; i < rc->num_entries; i++ ) + { + ratecontrol_entry_t *rce = &rc->entry[i]; + rce->pict_type = SLICE_TYPE_P; + rce->qscale = rce->new_qscale = qp2qscale( 20 + QP_BD_OFFSET ); + rce->misc_bits = rc->nmb + 10; + rce->new_qp = 0; + rc->entry_out[i] = rce; + } + + /* read stats */ + p = stats_in; + double total_qp_aq = 0; + for( int i = 0; i < rc->num_entries; i++ ) + { + ratecontrol_entry_t *rce; + int frame_number = 0; + int frame_out_number = 0; + char pict_type = 0; + int e; + char *next; + float qp_rc, qp_aq; + int ref; + + next= strchr(p, ';'); + if( next ) + *next++ = 0; //sscanf is unbelievably slow on long strings + e = sscanf( p, " in:%d out:%d ", &frame_number, &frame_out_number ); + + if( frame_number < 0 || frame_number >= rc->num_entries ) + { + x264_log( h, X264_LOG_ERROR, "bad frame number (%d) at stats line %d\n", frame_number, i ); + return -1; + } + if( frame_out_number < 0 || frame_out_number >= rc->num_entries ) + { + x264_log( h, X264_LOG_ERROR, "bad frame output number (%d) at stats line %d\n", frame_out_number, i ); + return -1; + } + rce = &rc->entry[frame_number]; + rc->entry_out[frame_out_number] = rce; + rce->direct_mode = 0; + + e += sscanf( p, " in:%*d out:%*d type:%c dur:%"SCNd64" cpbdur:%"SCNd64" q:%f aq:%f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c", + &pict_type, &rce->i_duration, &rce->i_cpb_duration, &qp_rc, &qp_aq, &rce->tex_bits, + &rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count, + &rce->s_count, &rce->direct_mode ); + rce->tex_bits *= res_factor_bits; + rce->mv_bits *= res_factor_bits; + rce->misc_bits *= res_factor_bits; + rce->i_count *= res_factor; + rce->p_count *= res_factor; + rce->s_count *= res_factor; + + p = strstr( p, "ref:" ); + if( !p ) + goto parse_error; + p += 4; + for( ref = 0; ref < 16; ref++ ) + { + if( sscanf( p, " %d", &rce->refcount[ref] ) != 1 ) + break; + p = strchr( p+1, ' ' ); + if( !p ) + goto parse_error; + } + rce->refs = ref; + + /* find weights */ + rce->i_weight_denom[0] = rce->i_weight_denom[1] = -1; + char *w = strchr( p, 'w' ); + if( w ) + { + int count = sscanf( w, "w:%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd", + &rce->i_weight_denom[0], &rce->weight[0][0], &rce->weight[0][1], + &rce->i_weight_denom[1], &rce->weight[1][0], &rce->weight[1][1], + &rce->weight[2][0], &rce->weight[2][1] ); + if( count == 3 ) + rce->i_weight_denom[1] = -1; + else if( count != 8 ) + rce->i_weight_denom[0] = rce->i_weight_denom[1] = -1; + } + + if( pict_type != 'b' ) + rce->kept_as_ref = 1; + switch( pict_type ) + { + case 'I': + rce->frame_type = X264_TYPE_IDR; + rce->pict_type = SLICE_TYPE_I; + break; + case 'i': + rce->frame_type = X264_TYPE_I; + rce->pict_type = SLICE_TYPE_I; + break; + case 'P': + rce->frame_type = X264_TYPE_P; + rce->pict_type = SLICE_TYPE_P; + break; + case 'B': + rce->frame_type = X264_TYPE_BREF; + rce->pict_type = SLICE_TYPE_B; + break; + case 'b': + rce->frame_type = X264_TYPE_B; + rce->pict_type = SLICE_TYPE_B; + break; + default: e = -1; break; + } + if( e < 14 ) + { +parse_error: + x264_log( h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e ); + return -1; + } + rce->qscale = qp2qscale( qp_rc ); + total_qp_aq += qp_aq; + p = next; + } + if( !h->param.b_stitchable ) + h->pps->i_pic_init_qp = SPEC_QP( (int)(total_qp_aq / rc->num_entries + 0.5) ); + + x264_free( stats_buf ); + + if( h->param.rc.i_rc_method == X264_RC_ABR ) + { + if( init_pass2( h ) < 0 ) + return -1; + } /* else we're using constant quant, so no need to run the bitrate allocation */ + } + + /* Open output file */ + /* If input and output files are the same, output to a temp file + * and move it to the real name only when it's complete */ + if( h->param.rc.b_stat_write ) + { + char *p; + rc->psz_stat_file_tmpname = x264_strcat_filename( h->param.rc.psz_stat_out, ".temp" ); + if( !rc->psz_stat_file_tmpname ) + return -1; + + rc->p_stat_file_out = x264_fopen( rc->psz_stat_file_tmpname, "wb" ); + if( rc->p_stat_file_out == NULL ) + { + x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open stats file\n" ); + return -1; + } + + p = x264_param2string( &h->param, 1 ); + if( p ) + fprintf( rc->p_stat_file_out, "#options: %s\n", p ); + x264_free( p ); + if( h->param.rc.b_mb_tree && !h->param.rc.b_stat_read ) + { + rc->psz_mbtree_stat_file_tmpname = x264_strcat_filename( h->param.rc.psz_stat_out, ".mbtree.temp" ); + rc->psz_mbtree_stat_file_name = x264_strcat_filename( h->param.rc.psz_stat_out, ".mbtree" ); + if( !rc->psz_mbtree_stat_file_tmpname || !rc->psz_mbtree_stat_file_name ) + return -1; + + rc->p_mbtree_stat_file_out = x264_fopen( rc->psz_mbtree_stat_file_tmpname, "wb" ); + if( rc->p_mbtree_stat_file_out == NULL ) + { + x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open mbtree stats file\n" ); + return -1; + } + } + } + + if( h->param.rc.b_mb_tree && (h->param.rc.b_stat_read || h->param.rc.b_stat_write) ) + { + if( !h->param.rc.b_stat_read ) + { + rc->mbtree.srcdim[0] = h->param.i_width; + rc->mbtree.srcdim[1] = h->param.i_height; + } + if( x264_macroblock_tree_rescale_init( h, rc ) < 0 ) + return -1; + } + + for( int i = 0; iparam.i_threads; i++ ) + { + h->thread[i]->rc = rc+i; + if( i ) + { + rc[i] = rc[0]; + h->thread[i]->param = h->param; + h->thread[i]->mb.b_variable_qp = h->mb.b_variable_qp; + h->thread[i]->mb.ip_offset = h->mb.ip_offset; + } + } + + return 0; +fail: + return -1; +} + +static int parse_zone( x264_t *h, x264_zone_t *z, char *p ) +{ + int len = 0; + char *tok, UNUSED *saveptr=NULL; + z->param = NULL; + z->f_bitrate_factor = 1; + if( 3 <= sscanf(p, "%d,%d,q=%d%n", &z->i_start, &z->i_end, &z->i_qp, &len) ) + z->b_force_qp = 1; + else if( 3 <= sscanf(p, "%d,%d,b=%f%n", &z->i_start, &z->i_end, &z->f_bitrate_factor, &len) ) + z->b_force_qp = 0; + else if( 2 <= sscanf(p, "%d,%d%n", &z->i_start, &z->i_end, &len) ) + z->b_force_qp = 0; + else + { + x264_log( h, X264_LOG_ERROR, "invalid zone: \"%s\"\n", p ); + return -1; + } + p += len; + if( !*p ) + return 0; + CHECKED_MALLOC( z->param, sizeof(x264_param_t) ); + memcpy( z->param, &h->param, sizeof(x264_param_t) ); + z->param->param_free = x264_free; + while( (tok = strtok_r( p, ",", &saveptr )) ) + { + char *val = strchr( tok, '=' ); + if( val ) + { + *val = '\0'; + val++; + } + if( x264_param_parse( z->param, tok, val ) ) + { + x264_log( h, X264_LOG_ERROR, "invalid zone param: %s = %s\n", tok, val ); + return -1; + } + p = NULL; + } + return 0; +fail: + return -1; +} + +static int parse_zones( x264_t *h ) +{ + x264_ratecontrol_t *rc = h->rc; + if( h->param.rc.psz_zones && !h->param.rc.i_zones ) + { + char *psz_zones, *p; + CHECKED_MALLOC( psz_zones, strlen( h->param.rc.psz_zones )+1 ); + strcpy( psz_zones, h->param.rc.psz_zones ); + h->param.rc.i_zones = 1; + for( p = psz_zones; *p; p++ ) + h->param.rc.i_zones += (*p == '/'); + CHECKED_MALLOC( h->param.rc.zones, h->param.rc.i_zones * sizeof(x264_zone_t) ); + p = psz_zones; + for( int i = 0; i < h->param.rc.i_zones; i++ ) + { + int i_tok = strcspn( p, "/" ); + p[i_tok] = 0; + if( parse_zone( h, &h->param.rc.zones[i], p ) ) + { + x264_free( psz_zones ); + return -1; + } + p += i_tok + 1; + } + x264_free( psz_zones ); + } + + if( h->param.rc.i_zones > 0 ) + { + for( int i = 0; i < h->param.rc.i_zones; i++ ) + { + x264_zone_t z = h->param.rc.zones[i]; + if( z.i_start < 0 || z.i_start > z.i_end ) + { + x264_log( h, X264_LOG_ERROR, "invalid zone: start=%d end=%d\n", + z.i_start, z.i_end ); + return -1; + } + else if( !z.b_force_qp && z.f_bitrate_factor <= 0 ) + { + x264_log( h, X264_LOG_ERROR, "invalid zone: bitrate_factor=%f\n", + z.f_bitrate_factor ); + return -1; + } + } + + rc->i_zones = h->param.rc.i_zones + 1; + CHECKED_MALLOC( rc->zones, rc->i_zones * sizeof(x264_zone_t) ); + memcpy( rc->zones+1, h->param.rc.zones, (rc->i_zones-1) * sizeof(x264_zone_t) ); + + // default zone to fall back to if none of the others match + rc->zones[0].i_start = 0; + rc->zones[0].i_end = INT_MAX; + rc->zones[0].b_force_qp = 0; + rc->zones[0].f_bitrate_factor = 1; + CHECKED_MALLOC( rc->zones[0].param, sizeof(x264_param_t) ); + memcpy( rc->zones[0].param, &h->param, sizeof(x264_param_t) ); + for( int i = 1; i < rc->i_zones; i++ ) + { + if( !rc->zones[i].param ) + rc->zones[i].param = rc->zones[0].param; + } + } + + return 0; +fail: + return -1; +} + +static x264_zone_t *get_zone( x264_t *h, int frame_num ) +{ + for( int i = h->rc->i_zones - 1; i >= 0; i-- ) + { + x264_zone_t *z = &h->rc->zones[i]; + if( frame_num >= z->i_start && frame_num <= z->i_end ) + return z; + } + return NULL; +} + +void x264_ratecontrol_summary( x264_t *h ) +{ + x264_ratecontrol_t *rc = h->rc; + if( rc->b_abr && h->param.rc.i_rc_method == X264_RC_ABR && rc->cbr_decay > .9999 ) + { + double base_cplx = h->mb.i_mb_count * (h->param.i_bframe ? 120 : 80); + double mbtree_offset = h->param.rc.b_mb_tree ? (1.0-h->param.rc.f_qcompress)*13.5 : 0; + x264_log( h, X264_LOG_INFO, "final ratefactor: %.2f\n", + qscale2qp( pow( base_cplx, 1 - rc->qcompress ) + * rc->cplxr_sum / rc->wanted_bits_window ) - mbtree_offset - QP_BD_OFFSET ); + } +} + +void x264_ratecontrol_delete( x264_t *h ) +{ + x264_ratecontrol_t *rc = h->rc; + int b_regular_file; + + if( rc->p_stat_file_out ) + { + b_regular_file = x264_is_regular_file( rc->p_stat_file_out ); + fclose( rc->p_stat_file_out ); + if( h->i_frame >= rc->num_entries && b_regular_file ) + if( x264_rename( rc->psz_stat_file_tmpname, h->param.rc.psz_stat_out ) != 0 ) + { + x264_log( h, X264_LOG_ERROR, "failed to rename \"%s\" to \"%s\"\n", + rc->psz_stat_file_tmpname, h->param.rc.psz_stat_out ); + } + x264_free( rc->psz_stat_file_tmpname ); + } + if( rc->p_mbtree_stat_file_out ) + { + b_regular_file = x264_is_regular_file( rc->p_mbtree_stat_file_out ); + fclose( rc->p_mbtree_stat_file_out ); + if( h->i_frame >= rc->num_entries && b_regular_file ) + if( x264_rename( rc->psz_mbtree_stat_file_tmpname, rc->psz_mbtree_stat_file_name ) != 0 ) + { + x264_log( h, X264_LOG_ERROR, "failed to rename \"%s\" to \"%s\"\n", + rc->psz_mbtree_stat_file_tmpname, rc->psz_mbtree_stat_file_name ); + } + x264_free( rc->psz_mbtree_stat_file_tmpname ); + x264_free( rc->psz_mbtree_stat_file_name ); + } + if( rc->p_mbtree_stat_file_in ) + fclose( rc->p_mbtree_stat_file_in ); + x264_free( rc->pred ); + x264_free( rc->pred_b_from_p ); + x264_free( rc->entry ); + x264_free( rc->entry_out ); + x264_macroblock_tree_rescale_destroy( rc ); + if( rc->zones ) + { + x264_free( rc->zones[0].param ); + for( int i = 1; i < rc->i_zones; i++ ) + if( rc->zones[i].param != rc->zones[0].param && rc->zones[i].param->param_free ) + rc->zones[i].param->param_free( rc->zones[i].param ); + x264_free( rc->zones ); + } + x264_free( rc ); +} + +static void accum_p_qp_update( x264_t *h, float qp ) +{ + x264_ratecontrol_t *rc = h->rc; + rc->accum_p_qp *= .95; + rc->accum_p_norm *= .95; + rc->accum_p_norm += 1; + if( h->sh.i_type == SLICE_TYPE_I ) + rc->accum_p_qp += qp + rc->ip_offset; + else + rc->accum_p_qp += qp; +} + +void x264_ratecontrol_zone_init( x264_t *h ) +{ + x264_ratecontrol_t *rc = h->rc; + x264_zone_t *zone = get_zone( h, h->fenc->i_frame ); + if( zone && (!rc->prev_zone || zone->param != rc->prev_zone->param) ) + x264_encoder_reconfig_apply( h, zone->param ); + rc->prev_zone = zone; +} + +/* Before encoding a frame, choose a QP for it */ +void x264_ratecontrol_start( x264_t *h, int i_force_qp, int overhead ) +{ + x264_ratecontrol_t *rc = h->rc; + ratecontrol_entry_t *rce = NULL; + x264_zone_t *zone = get_zone( h, h->fenc->i_frame ); + float q; + + x264_emms(); + + if( h->param.rc.b_stat_read ) + { + int frame = h->fenc->i_frame; + assert( frame >= 0 && frame < rc->num_entries ); + rce = h->rc->rce = &h->rc->entry[frame]; + + if( h->sh.i_type == SLICE_TYPE_B + && h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO ) + { + h->sh.b_direct_spatial_mv_pred = ( rce->direct_mode == 's' ); + h->mb.b_direct_auto_read = ( rce->direct_mode == 's' || rce->direct_mode == 't' ); + } + } + + if( rc->b_vbv ) + { + memset( h->fdec->i_row_bits, 0, h->mb.i_mb_height * sizeof(int) ); + memset( h->fdec->f_row_qp, 0, h->mb.i_mb_height * sizeof(float) ); + memset( h->fdec->f_row_qscale, 0, h->mb.i_mb_height * sizeof(float) ); + rc->row_pred = rc->row_preds[h->sh.i_type]; + rc->buffer_rate = h->fenc->i_cpb_duration * rc->vbv_max_rate * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + update_vbv_plan( h, overhead ); + + const x264_level_t *l = x264_levels; + while( l->level_idc != 0 && l->level_idc != h->param.i_level_idc ) + l++; + + int mincr = l->mincr; + + if( h->param.b_bluray_compat ) + mincr = 4; + + /* Profiles above High don't require minCR, so just set the maximum to a large value. */ + if( h->sps->i_profile_idc > PROFILE_HIGH ) + rc->frame_size_maximum = 1e9; + else + { + /* The spec has a bizarre special case for the first frame. */ + if( h->i_frame == 0 ) + { + //384 * ( Max( PicSizeInMbs, fR * MaxMBPS ) + MaxMBPS * ( tr( 0 ) - tr,n( 0 ) ) ) / MinCR + double fr = 1. / (h->param.i_level_idc >= 60 ? 300 : 172); + int pic_size_in_mbs = h->mb.i_mb_width * h->mb.i_mb_height; + rc->frame_size_maximum = 384 * BIT_DEPTH * X264_MAX( pic_size_in_mbs, fr*l->mbps ) / mincr; + } + else + { + //384 * MaxMBPS * ( tr( n ) - tr( n - 1 ) ) / MinCR + rc->frame_size_maximum = 384 * BIT_DEPTH * ((double)h->fenc->i_cpb_duration * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale) * l->mbps / mincr; + } + } + } + + if( h->sh.i_type != SLICE_TYPE_B ) + rc->bframes = h->fenc->i_bframes; + + if( rc->b_abr ) + { + q = qscale2qp( rate_estimate_qscale( h ) ); + } + else if( rc->b_2pass ) + { + rce->new_qscale = rate_estimate_qscale( h ); + q = qscale2qp( rce->new_qscale ); + } + else /* CQP */ + { + if( h->sh.i_type == SLICE_TYPE_B && h->fdec->b_kept_as_ref ) + q = ( rc->qp_constant[ SLICE_TYPE_B ] + rc->qp_constant[ SLICE_TYPE_P ] ) / 2; + else + q = rc->qp_constant[ h->sh.i_type ]; + + if( zone ) + { + if( zone->b_force_qp ) + q += zone->i_qp - rc->qp_constant[SLICE_TYPE_P]; + else + q -= 6*log2f( zone->f_bitrate_factor ); + } + } + if( i_force_qp != X264_QP_AUTO ) + q = i_force_qp - 1; + + q = x264_clip3f( q, h->param.rc.i_qp_min, h->param.rc.i_qp_max ); + + rc->qpa_rc = rc->qpa_rc_prev = + rc->qpa_aq = rc->qpa_aq_prev = 0; + h->fdec->f_qp_avg_rc = + h->fdec->f_qp_avg_aq = + rc->qpm = q; + if( rce ) + rce->new_qp = q; + + accum_p_qp_update( h, rc->qpm ); + + if( h->sh.i_type != SLICE_TYPE_B ) + rc->last_non_b_pict_type = h->sh.i_type; +} + +static float predict_row_size( x264_t *h, int y, float qscale ) +{ + /* average between two predictors: + * absolute SATD, and scaled bit cost of the colocated row in the previous frame */ + x264_ratecontrol_t *rc = h->rc; + float pred_s = predict_size( &rc->row_pred[0], qscale, h->fdec->i_row_satd[y] ); + if( h->sh.i_type == SLICE_TYPE_I || qscale >= h->fref[0][0]->f_row_qscale[y] ) + { + if( h->sh.i_type == SLICE_TYPE_P + && h->fref[0][0]->i_type == h->fdec->i_type + && h->fref[0][0]->f_row_qscale[y] > 0 + && h->fref[0][0]->i_row_satd[y] > 0 + && (abs(h->fref[0][0]->i_row_satd[y] - h->fdec->i_row_satd[y]) < h->fdec->i_row_satd[y]/2)) + { + float pred_t = h->fref[0][0]->i_row_bits[y] * h->fdec->i_row_satd[y] / h->fref[0][0]->i_row_satd[y] + * h->fref[0][0]->f_row_qscale[y] / qscale; + return (pred_s + pred_t) * 0.5f; + } + return pred_s; + } + /* Our QP is lower than the reference! */ + else + { + float pred_intra = predict_size( &rc->row_pred[1], qscale, h->fdec->i_row_satds[0][0][y] ); + /* Sum: better to overestimate than underestimate by using only one of the two predictors. */ + return pred_intra + pred_s; + } +} + +static int row_bits_so_far( x264_t *h, int y ) +{ + int bits = 0; + for( int i = h->i_threadslice_start; i <= y; i++ ) + bits += h->fdec->i_row_bits[i]; + return bits; +} + +static float predict_row_size_to_end( x264_t *h, int y, float qp ) +{ + float qscale = qp2qscale( qp ); + float bits = 0; + for( int i = y+1; i < h->i_threadslice_end; i++ ) + bits += predict_row_size( h, i, qscale ); + return bits; +} + +/* TODO: + * eliminate all use of qp in row ratecontrol: make it entirely qscale-based. + * make this function stop being needlessly O(N^2) + * update more often than once per row? */ +int x264_ratecontrol_mb( x264_t *h, int bits ) +{ + x264_ratecontrol_t *rc = h->rc; + const int y = h->mb.i_mb_y; + + h->fdec->i_row_bits[y] += bits; + rc->qpa_aq += h->mb.i_qp; + + if( h->mb.i_mb_x != h->mb.i_mb_width - 1 ) + return 0; + + x264_emms(); + rc->qpa_rc += rc->qpm * h->mb.i_mb_width; + + if( !rc->b_vbv ) + return 0; + + float qscale = qp2qscale( rc->qpm ); + h->fdec->f_row_qp[y] = rc->qpm; + h->fdec->f_row_qscale[y] = qscale; + + update_predictor( &rc->row_pred[0], qscale, h->fdec->i_row_satd[y], h->fdec->i_row_bits[y] ); + if( h->sh.i_type != SLICE_TYPE_I && rc->qpm < h->fref[0][0]->f_row_qp[y] ) + update_predictor( &rc->row_pred[1], qscale, h->fdec->i_row_satds[0][0][y], h->fdec->i_row_bits[y] ); + + /* update ratecontrol per-mbpair in MBAFF */ + if( SLICE_MBAFF && !(y&1) ) + return 0; + + /* FIXME: We don't currently support the case where there's a slice + * boundary in between. */ + int can_reencode_row = h->sh.i_first_mb <= ((h->mb.i_mb_y - SLICE_MBAFF) * h->mb.i_mb_stride); + + /* tweak quality based on difference from predicted size */ + float prev_row_qp = h->fdec->f_row_qp[y]; + float qp_absolute_max = h->param.rc.i_qp_max; + if( rc->rate_factor_max_increment ) + qp_absolute_max = X264_MIN( qp_absolute_max, rc->qp_novbv + rc->rate_factor_max_increment ); + float qp_max = X264_MIN( prev_row_qp + h->param.rc.i_qp_step, qp_absolute_max ); + float qp_min = X264_MAX( prev_row_qp - h->param.rc.i_qp_step, h->param.rc.i_qp_min ); + float step_size = 0.5f; + float slice_size_planned = h->param.b_sliced_threads ? rc->slice_size_planned : rc->frame_size_planned; + float bits_so_far = row_bits_so_far( h, y ); + float max_frame_error = x264_clip3f( 1.0 / h->mb.i_mb_height, 0.05, 0.25 ); + float max_frame_size = rc->frame_size_maximum - rc->frame_size_maximum * max_frame_error; + max_frame_size = X264_MIN( max_frame_size, rc->buffer_fill - rc->buffer_rate * max_frame_error ); + float size_of_other_slices = 0; + if( h->param.b_sliced_threads ) + { + float size_of_other_slices_planned = 0; + for( int i = 0; i < h->param.i_threads; i++ ) + if( h != h->thread[i] ) + { + size_of_other_slices += h->thread[i]->rc->frame_size_estimated; + size_of_other_slices_planned += h->thread[i]->rc->slice_size_planned; + } + float weight = rc->slice_size_planned / rc->frame_size_planned; + size_of_other_slices = (size_of_other_slices - size_of_other_slices_planned) * weight + size_of_other_slices_planned; + } + if( y < h->i_threadslice_end-1 ) + { + /* B-frames shouldn't use lower QP than their reference frames. */ + if( h->sh.i_type == SLICE_TYPE_B ) + { + qp_min = X264_MAX( qp_min, X264_MAX( h->fref[0][0]->f_row_qp[y+1], h->fref[1][0]->f_row_qp[y+1] ) ); + rc->qpm = X264_MAX( rc->qpm, qp_min ); + } + + float buffer_left_planned = rc->buffer_fill - rc->frame_size_planned; + buffer_left_planned = X264_MAX( buffer_left_planned, 0.f ); + /* More threads means we have to be more cautious in letting ratecontrol use up extra bits. */ + float rc_tol = buffer_left_planned / h->param.i_threads * rc->rate_tolerance; + float b1 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices; + float trust_coeff = x264_clip3f( bits_so_far / slice_size_planned, 0.0, 1.0 ); + + /* Don't increase the row QPs until a sufficent amount of the bits of the frame have been processed, in case a flat */ + /* area at the top of the frame was measured inaccurately. */ + if( trust_coeff < 0.05f ) + qp_max = qp_absolute_max = prev_row_qp; + + if( h->sh.i_type != SLICE_TYPE_I ) + rc_tol *= 0.5f; + + if( !rc->b_vbv_min_rate ) + qp_min = X264_MAX( qp_min, rc->qp_novbv ); + + while( rc->qpm < qp_max + && ((b1 > rc->frame_size_planned + rc_tol) || + (b1 > rc->frame_size_planned && rc->qpm < rc->qp_novbv) || + (b1 > rc->buffer_fill - buffer_left_planned * 0.5f)) ) + { + rc->qpm += step_size; + b1 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices; + } + + float b_max = b1 + ((rc->buffer_fill - rc->buffer_size + rc->buffer_rate) * 0.90f - b1) * trust_coeff; + rc->qpm -= step_size; + float b2 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices; + while( rc->qpm > qp_min && rc->qpm < prev_row_qp + && (rc->qpm > h->fdec->f_row_qp[0] || rc->single_frame_vbv) + && (b2 < max_frame_size) + && ((b2 < rc->frame_size_planned * 0.8f) || (b2 < b_max)) ) + { + b1 = b2; + rc->qpm -= step_size; + b2 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices; + } + rc->qpm += step_size; + + /* avoid VBV underflow or MinCR violation */ + while( rc->qpm < qp_absolute_max && (b1 > max_frame_size) ) + { + rc->qpm += step_size; + b1 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices; + } + + h->rc->frame_size_estimated = b1 - size_of_other_slices; + + /* If the current row was large enough to cause a large QP jump, try re-encoding it. */ + if( rc->qpm > qp_max && prev_row_qp < qp_max && can_reencode_row ) + { + /* Bump QP to halfway in between... close enough. */ + rc->qpm = x264_clip3f( (prev_row_qp + rc->qpm)*0.5f, prev_row_qp + 1.0f, qp_max ); + rc->qpa_rc = rc->qpa_rc_prev; + rc->qpa_aq = rc->qpa_aq_prev; + h->fdec->i_row_bits[y] = 0; + h->fdec->i_row_bits[y-SLICE_MBAFF] = 0; + return -1; + } + } + else + { + h->rc->frame_size_estimated = bits_so_far; + + /* Last-ditch attempt: if the last row of the frame underflowed the VBV, + * try again. */ + if( rc->qpm < qp_max && can_reencode_row + && (h->rc->frame_size_estimated + size_of_other_slices > X264_MIN( rc->frame_size_maximum, rc->buffer_fill )) ) + { + rc->qpm = qp_max; + rc->qpa_rc = rc->qpa_rc_prev; + rc->qpa_aq = rc->qpa_aq_prev; + h->fdec->i_row_bits[y] = 0; + h->fdec->i_row_bits[y-SLICE_MBAFF] = 0; + return -1; + } + } + + rc->qpa_rc_prev = rc->qpa_rc; + rc->qpa_aq_prev = rc->qpa_aq; + + return 0; +} + +int x264_ratecontrol_qp( x264_t *h ) +{ + x264_emms(); + return x264_clip3( h->rc->qpm + 0.5f, h->param.rc.i_qp_min, h->param.rc.i_qp_max ); +} + +int x264_ratecontrol_mb_qp( x264_t *h ) +{ + x264_emms(); + float qp = h->rc->qpm; + if( h->param.rc.i_aq_mode ) + { + /* MB-tree currently doesn't adjust quantizers in unreferenced frames. */ + float qp_offset = h->fdec->b_kept_as_ref ? h->fenc->f_qp_offset[h->mb.i_mb_xy] : h->fenc->f_qp_offset_aq[h->mb.i_mb_xy]; + /* Scale AQ's effect towards zero in emergency mode. */ + if( qp > QP_MAX_SPEC ) + qp_offset *= (QP_MAX - qp) / (QP_MAX - QP_MAX_SPEC); + qp += qp_offset; + } + return x264_clip3( qp + 0.5f, h->param.rc.i_qp_min, h->param.rc.i_qp_max ); +} + +/* In 2pass, force the same frame types as in the 1st pass */ +int x264_ratecontrol_slice_type( x264_t *h, int frame_num ) +{ + x264_ratecontrol_t *rc = h->rc; + if( h->param.rc.b_stat_read ) + { + if( frame_num >= rc->num_entries ) + { + /* We could try to initialize everything required for ABR and + * adaptive B-frames, but that would be complicated. + * So just calculate the average QP used so far. */ + h->param.rc.i_qp_constant = (h->stat.i_frame_count[SLICE_TYPE_P] == 0) ? 24 + QP_BD_OFFSET + : 1 + h->stat.f_frame_qp[SLICE_TYPE_P] / h->stat.i_frame_count[SLICE_TYPE_P]; + rc->qp_constant[SLICE_TYPE_P] = x264_clip3( h->param.rc.i_qp_constant, 0, QP_MAX ); + rc->qp_constant[SLICE_TYPE_I] = x264_clip3( (int)( qscale2qp( qp2qscale( h->param.rc.i_qp_constant ) / fabs( h->param.rc.f_ip_factor )) + 0.5 ), 0, QP_MAX ); + rc->qp_constant[SLICE_TYPE_B] = x264_clip3( (int)( qscale2qp( qp2qscale( h->param.rc.i_qp_constant ) * fabs( h->param.rc.f_pb_factor )) + 0.5 ), 0, QP_MAX ); + + x264_log( h, X264_LOG_ERROR, "2nd pass has more frames than 1st pass (%d)\n", rc->num_entries ); + x264_log( h, X264_LOG_ERROR, "continuing anyway, at constant QP=%d\n", h->param.rc.i_qp_constant ); + if( h->param.i_bframe_adaptive ) + x264_log( h, X264_LOG_ERROR, "disabling adaptive B-frames\n" ); + + for( int i = 0; i < h->param.i_threads; i++ ) + { + h->thread[i]->rc->b_abr = 0; + h->thread[i]->rc->b_2pass = 0; + h->thread[i]->param.rc.i_rc_method = X264_RC_CQP; + h->thread[i]->param.rc.b_stat_read = 0; + h->thread[i]->param.i_bframe_adaptive = 0; + h->thread[i]->param.i_scenecut_threshold = 0; + h->thread[i]->param.rc.b_mb_tree = 0; + if( h->thread[i]->param.i_bframe > 1 ) + h->thread[i]->param.i_bframe = 1; + } + return X264_TYPE_AUTO; + } + return rc->entry[frame_num].frame_type; + } + else + return X264_TYPE_AUTO; +} + +void x264_ratecontrol_set_weights( x264_t *h, x264_frame_t *frm ) +{ + ratecontrol_entry_t *rce = &h->rc->entry[frm->i_frame]; + if( h->param.analyse.i_weighted_pred <= 0 ) + return; + + if( rce->i_weight_denom[0] >= 0 ) + SET_WEIGHT( frm->weight[0][0], 1, rce->weight[0][0], rce->i_weight_denom[0], rce->weight[0][1] ); + + if( rce->i_weight_denom[1] >= 0 ) + { + SET_WEIGHT( frm->weight[0][1], 1, rce->weight[1][0], rce->i_weight_denom[1], rce->weight[1][1] ); + SET_WEIGHT( frm->weight[0][2], 1, rce->weight[2][0], rce->i_weight_denom[1], rce->weight[2][1] ); + } +} + +/* After encoding one frame, save stats and update ratecontrol state */ +int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) +{ + x264_ratecontrol_t *rc = h->rc; + const int *mbs = h->stat.frame.i_mb_count; + + x264_emms(); + + h->stat.frame.i_mb_count_skip = mbs[P_SKIP] + mbs[B_SKIP]; + h->stat.frame.i_mb_count_i = mbs[I_16x16] + mbs[I_8x8] + mbs[I_4x4]; + h->stat.frame.i_mb_count_p = mbs[P_L0] + mbs[P_8x8]; + for( int i = B_DIRECT; i < B_8x8; i++ ) + h->stat.frame.i_mb_count_p += mbs[i]; + + h->fdec->f_qp_avg_rc = rc->qpa_rc /= h->mb.i_mb_count; + h->fdec->f_qp_avg_aq = (float)rc->qpa_aq / h->mb.i_mb_count; + h->fdec->f_crf_avg = h->param.rc.f_rf_constant + h->fdec->f_qp_avg_rc - rc->qp_novbv; + + if( h->param.rc.b_stat_write ) + { + char c_type = h->sh.i_type==SLICE_TYPE_I ? (h->fenc->i_poc==0 ? 'I' : 'i') + : h->sh.i_type==SLICE_TYPE_P ? 'P' + : h->fenc->b_kept_as_ref ? 'B' : 'b'; + int dir_frame = h->stat.frame.i_direct_score[1] - h->stat.frame.i_direct_score[0]; + int dir_avg = h->stat.i_direct_score[1] - h->stat.i_direct_score[0]; + char c_direct = h->mb.b_direct_auto_write ? + ( dir_frame>0 ? 's' : dir_frame<0 ? 't' : + dir_avg>0 ? 's' : dir_avg<0 ? 't' : '-' ) + : '-'; + if( fprintf( rc->p_stat_file_out, + "in:%d out:%d type:%c dur:%"PRId64" cpbdur:%"PRId64" q:%.2f aq:%.2f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c ref:", + h->fenc->i_frame, h->i_frame, + c_type, h->fenc->i_duration, + h->fenc->i_cpb_duration, + rc->qpa_rc, h->fdec->f_qp_avg_aq, + h->stat.frame.i_tex_bits, + h->stat.frame.i_mv_bits, + h->stat.frame.i_misc_bits, + h->stat.frame.i_mb_count_i, + h->stat.frame.i_mb_count_p, + h->stat.frame.i_mb_count_skip, + c_direct) < 0 ) + goto fail; + + /* Only write information for reference reordering once. */ + int use_old_stats = h->param.rc.b_stat_read && rc->rce->refs > 1; + for( int i = 0; i < (use_old_stats ? rc->rce->refs : h->i_ref[0]); i++ ) + { + int refcount = use_old_stats ? rc->rce->refcount[i] + : PARAM_INTERLACED ? h->stat.frame.i_mb_count_ref[0][i*2] + + h->stat.frame.i_mb_count_ref[0][i*2+1] + : h->stat.frame.i_mb_count_ref[0][i]; + if( fprintf( rc->p_stat_file_out, "%d ", refcount ) < 0 ) + goto fail; + } + + if( h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE && h->sh.weight[0][0].weightfn ) + { + if( fprintf( rc->p_stat_file_out, "w:%d,%d,%d", + h->sh.weight[0][0].i_denom, h->sh.weight[0][0].i_scale, h->sh.weight[0][0].i_offset ) < 0 ) + goto fail; + if( h->sh.weight[0][1].weightfn || h->sh.weight[0][2].weightfn ) + { + if( fprintf( rc->p_stat_file_out, ",%d,%d,%d,%d,%d ", + h->sh.weight[0][1].i_denom, h->sh.weight[0][1].i_scale, h->sh.weight[0][1].i_offset, + h->sh.weight[0][2].i_scale, h->sh.weight[0][2].i_offset ) < 0 ) + goto fail; + } + else if( fprintf( rc->p_stat_file_out, " " ) < 0 ) + goto fail; + } + + if( fprintf( rc->p_stat_file_out, ";\n") < 0 ) + goto fail; + + /* Don't re-write the data in multi-pass mode. */ + if( h->param.rc.b_mb_tree && h->fenc->b_kept_as_ref && !h->param.rc.b_stat_read ) + { + uint8_t i_type = h->sh.i_type; + h->mc.mbtree_fix8_pack( rc->mbtree.qp_buffer[0], h->fenc->f_qp_offset, h->mb.i_mb_count ); + if( fwrite( &i_type, 1, 1, rc->p_mbtree_stat_file_out ) < 1 ) + goto fail; + if( fwrite( rc->mbtree.qp_buffer[0], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_out ) < h->mb.i_mb_count ) + goto fail; + } + } + + if( rc->b_abr ) + { + if( h->sh.i_type != SLICE_TYPE_B ) + rc->cplxr_sum += bits * qp2qscale( rc->qpa_rc ) / rc->last_rceq; + else + { + /* Depends on the fact that B-frame's QP is an offset from the following P-frame's. + * Not perfectly accurate with B-refs, but good enough. */ + rc->cplxr_sum += bits * qp2qscale( rc->qpa_rc ) / (rc->last_rceq * fabs( h->param.rc.f_pb_factor )); + } + rc->cplxr_sum *= rc->cbr_decay; + rc->wanted_bits_window += h->fenc->f_duration * rc->bitrate; + rc->wanted_bits_window *= rc->cbr_decay; + } + + if( rc->b_2pass ) + rc->expected_bits_sum += qscale2bits( rc->rce, qp2qscale( rc->rce->new_qp ) ); + + if( h->mb.b_variable_qp ) + { + if( h->sh.i_type == SLICE_TYPE_B ) + { + rc->bframe_bits += bits; + if( h->fenc->b_last_minigop_bframe ) + { + update_predictor( rc->pred_b_from_p, qp2qscale( rc->qpa_rc ), + h->fref[1][h->i_ref[1]-1]->i_satd, rc->bframe_bits / rc->bframes ); + rc->bframe_bits = 0; + } + } + } + + *filler = update_vbv( h, bits ); + rc->filler_bits_sum += *filler * 8; + + if( h->sps->vui.b_nal_hrd_parameters_present ) + { + if( h->fenc->i_frame == 0 ) + { + // access unit initialises the HRD + h->fenc->hrd_timing.cpb_initial_arrival_time = 0; + rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; + rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; + h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (double)rc->initial_cpb_removal_delay / 90000; + } + else + { + h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (double)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * + h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + + if( h->fenc->b_keyframe ) + { + rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; + rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; + rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; + } + + double cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - (double)rc->initial_cpb_removal_delay / 90000; + if( !h->fenc->b_keyframe ) + cpb_earliest_arrival_time -= (double)rc->initial_cpb_removal_delay_offset / 90000; + + if( h->sps->vui.hrd.b_cbr_hrd ) + h->fenc->hrd_timing.cpb_initial_arrival_time = rc->previous_cpb_final_arrival_time; + else + h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( rc->previous_cpb_final_arrival_time, cpb_earliest_arrival_time ); + } + int filler_bits = *filler ? X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), *filler )*8 : 0; + // Equation C-6 + h->fenc->hrd_timing.cpb_final_arrival_time = rc->previous_cpb_final_arrival_time = h->fenc->hrd_timing.cpb_initial_arrival_time + + (double)(bits + filler_bits) / h->sps->vui.hrd.i_bit_rate_unscaled; + + h->fenc->hrd_timing.dpb_output_time = (double)h->fenc->i_dpb_output_delay * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + + h->fenc->hrd_timing.cpb_removal_time; + } + + return 0; +fail: + x264_log( h, X264_LOG_ERROR, "ratecontrol_end: stats file could not be written to\n" ); + return -1; +} + +/**************************************************************************** + * 2 pass functions + ***************************************************************************/ + +/** + * modify the bitrate curve from pass1 for one frame + */ +static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor, int frame_num) +{ + x264_ratecontrol_t *rcc= h->rc; + x264_zone_t *zone = get_zone( h, frame_num ); + double q; + if( h->param.rc.b_mb_tree ) + { + double timescale = (double)h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + q = pow( BASE_FRAME_DURATION / CLIP_DURATION(rce->i_duration * timescale), 1 - h->param.rc.f_qcompress ); + } + else + q = pow( rce->blurred_complexity, 1 - rcc->qcompress ); + + // avoid NaN's in the rc_eq + if( !isfinite(q) || rce->tex_bits + rce->mv_bits == 0 ) + q = rcc->last_qscale_for[rce->pict_type]; + else + { + rcc->last_rceq = q; + q /= rate_factor; + rcc->last_qscale = q; + } + + if( zone ) + { + if( zone->b_force_qp ) + q = qp2qscale( zone->i_qp ); + else + q /= zone->f_bitrate_factor; + } + + return q; +} + +static double get_diff_limited_q(x264_t *h, ratecontrol_entry_t *rce, double q, int frame_num) +{ + x264_ratecontrol_t *rcc = h->rc; + const int pict_type = rce->pict_type; + x264_zone_t *zone = get_zone( h, frame_num ); + + // force I/B quants as a function of P quants + const double last_p_q = rcc->last_qscale_for[SLICE_TYPE_P]; + const double last_non_b_q= rcc->last_qscale_for[rcc->last_non_b_pict_type]; + if( pict_type == SLICE_TYPE_I ) + { + double iq = q; + double pq = qp2qscale( rcc->accum_p_qp / rcc->accum_p_norm ); + double ip_factor = fabs( h->param.rc.f_ip_factor ); + /* don't apply ip_factor if the following frame is also I */ + if( rcc->accum_p_norm <= 0 ) + q = iq; + else if( h->param.rc.f_ip_factor < 0 ) + q = iq / ip_factor; + else if( rcc->accum_p_norm >= 1 ) + q = pq / ip_factor; + else + q = rcc->accum_p_norm * pq / ip_factor + (1 - rcc->accum_p_norm) * iq; + } + else if( pict_type == SLICE_TYPE_B ) + { + if( h->param.rc.f_pb_factor > 0 ) + q = last_non_b_q; + if( !rce->kept_as_ref ) + q *= fabs( h->param.rc.f_pb_factor ); + } + else if( pict_type == SLICE_TYPE_P + && rcc->last_non_b_pict_type == SLICE_TYPE_P + && rce->tex_bits == 0 ) + { + q = last_p_q; + } + + /* last qscale / qdiff stuff */ + if( rcc->last_non_b_pict_type == pict_type && + (pict_type!=SLICE_TYPE_I || rcc->last_accum_p_norm < 1) ) + { + double last_q = rcc->last_qscale_for[pict_type]; + double max_qscale = last_q * rcc->lstep; + double min_qscale = last_q / rcc->lstep; + + if ( q > max_qscale ) q = max_qscale; + else if( q < min_qscale ) q = min_qscale; + } + + rcc->last_qscale_for[pict_type] = q; + if( pict_type != SLICE_TYPE_B ) + rcc->last_non_b_pict_type = pict_type; + if( pict_type == SLICE_TYPE_I ) + { + rcc->last_accum_p_norm = rcc->accum_p_norm; + rcc->accum_p_norm = 0; + rcc->accum_p_qp = 0; + } + if( pict_type == SLICE_TYPE_P ) + { + float mask = 1 - pow( (float)rce->i_count / rcc->nmb, 2 ); + rcc->accum_p_qp = mask * (qscale2qp( q ) + rcc->accum_p_qp); + rcc->accum_p_norm = mask * (1 + rcc->accum_p_norm); + } + + if( zone ) + { + if( zone->b_force_qp ) + q = qp2qscale( zone->i_qp ); + else + q /= zone->f_bitrate_factor; + } + + return q; +} + +static float predict_size( predictor_t *p, float q, float var ) +{ + return (p->coeff*var + p->offset) / (q*p->count); +} + +static void update_predictor( predictor_t *p, float q, float var, float bits ) +{ + float range = 1.5; + if( var < 10 ) + return; + float old_coeff = p->coeff / p->count; + float old_offset = p->offset / p->count; + float new_coeff = X264_MAX( (bits*q - old_offset) / var, p->coeff_min ); + float new_coeff_clipped = x264_clip3f( new_coeff, old_coeff/range, old_coeff*range ); + float new_offset = bits*q - new_coeff_clipped * var; + if( new_offset >= 0 ) + new_coeff = new_coeff_clipped; + else + new_offset = 0; + p->count *= p->decay; + p->coeff *= p->decay; + p->offset *= p->decay; + p->count ++; + p->coeff += new_coeff; + p->offset += new_offset; +} + +// update VBV after encoding a frame +static int update_vbv( x264_t *h, int bits ) +{ + int filler = 0; + int bitrate = h->sps->vui.hrd.i_bit_rate_unscaled; + x264_ratecontrol_t *rcc = h->rc; + x264_ratecontrol_t *rct = h->thread[0]->rc; + int64_t buffer_size = (int64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale; + + if( rcc->last_satd >= h->mb.i_mb_count ) + update_predictor( &rct->pred[h->sh.i_type], qp2qscale( rcc->qpa_rc ), rcc->last_satd, bits ); + + if( !rcc->b_vbv ) + return filler; + + uint64_t buffer_diff = (uint64_t)bits * h->sps->vui.i_time_scale; + rct->buffer_fill_final -= buffer_diff; + rct->buffer_fill_final_min -= buffer_diff; + + if( rct->buffer_fill_final_min < 0 ) + { + double underflow = (double)rct->buffer_fill_final_min / h->sps->vui.i_time_scale; + if( rcc->rate_factor_max_increment && rcc->qpm >= rcc->qp_novbv + rcc->rate_factor_max_increment ) + x264_log( h, X264_LOG_DEBUG, "VBV underflow due to CRF-max (frame %d, %.0f bits)\n", h->i_frame, underflow ); + else + x264_log( h, X264_LOG_WARNING, "VBV underflow (frame %d, %.0f bits)\n", h->i_frame, underflow ); + rct->buffer_fill_final = + rct->buffer_fill_final_min = 0; + } + + if( h->param.i_avcintra_class ) + buffer_diff = buffer_size; + else + buffer_diff = (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration; + rct->buffer_fill_final += buffer_diff; + rct->buffer_fill_final_min += buffer_diff; + + if( rct->buffer_fill_final > buffer_size ) + { + if( h->param.rc.b_filler ) + { + int64_t scale = (int64_t)h->sps->vui.i_time_scale * 8; + filler = (rct->buffer_fill_final - buffer_size + scale - 1) / scale; + bits = h->param.i_avcintra_class ? filler * 8 : X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8; + buffer_diff = (uint64_t)bits * h->sps->vui.i_time_scale; + rct->buffer_fill_final -= buffer_diff; + rct->buffer_fill_final_min -= buffer_diff; + } + else + { + rct->buffer_fill_final = X264_MIN( rct->buffer_fill_final, buffer_size ); + rct->buffer_fill_final_min = X264_MIN( rct->buffer_fill_final_min, buffer_size ); + } + } + + return filler; +} + +void x264_hrd_fullness( x264_t *h ) +{ + x264_ratecontrol_t *rct = h->thread[0]->rc; + uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale / rct->hrd_multiply_denom; + uint64_t cpb_state = rct->buffer_fill_final; + uint64_t cpb_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale; + uint64_t multiply_factor = 90000 / rct->hrd_multiply_denom; + + if( rct->buffer_fill_final < 0 || rct->buffer_fill_final > (int64_t)cpb_size ) + { + x264_log( h, X264_LOG_WARNING, "CPB %s: %.0f bits in a %.0f-bit buffer\n", + rct->buffer_fill_final < 0 ? "underflow" : "overflow", + (double)rct->buffer_fill_final / h->sps->vui.i_time_scale, (double)cpb_size / h->sps->vui.i_time_scale ); + } + + h->initial_cpb_removal_delay = (multiply_factor * cpb_state) / denom; + h->initial_cpb_removal_delay_offset = (multiply_factor * cpb_size) / denom - h->initial_cpb_removal_delay; + + int64_t decoder_buffer_fill = h->initial_cpb_removal_delay * denom / multiply_factor; + rct->buffer_fill_final_min = X264_MIN( rct->buffer_fill_final_min, decoder_buffer_fill ); +} + +// provisionally update VBV according to the planned size of all frames currently in progress +static void update_vbv_plan( x264_t *h, int overhead ) +{ + x264_ratecontrol_t *rcc = h->rc; + rcc->buffer_fill = h->thread[0]->rc->buffer_fill_final_min / h->sps->vui.i_time_scale; + if( h->i_thread_frames > 1 ) + { + int j = h->rc - h->thread[0]->rc; + for( int i = 1; i < h->i_thread_frames; i++ ) + { + x264_t *t = h->thread[ (j+i)%h->i_thread_frames ]; + double bits = t->rc->frame_size_planned; + if( !t->b_thread_active ) + continue; + bits = X264_MAX(bits, t->rc->frame_size_estimated); + rcc->buffer_fill -= bits; + rcc->buffer_fill = X264_MAX( rcc->buffer_fill, 0 ); + rcc->buffer_fill += t->rc->buffer_rate; + rcc->buffer_fill = X264_MIN( rcc->buffer_fill, rcc->buffer_size ); + } + } + rcc->buffer_fill = X264_MIN( rcc->buffer_fill, rcc->buffer_size ); + rcc->buffer_fill -= overhead; +} + +// apply VBV constraints and clip qscale to between lmin and lmax +static double clip_qscale( x264_t *h, int pict_type, double q ) +{ + x264_ratecontrol_t *rcc = h->rc; + double lmin = rcc->lmin[pict_type]; + double lmax = rcc->lmax[pict_type]; + if( rcc->rate_factor_max_increment ) + lmax = X264_MIN( lmax, qp2qscale( rcc->qp_novbv + rcc->rate_factor_max_increment ) ); + double q0 = q; + + /* B-frames are not directly subject to VBV, + * since they are controlled by the P-frames' QPs. */ + + if( rcc->b_vbv && rcc->last_satd > 0 ) + { + double fenc_cpb_duration = (double)h->fenc->i_cpb_duration * + h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + /* Lookahead VBV: raise the quantizer as necessary such that no frames in + * the lookahead overflow and such that the buffer is in a reasonable state + * by the end of the lookahead. */ + if( h->param.rc.i_lookahead ) + { + int terminate = 0; + + /* Avoid an infinite loop. */ + for( int iterations = 0; iterations < 1000 && terminate != 3; iterations++ ) + { + double frame_q[3]; + double cur_bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); + double buffer_fill_cur = rcc->buffer_fill - cur_bits; + double target_fill; + double total_duration = 0; + double last_duration = fenc_cpb_duration; + frame_q[0] = h->sh.i_type == SLICE_TYPE_I ? q * h->param.rc.f_ip_factor : q; + frame_q[1] = frame_q[0] * h->param.rc.f_pb_factor; + frame_q[2] = frame_q[0] / h->param.rc.f_ip_factor; + + /* Loop over the planned future frames. */ + for( int j = 0; buffer_fill_cur >= 0 && buffer_fill_cur <= rcc->buffer_size; j++ ) + { + total_duration += last_duration; + buffer_fill_cur += rcc->vbv_max_rate * last_duration; + int i_type = h->fenc->i_planned_type[j]; + int i_satd = h->fenc->i_planned_satd[j]; + if( i_type == X264_TYPE_AUTO ) + break; + i_type = IS_X264_TYPE_I( i_type ) ? SLICE_TYPE_I : IS_X264_TYPE_B( i_type ) ? SLICE_TYPE_B : SLICE_TYPE_P; + cur_bits = predict_size( &rcc->pred[i_type], frame_q[i_type], i_satd ); + buffer_fill_cur -= cur_bits; + last_duration = h->fenc->f_planned_cpb_duration[j]; + } + /* Try to get to get the buffer at least 50% filled, but don't set an impossible goal. */ + target_fill = X264_MIN( rcc->buffer_fill + total_duration * rcc->vbv_max_rate * 0.5, rcc->buffer_size * 0.5 ); + if( buffer_fill_cur < target_fill ) + { + q *= 1.01; + terminate |= 1; + continue; + } + /* Try to get the buffer no more than 80% filled, but don't set an impossible goal. */ + target_fill = x264_clip3f( rcc->buffer_fill - total_duration * rcc->vbv_max_rate * 0.5, rcc->buffer_size * 0.8, rcc->buffer_size ); + if( rcc->b_vbv_min_rate && buffer_fill_cur > target_fill ) + { + q /= 1.01; + terminate |= 2; + continue; + } + break; + } + } + /* Fallback to old purely-reactive algorithm: no lookahead. */ + else + { + if( ( pict_type == SLICE_TYPE_P || + ( pict_type == SLICE_TYPE_I && rcc->last_non_b_pict_type == SLICE_TYPE_I ) ) && + rcc->buffer_fill/rcc->buffer_size < 0.5 ) + { + q /= x264_clip3f( 2.0*rcc->buffer_fill/rcc->buffer_size, 0.5, 1.0 ); + } + + /* Now a hard threshold to make sure the frame fits in VBV. + * This one is mostly for I-frames. */ + double bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); + /* For small VBVs, allow the frame to use up the entire VBV. */ + double max_fill_factor = h->param.rc.i_vbv_buffer_size >= 5*h->param.rc.i_vbv_max_bitrate / rcc->fps ? 2 : 1; + /* For single-frame VBVs, request that the frame use up the entire VBV. */ + double min_fill_factor = rcc->single_frame_vbv ? 1 : 2; + + if( bits > rcc->buffer_fill/max_fill_factor ) + { + double qf = x264_clip3f( rcc->buffer_fill/(max_fill_factor*bits), 0.2, 1.0 ); + q /= qf; + bits *= qf; + } + if( bits < rcc->buffer_rate/min_fill_factor ) + { + double qf = x264_clip3f( bits*min_fill_factor/rcc->buffer_rate, 0.001, 1.0 ); + q *= qf; + } + q = X264_MAX( q0, q ); + } + + /* Check B-frame complexity, and use up any bits that would + * overflow before the next P-frame. */ + if( h->sh.i_type == SLICE_TYPE_P && !rcc->single_frame_vbv ) + { + int nb = rcc->bframes; + double bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); + double pbbits = bits; + double bbits = predict_size( rcc->pred_b_from_p, q * h->param.rc.f_pb_factor, rcc->last_satd ); + double space; + double bframe_cpb_duration = 0; + double minigop_cpb_duration; + for( int i = 0; i < nb; i++ ) + bframe_cpb_duration += h->fenc->f_planned_cpb_duration[i]; + + if( bbits * nb > bframe_cpb_duration * rcc->vbv_max_rate ) + nb = 0; + pbbits += nb * bbits; + + minigop_cpb_duration = bframe_cpb_duration + fenc_cpb_duration; + space = rcc->buffer_fill + minigop_cpb_duration*rcc->vbv_max_rate - rcc->buffer_size; + if( pbbits < space ) + { + q *= X264_MAX( pbbits / space, bits / (0.5 * rcc->buffer_size) ); + } + q = X264_MAX( q0/2, q ); + } + + /* Apply MinCR and buffer fill restrictions */ + double bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); + double frame_size_maximum = X264_MIN( rcc->frame_size_maximum, X264_MAX( rcc->buffer_fill, 0.001 ) ); + if( bits > frame_size_maximum ) + q *= bits / frame_size_maximum; + + if( !rcc->b_vbv_min_rate ) + q = X264_MAX( q0, q ); + } + + if( lmin==lmax ) + return lmin; + else if( rcc->b_2pass ) + { + double min2 = log( lmin ); + double max2 = log( lmax ); + q = (log(q) - min2)/(max2-min2) - 0.5; + q = 1.0/(1.0 + exp( -4*q )); + q = q*(max2-min2) + min2; + return exp( q ); + } + else + return x264_clip3f( q, lmin, lmax ); +} + +// update qscale for 1 frame based on actual bits used so far +static float rate_estimate_qscale( x264_t *h ) +{ + float q; + x264_ratecontrol_t *rcc = h->rc; + ratecontrol_entry_t rce = {0}; + int pict_type = h->sh.i_type; + int64_t total_bits = 8*(h->stat.i_frame_size[SLICE_TYPE_I] + + h->stat.i_frame_size[SLICE_TYPE_P] + + h->stat.i_frame_size[SLICE_TYPE_B]) + - rcc->filler_bits_sum; + + if( rcc->b_2pass ) + { + rce = *rcc->rce; + if( pict_type != rce.pict_type ) + { + x264_log( h, X264_LOG_ERROR, "slice=%c but 2pass stats say %c\n", + slice_type_to_char[pict_type], slice_type_to_char[rce.pict_type] ); + } + } + + if( pict_type == SLICE_TYPE_B ) + { + /* B-frames don't have independent ratecontrol, but rather get the + * average QP of the two adjacent P-frames + an offset */ + + int i0 = IS_X264_TYPE_I(h->fref_nearest[0]->i_type); + int i1 = IS_X264_TYPE_I(h->fref_nearest[1]->i_type); + int dt0 = abs(h->fenc->i_poc - h->fref_nearest[0]->i_poc); + int dt1 = abs(h->fenc->i_poc - h->fref_nearest[1]->i_poc); + float q0 = h->fref_nearest[0]->f_qp_avg_rc; + float q1 = h->fref_nearest[1]->f_qp_avg_rc; + + if( h->fref_nearest[0]->i_type == X264_TYPE_BREF ) + q0 -= rcc->pb_offset/2; + if( h->fref_nearest[1]->i_type == X264_TYPE_BREF ) + q1 -= rcc->pb_offset/2; + + if( i0 && i1 ) + q = (q0 + q1) / 2 + rcc->ip_offset; + else if( i0 ) + q = q1; + else if( i1 ) + q = q0; + else + q = (q0*dt1 + q1*dt0) / (dt0 + dt1); + + if( h->fenc->b_kept_as_ref ) + q += rcc->pb_offset/2; + else + q += rcc->pb_offset; + + rcc->qp_novbv = q; + q = qp2qscale( q ); + if( rcc->b_2pass ) + rcc->frame_size_planned = qscale2bits( &rce, q ); + else + rcc->frame_size_planned = predict_size( rcc->pred_b_from_p, q, h->fref[1][h->i_ref[1]-1]->i_satd ); + /* Limit planned size by MinCR */ + if( rcc->b_vbv ) + rcc->frame_size_planned = X264_MIN( rcc->frame_size_planned, rcc->frame_size_maximum ); + h->rc->frame_size_estimated = rcc->frame_size_planned; + + /* For row SATDs */ + if( rcc->b_vbv ) + rcc->last_satd = x264_rc_analyse_slice( h ); + return q; + } + else + { + double abr_buffer = 2 * rcc->rate_tolerance * rcc->bitrate; + double predicted_bits = total_bits; + if( h->i_thread_frames > 1 ) + { + int j = h->rc - h->thread[0]->rc; + for( int i = 1; i < h->i_thread_frames; i++ ) + { + x264_t *t = h->thread[(j+i) % h->i_thread_frames]; + double bits = t->rc->frame_size_planned; + if( !t->b_thread_active ) + continue; + bits = X264_MAX(bits, t->rc->frame_size_estimated); + predicted_bits += bits; + } + } + + if( rcc->b_2pass ) + { + double lmin = rcc->lmin[pict_type]; + double lmax = rcc->lmax[pict_type]; + double diff; + + /* Adjust ABR buffer based on distance to the end of the video. */ + if( rcc->num_entries > h->i_frame ) + { + double final_bits = rcc->entry_out[rcc->num_entries-1]->expected_bits; + double video_pos = rce.expected_bits / final_bits; + double scale_factor = sqrt( (1 - video_pos) * rcc->num_entries ); + abr_buffer *= 0.5 * X264_MAX( scale_factor, 0.5 ); + } + + diff = predicted_bits - rce.expected_bits; + q = rce.new_qscale; + q /= x264_clip3f((abr_buffer - diff) / abr_buffer, .5, 2); + if( h->i_frame >= rcc->fps && rcc->expected_bits_sum >= 1 ) + { + /* Adjust quant based on the difference between + * achieved and expected bitrate so far */ + double cur_time = (double)h->i_frame / rcc->num_entries; + double w = x264_clip3f( cur_time*100, 0.0, 1.0 ); + q *= pow( (double)total_bits / rcc->expected_bits_sum, w ); + } + rcc->qp_novbv = qscale2qp( q ); + if( rcc->b_vbv ) + { + /* Do not overflow vbv */ + double expected_size = qscale2bits( &rce, q ); + double expected_vbv = rcc->buffer_fill + rcc->buffer_rate - expected_size; + double expected_fullness = rce.expected_vbv / rcc->buffer_size; + double qmax = q*(2 - expected_fullness); + double size_constraint = 1 + expected_fullness; + qmax = X264_MAX( qmax, rce.new_qscale ); + if( expected_fullness < .05 ) + qmax = lmax; + qmax = X264_MIN(qmax, lmax); + while( ((expected_vbv < rce.expected_vbv/size_constraint) && (q < qmax)) || + ((expected_vbv < 0) && (q < lmax))) + { + q *= 1.05; + expected_size = qscale2bits(&rce, q); + expected_vbv = rcc->buffer_fill + rcc->buffer_rate - expected_size; + } + rcc->last_satd = x264_rc_analyse_slice( h ); + } + q = x264_clip3f( q, lmin, lmax ); + } + else /* 1pass ABR */ + { + /* Calculate the quantizer which would have produced the desired + * average bitrate if it had been applied to all frames so far. + * Then modulate that quant based on the current frame's complexity + * relative to the average complexity so far (using the 2pass RCEQ). + * Then bias the quant up or down if total size so far was far from + * the target. + * Result: Depending on the value of rate_tolerance, there is a + * tradeoff between quality and bitrate precision. But at large + * tolerances, the bit distribution approaches that of 2pass. */ + + double wanted_bits, overflow = 1; + + rcc->last_satd = x264_rc_analyse_slice( h ); + rcc->short_term_cplxsum *= 0.5; + rcc->short_term_cplxcount *= 0.5; + rcc->short_term_cplxsum += rcc->last_satd / (CLIP_DURATION(h->fenc->f_duration) / BASE_FRAME_DURATION); + rcc->short_term_cplxcount ++; + + rce.tex_bits = rcc->last_satd; + rce.blurred_complexity = rcc->short_term_cplxsum / rcc->short_term_cplxcount; + rce.mv_bits = 0; + rce.p_count = rcc->nmb; + rce.i_count = 0; + rce.s_count = 0; + rce.qscale = 1; + rce.pict_type = pict_type; + rce.i_duration = h->fenc->i_duration; + + if( h->param.rc.i_rc_method == X264_RC_CRF ) + { + q = get_qscale( h, &rce, rcc->rate_factor_constant, h->fenc->i_frame ); + } + else + { + q = get_qscale( h, &rce, rcc->wanted_bits_window / rcc->cplxr_sum, h->fenc->i_frame ); + + /* ABR code can potentially be counterproductive in CBR, so just don't bother. + * Don't run it if the frame complexity is zero either. */ + if( !rcc->b_vbv_min_rate && rcc->last_satd ) + { + // FIXME is it simpler to keep track of wanted_bits in ratecontrol_end? + int i_frame_done = h->i_frame; + double time_done = i_frame_done / rcc->fps; + if( h->param.b_vfr_input && i_frame_done > 0 ) + time_done = ((double)(h->fenc->i_reordered_pts - h->i_reordered_pts_delay)) * h->param.i_timebase_num / h->param.i_timebase_den; + wanted_bits = time_done * rcc->bitrate; + if( wanted_bits > 0 ) + { + abr_buffer *= X264_MAX( 1, sqrt( time_done ) ); + overflow = x264_clip3f( 1.0 + (predicted_bits - wanted_bits) / abr_buffer, .5, 2 ); + q *= overflow; + } + } + } + + if( pict_type == SLICE_TYPE_I && h->param.i_keyint_max > 1 + /* should test _next_ pict type, but that isn't decided yet */ + && rcc->last_non_b_pict_type != SLICE_TYPE_I ) + { + q = qp2qscale( rcc->accum_p_qp / rcc->accum_p_norm ); + q /= fabs( h->param.rc.f_ip_factor ); + } + else if( h->i_frame > 0 ) + { + if( h->param.rc.i_rc_method != X264_RC_CRF ) + { + /* Asymmetric clipping, because symmetric would prevent + * overflow control in areas of rapidly oscillating complexity */ + double lmin = rcc->last_qscale_for[pict_type] / rcc->lstep; + double lmax = rcc->last_qscale_for[pict_type] * rcc->lstep; + if( overflow > 1.1 && h->i_frame > 3 ) + lmax *= rcc->lstep; + else if( overflow < 0.9 ) + lmin /= rcc->lstep; + + q = x264_clip3f(q, lmin, lmax); + } + } + else if( h->param.rc.i_rc_method == X264_RC_CRF && rcc->qcompress != 1 ) + { + q = qp2qscale( ABR_INIT_QP ) / fabs( h->param.rc.f_ip_factor ); + } + rcc->qp_novbv = qscale2qp( q ); + + //FIXME use get_diff_limited_q() ? + q = clip_qscale( h, pict_type, q ); + } + + rcc->last_qscale_for[pict_type] = + rcc->last_qscale = q; + + if( !(rcc->b_2pass && !rcc->b_vbv) && h->fenc->i_frame == 0 ) + rcc->last_qscale_for[SLICE_TYPE_P] = q * fabs( h->param.rc.f_ip_factor ); + + if( rcc->b_2pass ) + rcc->frame_size_planned = qscale2bits( &rce, q ); + else + rcc->frame_size_planned = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); + + /* Always use up the whole VBV in this case. */ + if( rcc->single_frame_vbv ) + rcc->frame_size_planned = rcc->buffer_rate; + /* Limit planned size by MinCR */ + if( rcc->b_vbv ) + rcc->frame_size_planned = X264_MIN( rcc->frame_size_planned, rcc->frame_size_maximum ); + h->rc->frame_size_estimated = rcc->frame_size_planned; + return q; + } +} + +static void x264_threads_normalize_predictors( x264_t *h ) +{ + double totalsize = 0; + for( int i = 0; i < h->param.i_threads; i++ ) + totalsize += h->thread[i]->rc->slice_size_planned; + double factor = h->rc->frame_size_planned / totalsize; + for( int i = 0; i < h->param.i_threads; i++ ) + h->thread[i]->rc->slice_size_planned *= factor; +} + +void x264_threads_distribute_ratecontrol( x264_t *h ) +{ + int row; + x264_ratecontrol_t *rc = h->rc; + x264_emms(); + float qscale = qp2qscale( rc->qpm ); + + /* Initialize row predictors */ + if( h->i_frame == 0 ) + for( int i = 0; i < h->param.i_threads; i++ ) + { + x264_t *t = h->thread[i]; + if( t != h ) + memcpy( t->rc->row_preds, rc->row_preds, sizeof(rc->row_preds) ); + } + + for( int i = 0; i < h->param.i_threads; i++ ) + { + x264_t *t = h->thread[i]; + if( t != h ) + memcpy( t->rc, rc, offsetof(x264_ratecontrol_t, row_pred) ); + t->rc->row_pred = t->rc->row_preds[h->sh.i_type]; + /* Calculate the planned slice size. */ + if( rc->b_vbv && rc->frame_size_planned ) + { + int size = 0; + for( row = t->i_threadslice_start; row < t->i_threadslice_end; row++ ) + size += h->fdec->i_row_satd[row]; + t->rc->slice_size_planned = predict_size( &rc->pred[h->sh.i_type + (i+1)*5], qscale, size ); + } + else + t->rc->slice_size_planned = 0; + } + if( rc->b_vbv && rc->frame_size_planned ) + { + x264_threads_normalize_predictors( h ); + + if( rc->single_frame_vbv ) + { + /* Compensate for our max frame error threshold: give more bits (proportionally) to smaller slices. */ + for( int i = 0; i < h->param.i_threads; i++ ) + { + x264_t *t = h->thread[i]; + float max_frame_error = x264_clip3f( 1.0 / (t->i_threadslice_end - t->i_threadslice_start), 0.05, 0.25 ); + t->rc->slice_size_planned += 2 * max_frame_error * rc->frame_size_planned; + } + x264_threads_normalize_predictors( h ); + } + + for( int i = 0; i < h->param.i_threads; i++ ) + h->thread[i]->rc->frame_size_estimated = h->thread[i]->rc->slice_size_planned; + } +} + +void x264_threads_merge_ratecontrol( x264_t *h ) +{ + x264_ratecontrol_t *rc = h->rc; + x264_emms(); + + for( int i = 0; i < h->param.i_threads; i++ ) + { + x264_t *t = h->thread[i]; + x264_ratecontrol_t *rct = h->thread[i]->rc; + if( h->param.rc.i_vbv_buffer_size ) + { + int size = 0; + for( int row = t->i_threadslice_start; row < t->i_threadslice_end; row++ ) + size += h->fdec->i_row_satd[row]; + int bits = t->stat.frame.i_mv_bits + t->stat.frame.i_tex_bits + t->stat.frame.i_misc_bits; + int mb_count = (t->i_threadslice_end - t->i_threadslice_start) * h->mb.i_mb_width; + update_predictor( &rc->pred[h->sh.i_type+(i+1)*5], qp2qscale( rct->qpa_rc/mb_count ), size, bits ); + } + if( !i ) + continue; + rc->qpa_rc += rct->qpa_rc; + rc->qpa_aq += rct->qpa_aq; + } +} + +void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) +{ + if( cur != prev ) + { +#define COPY(var) memcpy(&cur->rc->var, &prev->rc->var, sizeof(cur->rc->var)) + /* these vars are updated in x264_ratecontrol_start() + * so copy them from the context that most recently started (prev) + * to the context that's about to start (cur). */ + COPY(accum_p_qp); + COPY(accum_p_norm); + COPY(last_satd); + COPY(last_rceq); + COPY(last_qscale_for); + COPY(last_non_b_pict_type); + COPY(short_term_cplxsum); + COPY(short_term_cplxcount); + COPY(bframes); + COPY(prev_zone); + COPY(mbtree.qpbuf_pos); + /* these vars can be updated by x264_ratecontrol_init_reconfigurable */ + COPY(bitrate); + COPY(buffer_size); + COPY(buffer_rate); + COPY(vbv_max_rate); + COPY(single_frame_vbv); + COPY(cbr_decay); + COPY(rate_factor_constant); + COPY(rate_factor_max_increment); +#undef COPY + } + if( cur != next ) + { +#define COPY(var) next->rc->var = cur->rc->var + /* these vars are updated in x264_ratecontrol_end() + * so copy them from the context that most recently ended (cur) + * to the context that's about to end (next) */ + COPY(cplxr_sum); + COPY(expected_bits_sum); + COPY(filler_bits_sum); + COPY(wanted_bits_window); + COPY(bframe_bits); + COPY(initial_cpb_removal_delay); + COPY(initial_cpb_removal_delay_offset); + COPY(nrt_first_access_unit); + COPY(previous_cpb_final_arrival_time); +#undef COPY + } + //FIXME row_preds[] (not strictly necessary, but would improve prediction) + /* the rest of the variables are either constant or thread-local */ +} + +static int find_underflow( x264_t *h, double *fills, int *t0, int *t1, int over ) +{ + /* find an interval ending on an overflow or underflow (depending on whether + * we're adding or removing bits), and starting on the earliest frame that + * can influence the buffer fill of that end frame. */ + x264_ratecontrol_t *rcc = h->rc; + const double buffer_min = .1 * rcc->buffer_size; + const double buffer_max = .9 * rcc->buffer_size; + double fill = fills[*t0-1]; + double parity = over ? 1. : -1.; + int start = -1, end = -1; + for( int i = *t0; i < rcc->num_entries; i++ ) + { + fill += (rcc->entry_out[i]->i_cpb_duration * rcc->vbv_max_rate * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale - + qscale2bits( rcc->entry_out[i], rcc->entry_out[i]->new_qscale )) * parity; + fill = x264_clip3f(fill, 0, rcc->buffer_size); + fills[i] = fill; + if( fill <= buffer_min || i == 0 ) + { + if( end >= 0 ) + break; + start = i; + } + else if( fill >= buffer_max && start >= 0 ) + end = i; + } + *t0 = start; + *t1 = end; + return start >= 0 && end >= 0; +} + +static int fix_underflow( x264_t *h, int t0, int t1, double adjustment, double qscale_min, double qscale_max ) +{ + x264_ratecontrol_t *rcc = h->rc; + double qscale_orig, qscale_new; + int adjusted = 0; + if( t0 > 0 ) + t0++; + for( int i = t0; i <= t1; i++ ) + { + qscale_orig = rcc->entry_out[i]->new_qscale; + qscale_orig = x264_clip3f( qscale_orig, qscale_min, qscale_max ); + qscale_new = qscale_orig * adjustment; + qscale_new = x264_clip3f( qscale_new, qscale_min, qscale_max ); + rcc->entry_out[i]->new_qscale = qscale_new; + adjusted = adjusted || (qscale_new != qscale_orig); + } + return adjusted; +} + +static double count_expected_bits( x264_t *h ) +{ + x264_ratecontrol_t *rcc = h->rc; + double expected_bits = 0; + for( int i = 0; i < rcc->num_entries; i++ ) + { + ratecontrol_entry_t *rce = rcc->entry_out[i]; + rce->expected_bits = expected_bits; + expected_bits += qscale2bits( rce, rce->new_qscale ); + } + return expected_bits; +} + +static int vbv_pass2( x264_t *h, double all_available_bits ) +{ + /* for each interval of buffer_full .. underflow, uniformly increase the qp of all + * frames in the interval until either buffer is full at some intermediate frame or the + * last frame in the interval no longer underflows. Recompute intervals and repeat. + * Then do the converse to put bits back into overflow areas until target size is met */ + + x264_ratecontrol_t *rcc = h->rc; + double *fills; + double expected_bits = 0; + double adjustment; + double prev_bits = 0; + int t0, t1; + double qscale_min = qp2qscale( h->param.rc.i_qp_min ); + double qscale_max = qp2qscale( h->param.rc.i_qp_max ); + int iterations = 0; + int adj_min, adj_max; + CHECKED_MALLOC( fills, (rcc->num_entries+1)*sizeof(double) ); + + fills++; + + /* adjust overall stream size */ + do + { + iterations++; + prev_bits = expected_bits; + + if( expected_bits ) + { /* not first iteration */ + adjustment = X264_MAX(X264_MIN(expected_bits / all_available_bits, 0.999), 0.9); + fills[-1] = rcc->buffer_size * h->param.rc.f_vbv_buffer_init; + t0 = 0; + /* fix overflows */ + adj_min = 1; + while( adj_min && find_underflow( h, fills, &t0, &t1, 1 ) ) + { + adj_min = fix_underflow( h, t0, t1, adjustment, qscale_min, qscale_max ); + t0 = t1; + } + } + + fills[-1] = rcc->buffer_size * (1. - h->param.rc.f_vbv_buffer_init); + t0 = 0; + /* fix underflows -- should be done after overflow, as we'd better undersize target than underflowing VBV */ + adj_max = 1; + while( adj_max && find_underflow( h, fills, &t0, &t1, 0 ) ) + adj_max = fix_underflow( h, t0, t1, 1.001, qscale_min, qscale_max ); + + expected_bits = count_expected_bits( h ); + } while( (expected_bits < .995*all_available_bits) && ((int64_t)(expected_bits+.5) > (int64_t)(prev_bits+.5)) ); + + if( !adj_max ) + x264_log( h, X264_LOG_WARNING, "vbv-maxrate issue, qpmax or vbv-maxrate too low\n"); + + /* store expected vbv filling values for tracking when encoding */ + for( int i = 0; i < rcc->num_entries; i++ ) + rcc->entry_out[i]->expected_vbv = rcc->buffer_size - fills[i]; + + x264_free( fills-1 ); + return 0; +fail: + return -1; +} + +static int init_pass2( x264_t *h ) +{ + x264_ratecontrol_t *rcc = h->rc; + uint64_t all_const_bits = 0; + double timescale = (double)h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + double duration = 0; + for( int i = 0; i < rcc->num_entries; i++ ) + duration += rcc->entry[i].i_duration; + duration *= timescale; + uint64_t all_available_bits = h->param.rc.i_bitrate * 1000. * duration; + double rate_factor, step_mult; + double qblur = h->param.rc.f_qblur; + double cplxblur = h->param.rc.f_complexity_blur; + const int filter_size = (int)(qblur*4) | 1; + double expected_bits; + double *qscale, *blurred_qscale; + double base_cplx = h->mb.i_mb_count * (h->param.i_bframe ? 120 : 80); + + /* find total/average complexity & const_bits */ + for( int i = 0; i < rcc->num_entries; i++ ) + { + ratecontrol_entry_t *rce = &rcc->entry[i]; + all_const_bits += rce->misc_bits; + } + + if( all_available_bits < all_const_bits) + { + x264_log( h, X264_LOG_ERROR, "requested bitrate is too low. estimated minimum is %d kbps\n", + (int)(all_const_bits * rcc->fps / (rcc->num_entries * 1000.)) ); + return -1; + } + + /* Blur complexities, to reduce local fluctuation of QP. + * We don't blur the QPs directly, because then one very simple frame + * could drag down the QP of a nearby complex frame and give it more + * bits than intended. */ + for( int i = 0; i < rcc->num_entries; i++ ) + { + ratecontrol_entry_t *rce = &rcc->entry[i]; + double weight_sum = 0; + double cplx_sum = 0; + double weight = 1.0; + double gaussian_weight; + /* weighted average of cplx of future frames */ + for( int j = 1; j < cplxblur*2 && j < rcc->num_entries-i; j++ ) + { + ratecontrol_entry_t *rcj = &rcc->entry[i+j]; + double frame_duration = CLIP_DURATION(rcj->i_duration * timescale) / BASE_FRAME_DURATION; + weight *= 1 - pow( (float)rcj->i_count / rcc->nmb, 2 ); + if( weight < .0001 ) + break; + gaussian_weight = weight * exp( -j*j/200.0 ); + weight_sum += gaussian_weight; + cplx_sum += gaussian_weight * (qscale2bits( rcj, 1 ) - rcj->misc_bits) / frame_duration; + } + /* weighted average of cplx of past frames */ + weight = 1.0; + for( int j = 0; j <= cplxblur*2 && j <= i; j++ ) + { + ratecontrol_entry_t *rcj = &rcc->entry[i-j]; + double frame_duration = CLIP_DURATION(rcj->i_duration * timescale) / BASE_FRAME_DURATION; + gaussian_weight = weight * exp( -j*j/200.0 ); + weight_sum += gaussian_weight; + cplx_sum += gaussian_weight * (qscale2bits( rcj, 1 ) - rcj->misc_bits) / frame_duration; + weight *= 1 - pow( (float)rcj->i_count / rcc->nmb, 2 ); + if( weight < .0001 ) + break; + } + rce->blurred_complexity = cplx_sum / weight_sum; + } + + CHECKED_MALLOC( qscale, sizeof(double)*rcc->num_entries ); + if( filter_size > 1 ) + CHECKED_MALLOC( blurred_qscale, sizeof(double)*rcc->num_entries ); + else + blurred_qscale = qscale; + + /* Search for a factor which, when multiplied by the RCEQ values from + * each frame, adds up to the desired total size. + * There is no exact closed-form solution because of VBV constraints and + * because qscale2bits is not invertible, but we can start with the simple + * approximation of scaling the 1st pass by the ratio of bitrates. + * The search range is probably overkill, but speed doesn't matter here. */ + + expected_bits = 1; + for( int i = 0; i < rcc->num_entries; i++ ) + { + double q = get_qscale(h, &rcc->entry[i], 1.0, i); + expected_bits += qscale2bits(&rcc->entry[i], q); + rcc->last_qscale_for[rcc->entry[i].pict_type] = q; + } + step_mult = all_available_bits / expected_bits; + + rate_factor = 0; + for( double step = 1E4 * step_mult; step > 1E-7 * step_mult; step *= 0.5) + { + expected_bits = 0; + rate_factor += step; + + rcc->last_non_b_pict_type = -1; + rcc->last_accum_p_norm = 1; + rcc->accum_p_norm = 0; + + rcc->last_qscale_for[0] = + rcc->last_qscale_for[1] = + rcc->last_qscale_for[2] = pow( base_cplx, 1 - rcc->qcompress ) / rate_factor; + + /* find qscale */ + for( int i = 0; i < rcc->num_entries; i++ ) + { + qscale[i] = get_qscale( h, &rcc->entry[i], rate_factor, -1 ); + rcc->last_qscale_for[rcc->entry[i].pict_type] = qscale[i]; + } + + /* fixed I/B qscale relative to P */ + for( int i = rcc->num_entries-1; i >= 0; i-- ) + { + qscale[i] = get_diff_limited_q( h, &rcc->entry[i], qscale[i], i ); + assert(qscale[i] >= 0); + } + + /* smooth curve */ + if( filter_size > 1 ) + { + assert( filter_size%2 == 1 ); + for( int i = 0; i < rcc->num_entries; i++ ) + { + ratecontrol_entry_t *rce = &rcc->entry[i]; + double q = 0.0, sum = 0.0; + + for( int j = 0; j < filter_size; j++ ) + { + int idx = i+j-filter_size/2; + double d = idx-i; + double coeff = qblur==0 ? 1.0 : exp( -d*d/(qblur*qblur) ); + if( idx < 0 || idx >= rcc->num_entries ) + continue; + if( rce->pict_type != rcc->entry[idx].pict_type ) + continue; + q += qscale[idx] * coeff; + sum += coeff; + } + blurred_qscale[i] = q/sum; + } + } + + /* find expected bits */ + for( int i = 0; i < rcc->num_entries; i++ ) + { + ratecontrol_entry_t *rce = &rcc->entry[i]; + rce->new_qscale = clip_qscale( h, rce->pict_type, blurred_qscale[i] ); + assert(rce->new_qscale >= 0); + expected_bits += qscale2bits( rce, rce->new_qscale ); + } + + if( expected_bits > all_available_bits ) + rate_factor -= step; + } + + x264_free( qscale ); + if( filter_size > 1 ) + x264_free( blurred_qscale ); + + if( rcc->b_vbv ) + if( vbv_pass2( h, all_available_bits ) ) + return -1; + expected_bits = count_expected_bits( h ); + + if( fabs( expected_bits/all_available_bits - 1.0 ) > 0.01 ) + { + double avgq = 0; + for( int i = 0; i < rcc->num_entries; i++ ) + avgq += rcc->entry[i].new_qscale; + avgq = qscale2qp( avgq / rcc->num_entries ); + + if( expected_bits > all_available_bits || !rcc->b_vbv ) + x264_log( h, X264_LOG_WARNING, "Error: 2pass curve failed to converge\n" ); + x264_log( h, X264_LOG_WARNING, "target: %.2f kbit/s, expected: %.2f kbit/s, avg QP: %.4f\n", + (float)h->param.rc.i_bitrate, + expected_bits * rcc->fps / (rcc->num_entries * 1000.), + avgq ); + if( expected_bits < all_available_bits && avgq < h->param.rc.i_qp_min + 2 ) + { + if( h->param.rc.i_qp_min > 0 ) + x264_log( h, X264_LOG_WARNING, "try reducing target bitrate or reducing qp_min (currently %d)\n", h->param.rc.i_qp_min ); + else + x264_log( h, X264_LOG_WARNING, "try reducing target bitrate\n" ); + } + else if( expected_bits > all_available_bits && avgq > h->param.rc.i_qp_max - 2 ) + { + if( h->param.rc.i_qp_max < QP_MAX ) + x264_log( h, X264_LOG_WARNING, "try increasing target bitrate or increasing qp_max (currently %d)\n", h->param.rc.i_qp_max ); + else + x264_log( h, X264_LOG_WARNING, "try increasing target bitrate\n"); + } + else if( !(rcc->b_2pass && rcc->b_vbv) ) + x264_log( h, X264_LOG_WARNING, "internal error\n" ); + } + + return 0; +fail: + return -1; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/ratecontrol.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/ratecontrol.h new file mode 100644 index 00000000..168b515c --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/ratecontrol.h @@ -0,0 +1,66 @@ +/***************************************************************************** + * ratecontrol.h: ratecontrol + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Loren Merritt + * Laurent Aimar + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_RATECONTROL_H +#define X264_RATECONTROL_H + +/* Completely arbitrary. Ratecontrol lowers relative quality at higher framerates + * and the reverse at lower framerates; this serves as the center of the curve. + * Halve all the values for frame-packed 3D to compensate for the "doubled" + * framerate. */ +#define BASE_FRAME_DURATION (0.04f / ((h->param.i_frame_packing == 5)+1)) + +/* Arbitrary limitations as a sanity check. */ +#define MAX_FRAME_DURATION (1.00f / ((h->param.i_frame_packing == 5)+1)) +#define MIN_FRAME_DURATION (0.01f / ((h->param.i_frame_packing == 5)+1)) + +#define CLIP_DURATION(f) x264_clip3f(f,MIN_FRAME_DURATION,MAX_FRAME_DURATION) + +int x264_ratecontrol_new ( x264_t * ); +void x264_ratecontrol_delete( x264_t * ); + +void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ); +int x264_encoder_reconfig_apply( x264_t *h, x264_param_t *param ); + +void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_offsets ); +int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets ); +int x264_reference_build_list_optimal( x264_t *h ); +void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ); +void x264_ratecontrol_zone_init( x264_t * ); +void x264_ratecontrol_start( x264_t *, int i_force_qp, int overhead ); +int x264_ratecontrol_slice_type( x264_t *, int i_frame ); +void x264_ratecontrol_set_weights( x264_t *h, x264_frame_t *frm ); +int x264_ratecontrol_mb( x264_t *, int bits ); +int x264_ratecontrol_qp( x264_t * ); +int x264_ratecontrol_mb_qp( x264_t *h ); +int x264_ratecontrol_end( x264_t *, int bits, int *filler ); +void x264_ratecontrol_summary( x264_t * ); +int x264_rc_analyse_slice( x264_t *h ); +void x264_threads_distribute_ratecontrol( x264_t *h ); +void x264_threads_merge_ratecontrol( x264_t *h ); +void x264_hrd_fullness( x264_t *h ); +#endif + diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/rdo.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/rdo.c new file mode 100644 index 00000000..a6865bd3 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/rdo.c @@ -0,0 +1,1165 @@ +/***************************************************************************** + * rdo.c: rate-distortion optimization + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +/* duplicate all the writer functions, just calculating bit cost + * instead of writing the bitstream. + * TODO: use these for fast 1st pass too. */ + +#define RDO_SKIP_BS 1 + +/* Transition and size tables for abs<9 MVD and residual coding */ +/* Consist of i_prefix-2 1s, one zero, and a bypass sign bit */ +uint8_t x264_cabac_transition_unary[15][128]; +uint16_t x264_cabac_size_unary[15][128]; +/* Transition and size tables for abs>9 MVD */ +/* Consist of 5 1s and a bypass sign bit */ +static uint8_t cabac_transition_5ones[128]; +static uint16_t cabac_size_5ones[128]; + +/* CAVLC: produces exactly the same bit count as a normal encode */ +/* this probably still leaves some unnecessary computations */ +#define bs_write1(s,v) ((s)->i_bits_encoded += 1) +#define bs_write(s,n,v) ((s)->i_bits_encoded += (n)) +#define bs_write_ue(s,v) ((s)->i_bits_encoded += bs_size_ue(v)) +#define bs_write_se(s,v) ((s)->i_bits_encoded += bs_size_se(v)) +#define bs_write_te(s,v,l) ((s)->i_bits_encoded += bs_size_te(v,l)) +#define x264_macroblock_write_cavlc static x264_macroblock_size_cavlc +#include "cavlc.c" + +/* CABAC: not exactly the same. x264_cabac_size_decision() keeps track of + * fractional bits, but only finite precision. */ +#undef x264_cabac_encode_decision +#undef x264_cabac_encode_decision_noup +#undef x264_cabac_encode_bypass +#undef x264_cabac_encode_terminal +#define x264_cabac_encode_decision(c,x,v) x264_cabac_size_decision(c,x,v) +#define x264_cabac_encode_decision_noup(c,x,v) x264_cabac_size_decision_noup(c,x,v) +#define x264_cabac_encode_terminal(c) ((c)->f8_bits_encoded += 7) +#define x264_cabac_encode_bypass(c,v) ((c)->f8_bits_encoded += 256) +#define x264_cabac_encode_ue_bypass(c,e,v) ((c)->f8_bits_encoded += (bs_size_ue_big(v+(1<mc.memcpy_aligned( &cabac_tmp.f8_bits_encoded, &h->cabac.f8_bits_encoded, \ + sizeof(int) + (CHROMA444 ? 1024+12 : 460) ) +#define COPY_CABAC_PART( pos, size ) memcpy( &cb->state[pos], &h->cabac.state[pos], size ) + +static ALWAYS_INLINE uint64_t cached_hadamard( x264_t *h, int size, int x, int y ) +{ + static const uint8_t hadamard_shift_x[4] = {4, 4, 3, 3}; + static const uint8_t hadamard_shift_y[4] = {4-0, 3-0, 4-1, 3-1}; + static const uint8_t hadamard_offset[4] = {0, 1, 3, 5}; + int cache_index = (x >> hadamard_shift_x[size]) + (y >> hadamard_shift_y[size]) + + hadamard_offset[size]; + uint64_t res = h->mb.pic.fenc_hadamard_cache[cache_index]; + if( res ) + return res - 1; + else + { + pixel *fenc = h->mb.pic.p_fenc[0] + x + y*FENC_STRIDE; + res = h->pixf.hadamard_ac[size]( fenc, FENC_STRIDE ); + h->mb.pic.fenc_hadamard_cache[cache_index] = res + 1; + return res; + } +} + +static ALWAYS_INLINE int cached_satd( x264_t *h, int size, int x, int y ) +{ + static const uint8_t satd_shift_x[3] = {3, 2, 2}; + static const uint8_t satd_shift_y[3] = {2-1, 3-2, 2-2}; + static const uint8_t satd_offset[3] = {0, 8, 16}; + ALIGNED_16( static pixel zero[16] ) = {0}; + int cache_index = (x >> satd_shift_x[size - PIXEL_8x4]) + (y >> satd_shift_y[size - PIXEL_8x4]) + + satd_offset[size - PIXEL_8x4]; + int res = h->mb.pic.fenc_satd_cache[cache_index]; + if( res ) + return res - 1; + else + { + pixel *fenc = h->mb.pic.p_fenc[0] + x + y*FENC_STRIDE; + int dc = h->pixf.sad[size]( fenc, FENC_STRIDE, zero, 0 ) >> 1; + res = h->pixf.satd[size]( fenc, FENC_STRIDE, zero, 0 ) - dc; + h->mb.pic.fenc_satd_cache[cache_index] = res + 1; + return res; + } +} + +/* Psy RD distortion metric: SSD plus "Absolute Difference of Complexities" */ +/* SATD and SA8D are used to measure block complexity. */ +/* The difference between SATD and SA8D scores are both used to avoid bias from the DCT size. Using SATD */ +/* only, for example, results in overusage of 8x8dct, while the opposite occurs when using SA8D. */ + +/* FIXME: Is there a better metric than averaged SATD/SA8D difference for complexity difference? */ +/* Hadamard transform is recursive, so a SATD+SA8D can be done faster by taking advantage of this fact. */ +/* This optimization can also be used in non-RD transform decision. */ + +static inline int ssd_plane( x264_t *h, int size, int p, int x, int y ) +{ + ALIGNED_16( static pixel zero[16] ) = {0}; + int satd = 0; + pixel *fdec = h->mb.pic.p_fdec[p] + x + y*FDEC_STRIDE; + pixel *fenc = h->mb.pic.p_fenc[p] + x + y*FENC_STRIDE; + if( p == 0 && h->mb.i_psy_rd ) + { + /* If the plane is smaller than 8x8, we can't do an SA8D; this probably isn't a big problem. */ + if( size <= PIXEL_8x8 ) + { + uint64_t fdec_acs = h->pixf.hadamard_ac[size]( fdec, FDEC_STRIDE ); + uint64_t fenc_acs = cached_hadamard( h, size, x, y ); + satd = abs((int32_t)fdec_acs - (int32_t)fenc_acs) + + abs((int32_t)(fdec_acs>>32) - (int32_t)(fenc_acs>>32)); + satd >>= 1; + } + else + { + int dc = h->pixf.sad[size]( fdec, FDEC_STRIDE, zero, 0 ) >> 1; + satd = abs(h->pixf.satd[size]( fdec, FDEC_STRIDE, zero, 0 ) - dc - cached_satd( h, size, x, y )); + } + satd = (satd * h->mb.i_psy_rd * h->mb.i_psy_rd_lambda + 128) >> 8; + } + return h->pixf.ssd[size](fenc, FENC_STRIDE, fdec, FDEC_STRIDE) + satd; +} + +static inline int ssd_mb( x264_t *h ) +{ + int chroma_size = h->luma2chroma_pixel[PIXEL_16x16]; + int chroma_ssd = ssd_plane(h, chroma_size, 1, 0, 0) + ssd_plane(h, chroma_size, 2, 0, 0); + chroma_ssd = ((uint64_t)chroma_ssd * h->mb.i_chroma_lambda2_offset + 128) >> 8; + return ssd_plane(h, PIXEL_16x16, 0, 0, 0) + chroma_ssd; +} + +static int x264_rd_cost_mb( x264_t *h, int i_lambda2 ) +{ + int b_transform_bak = h->mb.b_transform_8x8; + int i_ssd; + int i_bits; + int type_bak = h->mb.i_type; + + x264_macroblock_encode( h ); + + if( h->mb.b_deblock_rdo ) + x264_macroblock_deblock( h ); + + i_ssd = ssd_mb( h ); + + if( IS_SKIP( h->mb.i_type ) ) + { + i_bits = (1 * i_lambda2 + 128) >> 8; + } + else if( h->param.b_cabac ) + { + x264_cabac_t cabac_tmp; + COPY_CABAC; + x264_macroblock_size_cabac( h, &cabac_tmp ); + i_bits = ( (uint64_t)cabac_tmp.f8_bits_encoded * i_lambda2 + 32768 ) >> 16; + } + else + { + x264_macroblock_size_cavlc( h ); + i_bits = ( (uint64_t)h->out.bs.i_bits_encoded * i_lambda2 + 128 ) >> 8; + } + + h->mb.b_transform_8x8 = b_transform_bak; + h->mb.i_type = type_bak; + + return X264_MIN( i_ssd + i_bits, COST_MAX ); +} + +/* partition RD functions use 8 bits more precision to avoid large rounding errors at low QPs */ + +static uint64_t x264_rd_cost_subpart( x264_t *h, int i_lambda2, int i4, int i_pixel ) +{ + uint64_t i_ssd, i_bits; + + x264_macroblock_encode_p4x4( h, i4 ); + if( i_pixel == PIXEL_8x4 ) + x264_macroblock_encode_p4x4( h, i4+1 ); + if( i_pixel == PIXEL_4x8 ) + x264_macroblock_encode_p4x4( h, i4+2 ); + + i_ssd = ssd_plane( h, i_pixel, 0, block_idx_x[i4]*4, block_idx_y[i4]*4 ); + if( CHROMA444 ) + { + int chromassd = ssd_plane( h, i_pixel, 1, block_idx_x[i4]*4, block_idx_y[i4]*4 ) + + ssd_plane( h, i_pixel, 2, block_idx_x[i4]*4, block_idx_y[i4]*4 ); + chromassd = ((uint64_t)chromassd * h->mb.i_chroma_lambda2_offset + 128) >> 8; + i_ssd += chromassd; + } + + if( h->param.b_cabac ) + { + x264_cabac_t cabac_tmp; + COPY_CABAC; + x264_subpartition_size_cabac( h, &cabac_tmp, i4, i_pixel ); + i_bits = ( (uint64_t)cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8; + } + else + i_bits = x264_subpartition_size_cavlc( h, i4, i_pixel ); + + return (i_ssd<<8) + i_bits; +} + +uint64_t x264_rd_cost_part( x264_t *h, int i_lambda2, int i4, int i_pixel ) +{ + uint64_t i_ssd, i_bits; + int i8 = i4 >> 2; + + if( i_pixel == PIXEL_16x16 ) + { + int i_cost = x264_rd_cost_mb( h, i_lambda2 ); + return i_cost; + } + + if( i_pixel > PIXEL_8x8 ) + return x264_rd_cost_subpart( h, i_lambda2, i4, i_pixel ); + + h->mb.i_cbp_luma = 0; + + x264_macroblock_encode_p8x8( h, i8 ); + if( i_pixel == PIXEL_16x8 ) + x264_macroblock_encode_p8x8( h, i8+1 ); + if( i_pixel == PIXEL_8x16 ) + x264_macroblock_encode_p8x8( h, i8+2 ); + + int ssd_x = 8*(i8&1); + int ssd_y = 8*(i8>>1); + i_ssd = ssd_plane( h, i_pixel, 0, ssd_x, ssd_y ); + int chromapix = h->luma2chroma_pixel[i_pixel]; + int chromassd = ssd_plane( h, chromapix, 1, ssd_x>>CHROMA_H_SHIFT, ssd_y>>CHROMA_V_SHIFT ) + + ssd_plane( h, chromapix, 2, ssd_x>>CHROMA_H_SHIFT, ssd_y>>CHROMA_V_SHIFT ); + i_ssd += ((uint64_t)chromassd * h->mb.i_chroma_lambda2_offset + 128) >> 8; + + if( h->param.b_cabac ) + { + x264_cabac_t cabac_tmp; + COPY_CABAC; + x264_partition_size_cabac( h, &cabac_tmp, i8, i_pixel ); + i_bits = ( (uint64_t)cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8; + } + else + i_bits = (uint64_t)x264_partition_size_cavlc( h, i8, i_pixel ) * i_lambda2; + + return (i_ssd<<8) + i_bits; +} + +static uint64_t x264_rd_cost_i8x8( x264_t *h, int i_lambda2, int i8, int i_mode, pixel edge[4][32] ) +{ + uint64_t i_ssd, i_bits; + int plane_count = CHROMA444 ? 3 : 1; + int i_qp = h->mb.i_qp; + h->mb.i_cbp_luma &= ~(1<mb.b_transform_8x8 = 1; + + for( int p = 0; p < plane_count; p++ ) + { + x264_mb_encode_i8x8( h, p, i8, i_qp, i_mode, edge[p], 1 ); + i_qp = h->mb.i_chroma_qp; + } + + i_ssd = ssd_plane( h, PIXEL_8x8, 0, (i8&1)*8, (i8>>1)*8 ); + if( CHROMA444 ) + { + int chromassd = ssd_plane( h, PIXEL_8x8, 1, (i8&1)*8, (i8>>1)*8 ) + + ssd_plane( h, PIXEL_8x8, 2, (i8&1)*8, (i8>>1)*8 ); + chromassd = ((uint64_t)chromassd * h->mb.i_chroma_lambda2_offset + 128) >> 8; + i_ssd += chromassd; + } + + if( h->param.b_cabac ) + { + x264_cabac_t cabac_tmp; + COPY_CABAC; + x264_partition_i8x8_size_cabac( h, &cabac_tmp, i8, i_mode ); + i_bits = ( (uint64_t)cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8; + } + else + i_bits = (uint64_t)x264_partition_i8x8_size_cavlc( h, i8, i_mode ) * i_lambda2; + + return (i_ssd<<8) + i_bits; +} + +static uint64_t x264_rd_cost_i4x4( x264_t *h, int i_lambda2, int i4, int i_mode ) +{ + uint64_t i_ssd, i_bits; + int plane_count = CHROMA444 ? 3 : 1; + int i_qp = h->mb.i_qp; + + for( int p = 0; p < plane_count; p++ ) + { + x264_mb_encode_i4x4( h, p, i4, i_qp, i_mode, 1 ); + i_qp = h->mb.i_chroma_qp; + } + + i_ssd = ssd_plane( h, PIXEL_4x4, 0, block_idx_x[i4]*4, block_idx_y[i4]*4 ); + if( CHROMA444 ) + { + int chromassd = ssd_plane( h, PIXEL_4x4, 1, block_idx_x[i4]*4, block_idx_y[i4]*4 ) + + ssd_plane( h, PIXEL_4x4, 2, block_idx_x[i4]*4, block_idx_y[i4]*4 ); + chromassd = ((uint64_t)chromassd * h->mb.i_chroma_lambda2_offset + 128) >> 8; + i_ssd += chromassd; + } + + if( h->param.b_cabac ) + { + x264_cabac_t cabac_tmp; + COPY_CABAC; + x264_partition_i4x4_size_cabac( h, &cabac_tmp, i4, i_mode ); + i_bits = ( (uint64_t)cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8; + } + else + i_bits = (uint64_t)x264_partition_i4x4_size_cavlc( h, i4, i_mode ) * i_lambda2; + + return (i_ssd<<8) + i_bits; +} + +static uint64_t x264_rd_cost_chroma( x264_t *h, int i_lambda2, int i_mode, int b_dct ) +{ + uint64_t i_ssd, i_bits; + + if( b_dct ) + x264_mb_encode_chroma( h, 0, h->mb.i_chroma_qp ); + + int chromapix = h->luma2chroma_pixel[PIXEL_16x16]; + i_ssd = ssd_plane( h, chromapix, 1, 0, 0 ) + + ssd_plane( h, chromapix, 2, 0, 0 ); + + h->mb.i_chroma_pred_mode = i_mode; + + if( h->param.b_cabac ) + { + x264_cabac_t cabac_tmp; + COPY_CABAC; + x264_chroma_size_cabac( h, &cabac_tmp ); + i_bits = ( (uint64_t)cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8; + } + else + i_bits = (uint64_t)x264_chroma_size_cavlc( h ) * i_lambda2; + + return (i_ssd<<8) + i_bits; +} +/**************************************************************************** + * Trellis RD quantization + ****************************************************************************/ + +#define TRELLIS_SCORE_MAX -1LL // negative marks the node as invalid +#define TRELLIS_SCORE_BIAS 1LL<<60; // bias so that all valid scores are positive, even after negative contributions from psy +#define CABAC_SIZE_BITS 8 +#define LAMBDA_BITS 4 + +/* precalculate the cost of coding various combinations of bits in a single context */ +void x264_rdo_init( void ) +{ + for( int i_prefix = 0; i_prefix < 15; i_prefix++ ) + { + for( int i_ctx = 0; i_ctx < 128; i_ctx++ ) + { + int f8_bits = 0; + uint8_t ctx = i_ctx; + + for( int i = 1; i < i_prefix; i++ ) + f8_bits += x264_cabac_size_decision2( &ctx, 1 ); + if( i_prefix > 0 && i_prefix < 14 ) + f8_bits += x264_cabac_size_decision2( &ctx, 0 ); + f8_bits += 1 << CABAC_SIZE_BITS; //sign + + x264_cabac_size_unary[i_prefix][i_ctx] = f8_bits; + x264_cabac_transition_unary[i_prefix][i_ctx] = ctx; + } + } + for( int i_ctx = 0; i_ctx < 128; i_ctx++ ) + { + int f8_bits = 0; + uint8_t ctx = i_ctx; + + for( int i = 0; i < 5; i++ ) + f8_bits += x264_cabac_size_decision2( &ctx, 1 ); + f8_bits += 1 << CABAC_SIZE_BITS; //sign + + cabac_size_5ones[i_ctx] = f8_bits; + cabac_transition_5ones[i_ctx] = ctx; + } +} + +typedef struct +{ + uint64_t score; + int level_idx; // index into level_tree[] + uint8_t cabac_state[4]; // just contexts 0,4,8,9 of the 10 relevant to coding abs_level_m1 +} trellis_node_t; + +typedef struct +{ + uint16_t next; + uint16_t abs_level; +} trellis_level_t; + +// TODO: +// save cabac state between blocks? +// use trellis' RD score instead of x264_mb_decimate_score? +// code 8x8 sig/last flags forwards with deadzone and save the contexts at +// each position? +// change weights when using CQMs? + +// possible optimizations: +// make scores fit in 32bit +// save quantized coefs during rd, to avoid a duplicate trellis in the final encode +// if trellissing all MBRD modes, finish SSD calculation so we can skip all of +// the normal dequant/idct/ssd/cabac + +// the unquant_mf here is not the same as dequant_mf: +// in normal operation (dct->quant->dequant->idct) the dct and idct are not +// normalized. quant/dequant absorb those scaling factors. +// in this function, we just do (quant->unquant) and want the output to be +// comparable to the input. so unquant is the direct inverse of quant, +// and uses the dct scaling factors, not the idct ones. + +#define SIGN(x,y) ((x^(y >> 31))-(y >> 31)) + +#define SET_LEVEL(ndst, nsrc, l) {\ + if( sizeof(trellis_level_t) == sizeof(uint32_t) )\ + M32( &level_tree[levels_used] ) = pack16to32( nsrc.level_idx, l );\ + else\ + level_tree[levels_used] = (trellis_level_t){ nsrc.level_idx, l };\ + ndst.level_idx = levels_used;\ + levels_used++;\ +} + +// encode all values of the dc coef in a block which is known to have no ac +static NOINLINE +int trellis_dc_shortcut( int sign_coef, int quant_coef, int unquant_mf, int coef_weight, int lambda2, uint8_t *cabac_state, int cost_sig ) +{ + uint64_t bscore = TRELLIS_SCORE_MAX; + int ret = 0; + int q = abs( quant_coef ); + for( int abs_level = q-1; abs_level <= q; abs_level++ ) + { + int unquant_abs_level = (unquant_mf * abs_level + 128) >> 8; + + /* Optimize rounding for DC coefficients in DC-only luma 4x4/8x8 blocks. */ + int d = sign_coef - ((SIGN(unquant_abs_level, sign_coef) + 8)&~15); + uint64_t score = (uint64_t)d*d * coef_weight; + + /* code the proposed level, and count how much entropy it would take */ + if( abs_level ) + { + unsigned f8_bits = cost_sig; + int prefix = X264_MIN( abs_level - 1, 14 ); + f8_bits += x264_cabac_size_decision_noup2( cabac_state+1, prefix > 0 ); + f8_bits += x264_cabac_size_unary[prefix][cabac_state[5]]; + if( abs_level >= 15 ) + f8_bits += bs_size_ue_big( abs_level - 15 ) << CABAC_SIZE_BITS; + score += (uint64_t)f8_bits * lambda2 >> ( CABAC_SIZE_BITS - LAMBDA_BITS ); + } + + COPY2_IF_LT( bscore, score, ret, abs_level ); + } + return SIGN(ret, sign_coef); +} + +// encode one value of one coef in one context +static ALWAYS_INLINE +int trellis_coef( int j, int const_level, int abs_level, int prefix, int suffix_cost, + int node_ctx, int level1_ctx, int levelgt1_ctx, uint64_t ssd, int cost_siglast[3], + trellis_node_t *nodes_cur, trellis_node_t *nodes_prev, + trellis_level_t *level_tree, int levels_used, int lambda2, uint8_t *level_state ) +{ + uint64_t score = nodes_prev[j].score + ssd; + /* code the proposed level, and count how much entropy it would take */ + unsigned f8_bits = cost_siglast[ j ? 1 : 2 ]; + uint8_t level1_state = (j >= 3) ? nodes_prev[j].cabac_state[level1_ctx>>2] : level_state[level1_ctx]; + f8_bits += x264_cabac_entropy[level1_state ^ (const_level > 1)]; + uint8_t levelgt1_state; + if( const_level > 1 ) + { + levelgt1_state = j >= 6 ? nodes_prev[j].cabac_state[levelgt1_ctx-6] : level_state[levelgt1_ctx]; + f8_bits += x264_cabac_size_unary[prefix][levelgt1_state] + suffix_cost; + } + else + f8_bits += 1 << CABAC_SIZE_BITS; + score += (uint64_t)f8_bits * lambda2 >> ( CABAC_SIZE_BITS - LAMBDA_BITS ); + + /* save the node if it's better than any existing node with the same cabac ctx */ + if( score < nodes_cur[node_ctx].score ) + { + nodes_cur[node_ctx].score = score; + if( j == 2 || (j <= 3 && node_ctx == 4) ) // init from input state + M32(nodes_cur[node_ctx].cabac_state) = M32(level_state+12); + else if( j >= 3 ) + M32(nodes_cur[node_ctx].cabac_state) = M32(nodes_prev[j].cabac_state); + if( j >= 3 ) // skip the transition if we're not going to reuse the context + nodes_cur[node_ctx].cabac_state[level1_ctx>>2] = x264_cabac_transition[level1_state][const_level > 1]; + if( const_level > 1 && node_ctx == 7 ) + nodes_cur[node_ctx].cabac_state[levelgt1_ctx-6] = x264_cabac_transition_unary[prefix][levelgt1_state]; + nodes_cur[node_ctx].level_idx = nodes_prev[j].level_idx; + SET_LEVEL( nodes_cur[node_ctx], nodes_prev[j], abs_level ); + } + return levels_used; +} + +// encode one value of one coef in all contexts, templated by which value that is. +// in ctx_lo, the set of live nodes is contiguous and starts at ctx0, so return as soon as we've seen one failure. +// in ctx_hi, they're contiguous within each block of 4 ctxs, but not necessarily starting at the beginning, +// so exploiting that would be more complicated. +static NOINLINE +int trellis_coef0_0( uint64_t ssd0, trellis_node_t *nodes_cur, trellis_node_t *nodes_prev, + trellis_level_t *level_tree, int levels_used ) +{ + nodes_cur[0].score = nodes_prev[0].score + ssd0; + nodes_cur[0].level_idx = nodes_prev[0].level_idx; + for( int j = 1; j < 4 && (int64_t)nodes_prev[j].score >= 0; j++ ) + { + nodes_cur[j].score = nodes_prev[j].score; + if( j >= 3 ) + M32(nodes_cur[j].cabac_state) = M32(nodes_prev[j].cabac_state); + SET_LEVEL( nodes_cur[j], nodes_prev[j], 0 ); + } + return levels_used; +} + +static NOINLINE +int trellis_coef0_1( uint64_t ssd0, trellis_node_t *nodes_cur, trellis_node_t *nodes_prev, + trellis_level_t *level_tree, int levels_used ) +{ + for( int j = 1; j < 8; j++ ) + // this branch only affects speed, not function; there's nothing wrong with updating invalid nodes in coef0. + if( (int64_t)nodes_prev[j].score >= 0 ) + { + nodes_cur[j].score = nodes_prev[j].score; + if( j >= 3 ) + M32(nodes_cur[j].cabac_state) = M32(nodes_prev[j].cabac_state); + SET_LEVEL( nodes_cur[j], nodes_prev[j], 0 ); + } + return levels_used; +} + +#define COEF(const_level, ctx_hi, j, ...)\ + if( !j || (int64_t)nodes_prev[j].score >= 0 )\ + levels_used = trellis_coef( j, const_level, abs_level, prefix, suffix_cost, __VA_ARGS__,\ + j?ssd1:ssd0, cost_siglast, nodes_cur, nodes_prev,\ + level_tree, levels_used, lambda2, level_state );\ + else if( !ctx_hi )\ + return levels_used; + +static NOINLINE +int trellis_coef1_0( uint64_t ssd0, uint64_t ssd1, int cost_siglast[3], + trellis_node_t *nodes_cur, trellis_node_t *nodes_prev, + trellis_level_t *level_tree, int levels_used, int lambda2, + uint8_t *level_state ) +{ + int abs_level = 1, prefix = 1, suffix_cost = 0; + COEF( 1, 0, 0, 1, 1, 0 ); + COEF( 1, 0, 1, 2, 2, 0 ); + COEF( 1, 0, 2, 3, 3, 0 ); + COEF( 1, 0, 3, 3, 4, 0 ); + return levels_used; +} + +static NOINLINE +int trellis_coef1_1( uint64_t ssd0, uint64_t ssd1, int cost_siglast[3], + trellis_node_t *nodes_cur, trellis_node_t *nodes_prev, + trellis_level_t *level_tree, int levels_used, int lambda2, + uint8_t *level_state ) +{ + int abs_level = 1, prefix = 1, suffix_cost = 0; + COEF( 1, 1, 1, 2, 2, 0 ); + COEF( 1, 1, 2, 3, 3, 0 ); + COEF( 1, 1, 3, 3, 4, 0 ); + COEF( 1, 1, 4, 4, 0, 0 ); + COEF( 1, 1, 5, 5, 0, 0 ); + COEF( 1, 1, 6, 6, 0, 0 ); + COEF( 1, 1, 7, 7, 0, 0 ); + return levels_used; +} + +static NOINLINE +int trellis_coefn_0( int abs_level, uint64_t ssd0, uint64_t ssd1, int cost_siglast[3], + trellis_node_t *nodes_cur, trellis_node_t *nodes_prev, + trellis_level_t *level_tree, int levels_used, int lambda2, + uint8_t *level_state, int levelgt1_ctx ) +{ + int prefix = X264_MIN( abs_level-1, 14 ); + int suffix_cost = abs_level >= 15 ? bs_size_ue_big( abs_level - 15 ) << CABAC_SIZE_BITS : 0; + COEF( 2, 0, 0, 4, 1, 5 ); + COEF( 2, 0, 1, 4, 2, 5 ); + COEF( 2, 0, 2, 4, 3, 5 ); + COEF( 2, 0, 3, 4, 4, 5 ); + return levels_used; +} + +static NOINLINE +int trellis_coefn_1( int abs_level, uint64_t ssd0, uint64_t ssd1, int cost_siglast[3], + trellis_node_t *nodes_cur, trellis_node_t *nodes_prev, + trellis_level_t *level_tree, int levels_used, int lambda2, + uint8_t *level_state, int levelgt1_ctx ) +{ + int prefix = X264_MIN( abs_level-1, 14 ); + int suffix_cost = abs_level >= 15 ? bs_size_ue_big( abs_level - 15 ) << CABAC_SIZE_BITS : 0; + COEF( 2, 1, 1, 4, 2, 5 ); + COEF( 2, 1, 2, 4, 3, 5 ); + COEF( 2, 1, 3, 4, 4, 5 ); + COEF( 2, 1, 4, 5, 0, 6 ); + COEF( 2, 1, 5, 6, 0, 7 ); + COEF( 2, 1, 6, 7, 0, 8 ); + COEF( 2, 1, 7, 7, 0, levelgt1_ctx ); + return levels_used; +} + +static ALWAYS_INLINE +int quant_trellis_cabac( x264_t *h, dctcoef *dct, + udctcoef *quant_mf, udctcoef *quant_bias, const int *unquant_mf, + const uint8_t *zigzag, int ctx_block_cat, int lambda2, int b_ac, + int b_chroma, int dc, int num_coefs, int idx ) +{ + ALIGNED_ARRAY_64( dctcoef, orig_coefs, [64] ); + ALIGNED_ARRAY_64( dctcoef, quant_coefs, [64] ); + const uint32_t *coef_weight1 = num_coefs == 64 ? x264_dct8_weight_tab : x264_dct4_weight_tab; + const uint32_t *coef_weight2 = num_coefs == 64 ? x264_dct8_weight2_tab : x264_dct4_weight2_tab; + const int b_interlaced = MB_INTERLACED; + uint8_t *cabac_state_sig = &h->cabac.state[ x264_significant_coeff_flag_offset[b_interlaced][ctx_block_cat] ]; + uint8_t *cabac_state_last = &h->cabac.state[ x264_last_coeff_flag_offset[b_interlaced][ctx_block_cat] ]; + int levelgt1_ctx = b_chroma && dc ? 8 : 9; + + if( dc ) + { + if( num_coefs == 16 ) + { + memcpy( orig_coefs, dct, sizeof(dctcoef)*16 ); + if( !h->quantf.quant_4x4_dc( dct, quant_mf[0] >> 1, quant_bias[0] << 1 ) ) + return 0; + h->zigzagf.scan_4x4( quant_coefs, dct ); + } + else + { + memcpy( orig_coefs, dct, sizeof(dctcoef)*num_coefs ); + int nz = h->quantf.quant_2x2_dc( &dct[0], quant_mf[0] >> 1, quant_bias[0] << 1 ); + if( num_coefs == 8 ) + nz |= h->quantf.quant_2x2_dc( &dct[4], quant_mf[0] >> 1, quant_bias[0] << 1 ); + if( !nz ) + return 0; + for( int i = 0; i < num_coefs; i++ ) + quant_coefs[i] = dct[zigzag[i]]; + } + } + else + { + if( num_coefs == 64 ) + { + h->mc.memcpy_aligned( orig_coefs, dct, sizeof(dctcoef)*64 ); + if( !h->quantf.quant_8x8( dct, quant_mf, quant_bias ) ) + return 0; + h->zigzagf.scan_8x8( quant_coefs, dct ); + } + else //if( num_coefs == 16 ) + { + memcpy( orig_coefs, dct, sizeof(dctcoef)*16 ); + if( !h->quantf.quant_4x4( dct, quant_mf, quant_bias ) ) + return 0; + h->zigzagf.scan_4x4( quant_coefs, dct ); + } + } + + int last_nnz = h->quantf.coeff_last[ctx_block_cat]( quant_coefs+b_ac )+b_ac; + uint8_t *cabac_state = &h->cabac.state[ x264_coeff_abs_level_m1_offset[ctx_block_cat] ]; + + /* shortcut for dc-only blocks. + * this doesn't affect the output, but saves some unnecessary computation. */ + if( last_nnz == 0 && !dc ) + { + int cost_sig = x264_cabac_size_decision_noup2( &cabac_state_sig[0], 1 ) + + x264_cabac_size_decision_noup2( &cabac_state_last[0], 1 ); + dct[0] = trellis_dc_shortcut( orig_coefs[0], quant_coefs[0], unquant_mf[0], coef_weight2[0], lambda2, cabac_state, cost_sig ); + return !!dct[0]; + } + +#if HAVE_MMX && ARCH_X86_64 && !defined( __MACH__ ) +#define TRELLIS_ARGS unquant_mf, zigzag, lambda2, last_nnz, orig_coefs, quant_coefs, dct,\ + cabac_state_sig, cabac_state_last, M64(cabac_state), M16(cabac_state+8) + if( num_coefs == 16 && !dc ) + if( b_chroma || !h->mb.i_psy_trellis ) + return h->quantf.trellis_cabac_4x4( TRELLIS_ARGS, b_ac ); + else + return h->quantf.trellis_cabac_4x4_psy( TRELLIS_ARGS, b_ac, h->mb.pic.fenc_dct4[idx&15], h->mb.i_psy_trellis ); + else if( num_coefs == 64 && !dc ) + if( b_chroma || !h->mb.i_psy_trellis ) + return h->quantf.trellis_cabac_8x8( TRELLIS_ARGS, b_interlaced ); + else + return h->quantf.trellis_cabac_8x8_psy( TRELLIS_ARGS, b_interlaced, h->mb.pic.fenc_dct8[idx&3], h->mb.i_psy_trellis); + else if( num_coefs == 8 && dc ) + return h->quantf.trellis_cabac_chroma_422_dc( TRELLIS_ARGS ); + else if( dc ) + return h->quantf.trellis_cabac_dc( TRELLIS_ARGS, num_coefs-1 ); +#endif + + // (# of coefs) * (# of ctx) * (# of levels tried) = 1024 + // we don't need to keep all of those: (# of coefs) * (# of ctx) would be enough, + // but it takes more time to remove dead states than you gain in reduced memory. + trellis_level_t level_tree[64*8*2]; + int levels_used = 1; + /* init trellis */ + trellis_node_t nodes[2][8]; + trellis_node_t *nodes_cur = nodes[0]; + trellis_node_t *nodes_prev = nodes[1]; + trellis_node_t *bnode; + for( int j = 1; j < 4; j++ ) + nodes_cur[j].score = TRELLIS_SCORE_MAX; + nodes_cur[0].score = TRELLIS_SCORE_BIAS; + nodes_cur[0].level_idx = 0; + level_tree[0].abs_level = 0; + level_tree[0].next = 0; + ALIGNED_4( uint8_t level_state[16] ); + memcpy( level_state, cabac_state, 10 ); + level_state[12] = cabac_state[0]; // packed subset for copying into trellis_node_t + level_state[13] = cabac_state[4]; + level_state[14] = cabac_state[8]; + level_state[15] = cabac_state[9]; + + idx &= num_coefs == 64 ? 3 : 15; + + // coefs are processed in reverse order, because that's how the abs value is coded. + // last_coef and significant_coef flags are normally coded in forward order, but + // we have to reverse them to match the levels. + // in 4x4 blocks, last_coef and significant_coef use a separate context for each + // position, so the order doesn't matter, and we don't even have to update their contexts. + // in 8x8 blocks, some positions share contexts, so we'll just have to hope that + // cabac isn't too sensitive. + int i = last_nnz; +#define TRELLIS_LOOP(ctx_hi)\ + for( ; i >= b_ac; i-- )\ + {\ + /* skip 0s: this doesn't affect the output, but saves some unnecessary computation. */\ + if( !quant_coefs[i] )\ + {\ + /* no need to calculate ssd of 0s: it's the same in all nodes.\ + * no need to modify level_tree for ctx=0: it starts with an infinite loop of 0s. + * subtracting from one score is equivalent to adding to the rest. */\ + if( !ctx_hi )\ + {\ + int sigindex = !dc && num_coefs == 64 ? x264_significant_coeff_flag_offset_8x8[b_interlaced][i] :\ + b_chroma && dc && num_coefs == 8 ? x264_coeff_flag_offset_chroma_422_dc[i] : i;\ + uint64_t cost_sig0 = x264_cabac_size_decision_noup2( &cabac_state_sig[sigindex], 0 )\ + * (uint64_t)lambda2 >> ( CABAC_SIZE_BITS - LAMBDA_BITS );\ + nodes_cur[0].score -= cost_sig0;\ + }\ + for( int j = 1; j < (ctx_hi?8:4); j++ )\ + SET_LEVEL( nodes_cur[j], nodes_cur[j], 0 );\ + continue;\ + }\ +\ + int sign_coef = orig_coefs[zigzag[i]];\ + int abs_coef = abs( sign_coef );\ + int q = abs( quant_coefs[i] );\ + int cost_siglast[3]; /* { zero, nonzero, nonzero-and-last } */\ + XCHG( trellis_node_t*, nodes_cur, nodes_prev );\ + for( int j = ctx_hi; j < 8; j++ )\ + nodes_cur[j].score = TRELLIS_SCORE_MAX;\ +\ + if( i < num_coefs-1 || ctx_hi )\ + {\ + int sigindex = !dc && num_coefs == 64 ? x264_significant_coeff_flag_offset_8x8[b_interlaced][i] :\ + b_chroma && dc && num_coefs == 8 ? x264_coeff_flag_offset_chroma_422_dc[i] : i;\ + int lastindex = !dc && num_coefs == 64 ? x264_last_coeff_flag_offset_8x8[i] :\ + b_chroma && dc && num_coefs == 8 ? x264_coeff_flag_offset_chroma_422_dc[i] : i;\ + cost_siglast[0] = x264_cabac_size_decision_noup2( &cabac_state_sig[sigindex], 0 );\ + int cost_sig1 = x264_cabac_size_decision_noup2( &cabac_state_sig[sigindex], 1 );\ + cost_siglast[1] = x264_cabac_size_decision_noup2( &cabac_state_last[lastindex], 0 ) + cost_sig1;\ + if( !ctx_hi )\ + cost_siglast[2] = x264_cabac_size_decision_noup2( &cabac_state_last[lastindex], 1 ) + cost_sig1;\ + }\ + else\ + {\ + cost_siglast[0] = cost_siglast[1] = cost_siglast[2] = 0;\ + }\ +\ + /* there are a few cases where increasing the coeff magnitude helps,\ + * but it's only around .003 dB, and skipping them ~doubles the speed of trellis.\ + * could also try q-2: that sometimes helps, but also sometimes decimates blocks\ + * that are better left coded, especially at QP > 40. */\ + uint64_t ssd0[2], ssd1[2];\ + for( int k = 0; k < 2; k++ )\ + {\ + int abs_level = q-1+k;\ + int unquant_abs_level = (((dc?unquant_mf[0]<<1:unquant_mf[zigzag[i]]) * abs_level + 128) >> 8);\ + int d = abs_coef - unquant_abs_level;\ + /* Psy trellis: bias in favor of higher AC coefficients in the reconstructed frame. */\ + if( h->mb.i_psy_trellis && i && !dc && !b_chroma )\ + {\ + int orig_coef = (num_coefs == 64) ? h->mb.pic.fenc_dct8[idx][zigzag[i]] : h->mb.pic.fenc_dct4[idx][zigzag[i]];\ + int predicted_coef = orig_coef - sign_coef;\ + int psy_value = abs(unquant_abs_level + SIGN(predicted_coef, sign_coef));\ + int psy_weight = coef_weight1[zigzag[i]] * h->mb.i_psy_trellis;\ + ssd1[k] = (uint64_t)d*d * coef_weight2[zigzag[i]] - psy_weight * psy_value;\ + }\ + else\ + /* FIXME: for i16x16 dc is this weight optimal? */\ + ssd1[k] = (uint64_t)d*d * (dc?256:coef_weight2[zigzag[i]]);\ + ssd0[k] = ssd1[k];\ + if( !i && !dc && !ctx_hi )\ + {\ + /* Optimize rounding for DC coefficients in DC-only luma 4x4/8x8 blocks. */\ + d = sign_coef - ((SIGN(unquant_abs_level, sign_coef) + 8)&~15);\ + ssd0[k] = (uint64_t)d*d * coef_weight2[zigzag[i]];\ + }\ + }\ +\ + /* argument passing imposes some significant overhead here. gcc's interprocedural register allocation isn't up to it. */\ + switch( q )\ + {\ + case 1:\ + ssd1[0] += (uint64_t)cost_siglast[0] * lambda2 >> ( CABAC_SIZE_BITS - LAMBDA_BITS );\ + levels_used = trellis_coef0_##ctx_hi( ssd0[0]-ssd1[0], nodes_cur, nodes_prev, level_tree, levels_used );\ + levels_used = trellis_coef1_##ctx_hi( ssd0[1]-ssd1[0], ssd1[1]-ssd1[0], cost_siglast, nodes_cur, nodes_prev, level_tree, levels_used, lambda2, level_state );\ + goto next##ctx_hi;\ + case 2:\ + levels_used = trellis_coef1_##ctx_hi( ssd0[0], ssd1[0], cost_siglast, nodes_cur, nodes_prev, level_tree, levels_used, lambda2, level_state );\ + levels_used = trellis_coefn_##ctx_hi( q, ssd0[1], ssd1[1], cost_siglast, nodes_cur, nodes_prev, level_tree, levels_used, lambda2, level_state, levelgt1_ctx );\ + goto next1;\ + default:\ + levels_used = trellis_coefn_##ctx_hi( q-1, ssd0[0], ssd1[0], cost_siglast, nodes_cur, nodes_prev, level_tree, levels_used, lambda2, level_state, levelgt1_ctx );\ + levels_used = trellis_coefn_##ctx_hi( q, ssd0[1], ssd1[1], cost_siglast, nodes_cur, nodes_prev, level_tree, levels_used, lambda2, level_state, levelgt1_ctx );\ + goto next1;\ + }\ + next##ctx_hi:;\ + }\ + /* output levels from the best path through the trellis */\ + bnode = &nodes_cur[ctx_hi];\ + for( int j = ctx_hi+1; j < (ctx_hi?8:4); j++ )\ + if( nodes_cur[j].score < bnode->score )\ + bnode = &nodes_cur[j]; + + // keep 2 versions of the main quantization loop, depending on which subsets of the node_ctxs are live + // node_ctx 0..3, i.e. having not yet encountered any coefs that might be quantized to >1 + TRELLIS_LOOP(0); + + if( bnode == &nodes_cur[0] ) + { + /* We only need to zero an empty 4x4 block. 8x8 can be + implicitly emptied via zero nnz, as can dc. */ + if( num_coefs == 16 && !dc ) + memset( dct, 0, 16 * sizeof(dctcoef) ); + return 0; + } + + if( 0 ) // accessible only by goto, not fallthrough + { + // node_ctx 1..7 (ctx0 ruled out because we never try both level0 and level2+ on the same coef) + TRELLIS_LOOP(1); + } + + int level = bnode->level_idx; + for( i = b_ac; i <= last_nnz; i++ ) + { + dct[zigzag[i]] = SIGN(level_tree[level].abs_level, dct[zigzag[i]]); + level = level_tree[level].next; + } + + return 1; +} + +/* FIXME: This is a gigantic hack. See below. + * + * CAVLC is much more difficult to trellis than CABAC. + * + * CABAC has only three states to track: significance map, last, and the + * level state machine. + * CAVLC, by comparison, has five: coeff_token (trailing + total), + * total_zeroes, zero_run, and the level state machine. + * + * I know of no paper that has managed to design a close-to-optimal trellis + * that covers all five of these and isn't exponential-time. As a result, this + * "trellis" isn't: it's just a QNS search. Patches welcome for something better. + * It's actually surprisingly fast, albeit not quite optimal. It's pretty close + * though; since CAVLC only has 2^16 possible rounding modes (assuming only two + * roundings as options), a bruteforce search is feasible. Testing shows + * that this QNS is reasonably close to optimal in terms of compression. + * + * TODO: + * Don't bother changing large coefficients when it wouldn't affect bit cost + * (e.g. only affecting bypassed suffix bits). + * Don't re-run all parts of CAVLC bit cost calculation when not necessary. + * e.g. when changing a coefficient from one non-zero value to another in + * such a way that trailing ones and suffix length isn't affected. */ +static ALWAYS_INLINE +int quant_trellis_cavlc( x264_t *h, dctcoef *dct, + const udctcoef *quant_mf, const int *unquant_mf, + const uint8_t *zigzag, int ctx_block_cat, int lambda2, int b_ac, + int b_chroma, int dc, int num_coefs, int idx, int b_8x8 ) +{ + ALIGNED_16( dctcoef quant_coefs[2][16] ); + ALIGNED_16( dctcoef coefs[16] ) = {0}; + const uint32_t *coef_weight1 = b_8x8 ? x264_dct8_weight_tab : x264_dct4_weight_tab; + const uint32_t *coef_weight2 = b_8x8 ? x264_dct8_weight2_tab : x264_dct4_weight2_tab; + int delta_distortion[16]; + int64_t score = 1ULL<<62; + int i, j; + const int f = 1<<15; + int nC = b_chroma && dc ? 3 + (num_coefs>>2) + : ct_index[x264_mb_predict_non_zero_code( h, !b_chroma && dc ? (idx - LUMA_DC)*16 : idx )]; + + /* Code for handling 8x8dct -> 4x4dct CAVLC munging. Input/output use a different + * step/start/end than internal processing. */ + int step = 1; + int start = b_ac; + int end = num_coefs - 1; + if( b_8x8 ) + { + start = idx&3; + end = 60 + start; + step = 4; + } + idx &= 15; + + lambda2 <<= LAMBDA_BITS; + + /* Find last non-zero coefficient. */ + for( i = end; i >= start; i -= step ) + if( (unsigned)(dct[zigzag[i]] * (dc?quant_mf[0]>>1:quant_mf[zigzag[i]]) + f-1) >= 2*f ) + break; + + if( i < start ) + goto zeroblock; + + /* Prepare for QNS search: calculate distortion caused by each DCT coefficient + * rounding to be searched. + * + * We only search two roundings (nearest and nearest-1) like in CABAC trellis, + * so we just store the difference in distortion between them. */ + int last_nnz = b_8x8 ? i >> 2 : i; + int coef_mask = 0; + int round_mask = 0; + for( i = b_ac, j = start; i <= last_nnz; i++, j += step ) + { + int coef = dct[zigzag[j]]; + int abs_coef = abs(coef); + int sign = coef < 0 ? -1 : 1; + int nearest_quant = ( f + abs_coef * (dc?quant_mf[0]>>1:quant_mf[zigzag[j]]) ) >> 16; + quant_coefs[1][i] = quant_coefs[0][i] = sign * nearest_quant; + coefs[i] = quant_coefs[1][i]; + if( nearest_quant ) + { + /* We initialize the trellis with a deadzone halfway between nearest rounding + * and always-round-down. This gives much better results than initializing to either + * extreme. + * FIXME: should we initialize to the deadzones used by deadzone quant? */ + int deadzone_quant = ( f/2 + abs_coef * (dc?quant_mf[0]>>1:quant_mf[zigzag[j]]) ) >> 16; + int unquant1 = (((dc?unquant_mf[0]<<1:unquant_mf[zigzag[j]]) * (nearest_quant-0) + 128) >> 8); + int unquant0 = (((dc?unquant_mf[0]<<1:unquant_mf[zigzag[j]]) * (nearest_quant-1) + 128) >> 8); + int d1 = abs_coef - unquant1; + int d0 = abs_coef - unquant0; + delta_distortion[i] = (d0*d0 - d1*d1) * (dc?256:coef_weight2[zigzag[j]]); + + /* Psy trellis: bias in favor of higher AC coefficients in the reconstructed frame. */ + if( h->mb.i_psy_trellis && j && !dc && !b_chroma ) + { + int orig_coef = b_8x8 ? h->mb.pic.fenc_dct8[idx>>2][zigzag[j]] : h->mb.pic.fenc_dct4[idx][zigzag[j]]; + int predicted_coef = orig_coef - coef; + int psy_weight = coef_weight1[zigzag[j]]; + int psy_value0 = h->mb.i_psy_trellis * abs(predicted_coef + unquant0 * sign); + int psy_value1 = h->mb.i_psy_trellis * abs(predicted_coef + unquant1 * sign); + delta_distortion[i] += (psy_value0 - psy_value1) * psy_weight; + } + + quant_coefs[0][i] = sign * (nearest_quant-1); + if( deadzone_quant != nearest_quant ) + coefs[i] = quant_coefs[0][i]; + else + round_mask |= 1 << i; + } + else + delta_distortion[i] = 0; + coef_mask |= (!!coefs[i]) << i; + } + + /* Calculate the cost of the starting state. */ + h->out.bs.i_bits_encoded = 0; + if( !coef_mask ) + bs_write_vlc( &h->out.bs, x264_coeff0_token[nC] ); + else + x264_cavlc_block_residual_internal( h, ctx_block_cat, coefs + b_ac, nC ); + score = (int64_t)h->out.bs.i_bits_encoded * lambda2; + + /* QNS loop: pick the change that improves RD the most, apply it, repeat. + * coef_mask and round_mask are used to simplify tracking of nonzeroness + * and rounding modes chosen. */ + while( 1 ) + { + int64_t iter_score = score; + int iter_distortion_delta = 0; + int iter_coef = -1; + int iter_mask = coef_mask; + int iter_round = round_mask; + for( i = b_ac; i <= last_nnz; i++ ) + { + if( !delta_distortion[i] ) + continue; + + /* Set up all the variables for this iteration. */ + int cur_round = round_mask ^ (1 << i); + int round_change = (cur_round >> i)&1; + int old_coef = coefs[i]; + int new_coef = quant_coefs[round_change][i]; + int cur_mask = (coef_mask&~(1 << i))|(!!new_coef << i); + int cur_distortion_delta = delta_distortion[i] * (round_change ? -1 : 1); + int64_t cur_score = cur_distortion_delta; + coefs[i] = new_coef; + + /* Count up bits. */ + h->out.bs.i_bits_encoded = 0; + if( !cur_mask ) + bs_write_vlc( &h->out.bs, x264_coeff0_token[nC] ); + else + x264_cavlc_block_residual_internal( h, ctx_block_cat, coefs + b_ac, nC ); + cur_score += (int64_t)h->out.bs.i_bits_encoded * lambda2; + + coefs[i] = old_coef; + if( cur_score < iter_score ) + { + iter_score = cur_score; + iter_coef = i; + iter_mask = cur_mask; + iter_round = cur_round; + iter_distortion_delta = cur_distortion_delta; + } + } + if( iter_coef >= 0 ) + { + score = iter_score - iter_distortion_delta; + coef_mask = iter_mask; + round_mask = iter_round; + coefs[iter_coef] = quant_coefs[((round_mask >> iter_coef)&1)][iter_coef]; + /* Don't try adjusting coefficients we've already adjusted. + * Testing suggests this doesn't hurt results -- and sometimes actually helps. */ + delta_distortion[iter_coef] = 0; + } + else + break; + } + + if( coef_mask ) + { + for( i = b_ac, j = start; i < num_coefs; i++, j += step ) + dct[zigzag[j]] = coefs[i]; + return 1; + } + +zeroblock: + if( !dc ) + { + if( b_8x8 ) + for( i = start; i <= end; i+=step ) + dct[zigzag[i]] = 0; + else + memset( dct, 0, 16*sizeof(dctcoef) ); + } + return 0; +} + +int x264_quant_luma_dc_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, int i_qp, int ctx_block_cat, int b_intra, int idx ) +{ + if( h->param.b_cabac ) + return quant_trellis_cabac( h, dct, + h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias0[i_quant_cat][i_qp], + h->unquant4_mf[i_quant_cat][i_qp], x264_zigzag_scan4[MB_INTERLACED], + ctx_block_cat, h->mb.i_trellis_lambda2[0][b_intra], 0, 0, 1, 16, idx ); + + return quant_trellis_cavlc( h, dct, + h->quant4_mf[i_quant_cat][i_qp], h->unquant4_mf[i_quant_cat][i_qp], x264_zigzag_scan4[MB_INTERLACED], + DCT_LUMA_DC, h->mb.i_trellis_lambda2[0][b_intra], 0, 0, 1, 16, idx, 0 ); +} + +static const uint8_t x264_zigzag_scan2x2[4] = { 0, 1, 2, 3 }; +static const uint8_t x264_zigzag_scan2x4[8] = { 0, 2, 1, 4, 6, 3, 5, 7 }; + +int x264_quant_chroma_dc_trellis( x264_t *h, dctcoef *dct, int i_qp, int b_intra, int idx ) +{ + const uint8_t *zigzag; + int num_coefs; + int quant_cat = CQM_4IC+1 - b_intra; + + if( CHROMA_FORMAT == CHROMA_422 ) + { + zigzag = x264_zigzag_scan2x4; + num_coefs = 8; + } + else + { + zigzag = x264_zigzag_scan2x2; + num_coefs = 4; + } + + if( h->param.b_cabac ) + return quant_trellis_cabac( h, dct, + h->quant4_mf[quant_cat][i_qp], h->quant4_bias0[quant_cat][i_qp], + h->unquant4_mf[quant_cat][i_qp], zigzag, + DCT_CHROMA_DC, h->mb.i_trellis_lambda2[1][b_intra], 0, 1, 1, num_coefs, idx ); + + return quant_trellis_cavlc( h, dct, + h->quant4_mf[quant_cat][i_qp], h->unquant4_mf[quant_cat][i_qp], zigzag, + DCT_CHROMA_DC, h->mb.i_trellis_lambda2[1][b_intra], 0, 1, 1, num_coefs, idx, 0 ); +} + +int x264_quant_4x4_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, + int i_qp, int ctx_block_cat, int b_intra, int b_chroma, int idx ) +{ + static const uint8_t ctx_ac[14] = {0,1,0,0,1,0,0,1,0,0,0,1,0,0}; + int b_ac = ctx_ac[ctx_block_cat]; + if( h->param.b_cabac ) + return quant_trellis_cabac( h, dct, + h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias0[i_quant_cat][i_qp], + h->unquant4_mf[i_quant_cat][i_qp], x264_zigzag_scan4[MB_INTERLACED], + ctx_block_cat, h->mb.i_trellis_lambda2[b_chroma][b_intra], b_ac, b_chroma, 0, 16, idx ); + + return quant_trellis_cavlc( h, dct, + h->quant4_mf[i_quant_cat][i_qp], h->unquant4_mf[i_quant_cat][i_qp], + x264_zigzag_scan4[MB_INTERLACED], + ctx_block_cat, h->mb.i_trellis_lambda2[b_chroma][b_intra], b_ac, b_chroma, 0, 16, idx, 0 ); +} + +int x264_quant_8x8_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, + int i_qp, int ctx_block_cat, int b_intra, int b_chroma, int idx ) +{ + if( h->param.b_cabac ) + { + return quant_trellis_cabac( h, dct, + h->quant8_mf[i_quant_cat][i_qp], h->quant8_bias0[i_quant_cat][i_qp], + h->unquant8_mf[i_quant_cat][i_qp], x264_zigzag_scan8[MB_INTERLACED], + ctx_block_cat, h->mb.i_trellis_lambda2[b_chroma][b_intra], 0, b_chroma, 0, 64, idx ); + } + + /* 8x8 CAVLC is split into 4 4x4 blocks */ + int nzaccum = 0; + for( int i = 0; i < 4; i++ ) + { + int nz = quant_trellis_cavlc( h, dct, + h->quant8_mf[i_quant_cat][i_qp], h->unquant8_mf[i_quant_cat][i_qp], + x264_zigzag_scan8[MB_INTERLACED], + DCT_LUMA_4x4, h->mb.i_trellis_lambda2[b_chroma][b_intra], 0, b_chroma, 0, 16, idx*4+i, 1 ); + /* Set up nonzero count for future calls */ + h->mb.cache.non_zero_count[x264_scan8[idx*4+i]] = nz; + nzaccum |= nz; + } + STORE_8x8_NNZ( 0, idx, 0 ); + return nzaccum; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/set.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/set.c new file mode 100644 index 00000000..2ab4e4e8 --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/set.c @@ -0,0 +1,853 @@ +/***************************************************************************** + * set: header writing + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "set.h" + +#define bs_write_ue bs_write_ue_big + +// Indexed by pic_struct values +static const uint8_t num_clock_ts[10] = { 0, 1, 1, 1, 2, 2, 3, 3, 2, 3 }; +const static uint8_t avcintra_uuid[] = {0xF7, 0x49, 0x3E, 0xB3, 0xD4, 0x00, 0x47, 0x96, 0x86, 0x86, 0xC9, 0x70, 0x7B, 0x64, 0x37, 0x2A}; + +static void transpose( uint8_t *buf, int w ) +{ + for( int i = 0; i < w; i++ ) + for( int j = 0; j < i; j++ ) + XCHG( uint8_t, buf[w*i+j], buf[w*j+i] ); +} + +static void scaling_list_write( bs_t *s, x264_pps_t *pps, int idx ) +{ + const int len = idx<4 ? 16 : 64; + const uint8_t *zigzag = idx<4 ? x264_zigzag_scan4[0] : x264_zigzag_scan8[0]; + const uint8_t *list = pps->scaling_list[idx]; + const uint8_t *def_list = (idx==CQM_4IC) ? pps->scaling_list[CQM_4IY] + : (idx==CQM_4PC) ? pps->scaling_list[CQM_4PY] + : (idx==CQM_8IC+4) ? pps->scaling_list[CQM_8IY+4] + : (idx==CQM_8PC+4) ? pps->scaling_list[CQM_8PY+4] + : x264_cqm_jvt[idx]; + if( !memcmp( list, def_list, len ) ) + bs_write1( s, 0 ); // scaling_list_present_flag + else if( !memcmp( list, x264_cqm_jvt[idx], len ) ) + { + bs_write1( s, 1 ); // scaling_list_present_flag + bs_write_se( s, -8 ); // use jvt list + } + else + { + int run; + bs_write1( s, 1 ); // scaling_list_present_flag + + // try run-length compression of trailing values + for( run = len; run > 1; run-- ) + if( list[zigzag[run-1]] != list[zigzag[run-2]] ) + break; + if( run < len && len - run < bs_size_se( (int8_t)-list[zigzag[run]] ) ) + run = len; + + for( int j = 0; j < run; j++ ) + bs_write_se( s, (int8_t)(list[zigzag[j]] - (j>0 ? list[zigzag[j-1]] : 8)) ); // delta + + if( run < len ) + bs_write_se( s, (int8_t)-list[zigzag[run]] ); + } +} + +void x264_sei_write( bs_t *s, uint8_t *payload, int payload_size, int payload_type ) +{ + int i; + + bs_realign( s ); + + for( i = 0; i <= payload_type-255; i += 255 ) + bs_write( s, 8, 255 ); + bs_write( s, 8, payload_type-i ); + + for( i = 0; i <= payload_size-255; i += 255 ) + bs_write( s, 8, 255 ); + bs_write( s, 8, payload_size-i ); + + for( i = 0; i < payload_size; i++ ) + bs_write( s, 8, payload[i] ); + + bs_rbsp_trailing( s ); + bs_flush( s ); +} + +void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) +{ + int csp = param->i_csp & X264_CSP_MASK; + + sps->i_id = i_id; + sps->i_mb_width = ( param->i_width + 15 ) / 16; + sps->i_mb_height= ( param->i_height + 15 ) / 16; + sps->i_chroma_format_idc = csp >= X264_CSP_I444 ? CHROMA_444 : + csp >= X264_CSP_I422 ? CHROMA_422 : CHROMA_420; + + sps->b_qpprime_y_zero_transform_bypass = param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant == 0; + if( sps->b_qpprime_y_zero_transform_bypass || sps->i_chroma_format_idc == CHROMA_444 ) + sps->i_profile_idc = PROFILE_HIGH444_PREDICTIVE; + else if( sps->i_chroma_format_idc == CHROMA_422 ) + sps->i_profile_idc = PROFILE_HIGH422; + else if( BIT_DEPTH > 8 ) + sps->i_profile_idc = PROFILE_HIGH10; + else if( param->analyse.b_transform_8x8 || param->i_cqm_preset != X264_CQM_FLAT ) + sps->i_profile_idc = PROFILE_HIGH; + else if( param->b_cabac || param->i_bframe > 0 || param->b_interlaced || param->b_fake_interlaced || param->analyse.i_weighted_pred > 0 ) + sps->i_profile_idc = PROFILE_MAIN; + else + sps->i_profile_idc = PROFILE_BASELINE; + + sps->b_constraint_set0 = sps->i_profile_idc == PROFILE_BASELINE; + /* x264 doesn't support the features that are in Baseline and not in Main, + * namely arbitrary_slice_order and slice_groups. */ + sps->b_constraint_set1 = sps->i_profile_idc <= PROFILE_MAIN; + /* Never set constraint_set2, it is not necessary and not used in real world. */ + sps->b_constraint_set2 = 0; + sps->b_constraint_set3 = 0; + + sps->i_level_idc = param->i_level_idc; + if( param->i_level_idc == 9 && ( sps->i_profile_idc == PROFILE_BASELINE || sps->i_profile_idc == PROFILE_MAIN ) ) + { + sps->b_constraint_set3 = 1; /* level 1b with Baseline or Main profile is signalled via constraint_set3 */ + sps->i_level_idc = 11; + } + /* Intra profiles */ + if( param->i_keyint_max == 1 && sps->i_profile_idc >= PROFILE_HIGH ) + sps->b_constraint_set3 = 1; + + sps->vui.i_num_reorder_frames = param->i_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0; + /* extra slot with pyramid so that we don't have to override the + * order of forgetting old pictures */ + sps->vui.i_max_dec_frame_buffering = + sps->i_num_ref_frames = X264_MIN(X264_REF_MAX, X264_MAX4(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames, + param->i_bframe_pyramid ? 4 : 1, param->i_dpb_size)); + sps->i_num_ref_frames -= param->i_bframe_pyramid == X264_B_PYRAMID_STRICT; + if( param->i_keyint_max == 1 ) + { + sps->i_num_ref_frames = 0; + sps->vui.i_max_dec_frame_buffering = 0; + } + + /* number of refs + current frame */ + int max_frame_num = sps->vui.i_max_dec_frame_buffering * (!!param->i_bframe_pyramid+1) + 1; + /* Intra refresh cannot write a recovery time greater than max frame num-1 */ + if( param->b_intra_refresh ) + { + int time_to_recovery = X264_MIN( sps->i_mb_width - 1, param->i_keyint_max ) + param->i_bframe - 1; + max_frame_num = X264_MAX( max_frame_num, time_to_recovery+1 ); + } + + sps->i_log2_max_frame_num = 4; + while( (1 << sps->i_log2_max_frame_num) <= max_frame_num ) + sps->i_log2_max_frame_num++; + + sps->i_poc_type = param->i_bframe || param->b_interlaced || param->i_avcintra_class ? 0 : 2; + if( sps->i_poc_type == 0 ) + { + int max_delta_poc = (param->i_bframe + 2) * (!!param->i_bframe_pyramid + 1) * 2; + sps->i_log2_max_poc_lsb = 4; + while( (1 << sps->i_log2_max_poc_lsb) <= max_delta_poc * 2 ) + sps->i_log2_max_poc_lsb++; + } + + sps->b_vui = 1; + + sps->b_gaps_in_frame_num_value_allowed = 0; + sps->b_frame_mbs_only = !(param->b_interlaced || param->b_fake_interlaced); + if( !sps->b_frame_mbs_only ) + sps->i_mb_height = ( sps->i_mb_height + 1 ) & ~1; + sps->b_mb_adaptive_frame_field = param->b_interlaced; + sps->b_direct8x8_inference = 1; + + x264_sps_init_reconfigurable( sps, param ); + + sps->vui.b_overscan_info_present = param->vui.i_overscan > 0 && param->vui.i_overscan <= 2; + if( sps->vui.b_overscan_info_present ) + sps->vui.b_overscan_info = ( param->vui.i_overscan == 2 ? 1 : 0 ); + + sps->vui.b_signal_type_present = 0; + sps->vui.i_vidformat = ( param->vui.i_vidformat >= 0 && param->vui.i_vidformat <= 5 ? param->vui.i_vidformat : 5 ); + sps->vui.b_fullrange = ( param->vui.b_fullrange >= 0 && param->vui.b_fullrange <= 1 ? param->vui.b_fullrange : + ( csp >= X264_CSP_BGR ? 1 : 0 ) ); + sps->vui.b_color_description_present = 0; + + sps->vui.i_colorprim = ( param->vui.i_colorprim >= 0 && param->vui.i_colorprim <= 12 ? param->vui.i_colorprim : 2 ); + sps->vui.i_transfer = ( param->vui.i_transfer >= 0 && param->vui.i_transfer <= 17 ? param->vui.i_transfer : 2 ); + sps->vui.i_colmatrix = ( param->vui.i_colmatrix >= 0 && param->vui.i_colmatrix <= 11 ? param->vui.i_colmatrix : + ( csp >= X264_CSP_BGR ? 0 : 2 ) ); + if( sps->vui.i_colorprim != 2 || + sps->vui.i_transfer != 2 || + sps->vui.i_colmatrix != 2 ) + { + sps->vui.b_color_description_present = 1; + } + + if( sps->vui.i_vidformat != 5 || + sps->vui.b_fullrange || + sps->vui.b_color_description_present ) + { + sps->vui.b_signal_type_present = 1; + } + + /* FIXME: not sufficient for interlaced video */ + sps->vui.b_chroma_loc_info_present = param->vui.i_chroma_loc > 0 && param->vui.i_chroma_loc <= 5 && + sps->i_chroma_format_idc == CHROMA_420; + if( sps->vui.b_chroma_loc_info_present ) + { + sps->vui.i_chroma_loc_top = param->vui.i_chroma_loc; + sps->vui.i_chroma_loc_bottom = param->vui.i_chroma_loc; + } + + sps->vui.b_timing_info_present = param->i_timebase_num > 0 && param->i_timebase_den > 0; + + if( sps->vui.b_timing_info_present ) + { + sps->vui.i_num_units_in_tick = param->i_timebase_num; + sps->vui.i_time_scale = param->i_timebase_den * 2; + sps->vui.b_fixed_frame_rate = !param->b_vfr_input; + } + + sps->vui.b_vcl_hrd_parameters_present = 0; // we don't support VCL HRD + sps->vui.b_nal_hrd_parameters_present = !!param->i_nal_hrd; + sps->vui.b_pic_struct_present = param->b_pic_struct; + + // NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable + + sps->vui.b_bitstream_restriction = !(sps->b_constraint_set3 && sps->i_profile_idc >= PROFILE_HIGH); + if( sps->vui.b_bitstream_restriction ) + { + sps->vui.b_motion_vectors_over_pic_boundaries = 1; + sps->vui.i_max_bytes_per_pic_denom = 0; + sps->vui.i_max_bits_per_mb_denom = 0; + sps->vui.i_log2_max_mv_length_horizontal = + sps->vui.i_log2_max_mv_length_vertical = (int)log2f( X264_MAX( 1, param->analyse.i_mv_range*4-1 ) ) + 1; + } +} + +void x264_sps_init_reconfigurable( x264_sps_t *sps, x264_param_t *param ) +{ + sps->crop.i_left = param->crop_rect.i_left; + sps->crop.i_top = param->crop_rect.i_top; + sps->crop.i_right = param->crop_rect.i_right + sps->i_mb_width*16 - param->i_width; + sps->crop.i_bottom = (param->crop_rect.i_bottom + sps->i_mb_height*16 - param->i_height) >> !sps->b_frame_mbs_only; + sps->b_crop = sps->crop.i_left || sps->crop.i_top || + sps->crop.i_right || sps->crop.i_bottom; + + sps->vui.b_aspect_ratio_info_present = 0; + if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 ) + { + sps->vui.b_aspect_ratio_info_present = 1; + sps->vui.i_sar_width = param->vui.i_sar_width; + sps->vui.i_sar_height= param->vui.i_sar_height; + } +} + +void x264_sps_write( bs_t *s, x264_sps_t *sps ) +{ + bs_realign( s ); + bs_write( s, 8, sps->i_profile_idc ); + bs_write1( s, sps->b_constraint_set0 ); + bs_write1( s, sps->b_constraint_set1 ); + bs_write1( s, sps->b_constraint_set2 ); + bs_write1( s, sps->b_constraint_set3 ); + + bs_write( s, 4, 0 ); /* reserved */ + + bs_write( s, 8, sps->i_level_idc ); + + bs_write_ue( s, sps->i_id ); + + if( sps->i_profile_idc >= PROFILE_HIGH ) + { + bs_write_ue( s, sps->i_chroma_format_idc ); + if( sps->i_chroma_format_idc == CHROMA_444 ) + bs_write1( s, 0 ); // separate_colour_plane_flag + bs_write_ue( s, BIT_DEPTH-8 ); // bit_depth_luma_minus8 + bs_write_ue( s, BIT_DEPTH-8 ); // bit_depth_chroma_minus8 + bs_write1( s, sps->b_qpprime_y_zero_transform_bypass ); + bs_write1( s, 0 ); // seq_scaling_matrix_present_flag + } + + bs_write_ue( s, sps->i_log2_max_frame_num - 4 ); + bs_write_ue( s, sps->i_poc_type ); + if( sps->i_poc_type == 0 ) + bs_write_ue( s, sps->i_log2_max_poc_lsb - 4 ); + bs_write_ue( s, sps->i_num_ref_frames ); + bs_write1( s, sps->b_gaps_in_frame_num_value_allowed ); + bs_write_ue( s, sps->i_mb_width - 1 ); + bs_write_ue( s, (sps->i_mb_height >> !sps->b_frame_mbs_only) - 1); + bs_write1( s, sps->b_frame_mbs_only ); + if( !sps->b_frame_mbs_only ) + bs_write1( s, sps->b_mb_adaptive_frame_field ); + bs_write1( s, sps->b_direct8x8_inference ); + + bs_write1( s, sps->b_crop ); + if( sps->b_crop ) + { + int h_shift = sps->i_chroma_format_idc == CHROMA_420 || sps->i_chroma_format_idc == CHROMA_422; + int v_shift = sps->i_chroma_format_idc == CHROMA_420; + bs_write_ue( s, sps->crop.i_left >> h_shift ); + bs_write_ue( s, sps->crop.i_right >> h_shift ); + bs_write_ue( s, sps->crop.i_top >> v_shift ); + bs_write_ue( s, sps->crop.i_bottom >> v_shift ); + } + + bs_write1( s, sps->b_vui ); + if( sps->b_vui ) + { + bs_write1( s, sps->vui.b_aspect_ratio_info_present ); + if( sps->vui.b_aspect_ratio_info_present ) + { + int i; + static const struct { uint8_t w, h, sar; } sar[] = + { + // aspect_ratio_idc = 0 -> unspecified + { 1, 1, 1 }, { 12, 11, 2 }, { 10, 11, 3 }, { 16, 11, 4 }, + { 40, 33, 5 }, { 24, 11, 6 }, { 20, 11, 7 }, { 32, 11, 8 }, + { 80, 33, 9 }, { 18, 11, 10}, { 15, 11, 11}, { 64, 33, 12}, + {160, 99, 13}, { 4, 3, 14}, { 3, 2, 15}, { 2, 1, 16}, + // aspect_ratio_idc = [17..254] -> reserved + { 0, 0, 255 } + }; + for( i = 0; sar[i].sar != 255; i++ ) + { + if( sar[i].w == sps->vui.i_sar_width && + sar[i].h == sps->vui.i_sar_height ) + break; + } + bs_write( s, 8, sar[i].sar ); + if( sar[i].sar == 255 ) /* aspect_ratio_idc (extended) */ + { + bs_write( s, 16, sps->vui.i_sar_width ); + bs_write( s, 16, sps->vui.i_sar_height ); + } + } + + bs_write1( s, sps->vui.b_overscan_info_present ); + if( sps->vui.b_overscan_info_present ) + bs_write1( s, sps->vui.b_overscan_info ); + + bs_write1( s, sps->vui.b_signal_type_present ); + if( sps->vui.b_signal_type_present ) + { + bs_write( s, 3, sps->vui.i_vidformat ); + bs_write1( s, sps->vui.b_fullrange ); + bs_write1( s, sps->vui.b_color_description_present ); + if( sps->vui.b_color_description_present ) + { + bs_write( s, 8, sps->vui.i_colorprim ); + bs_write( s, 8, sps->vui.i_transfer ); + bs_write( s, 8, sps->vui.i_colmatrix ); + } + } + + bs_write1( s, sps->vui.b_chroma_loc_info_present ); + if( sps->vui.b_chroma_loc_info_present ) + { + bs_write_ue( s, sps->vui.i_chroma_loc_top ); + bs_write_ue( s, sps->vui.i_chroma_loc_bottom ); + } + + bs_write1( s, sps->vui.b_timing_info_present ); + if( sps->vui.b_timing_info_present ) + { + bs_write32( s, sps->vui.i_num_units_in_tick ); + bs_write32( s, sps->vui.i_time_scale ); + bs_write1( s, sps->vui.b_fixed_frame_rate ); + } + + bs_write1( s, sps->vui.b_nal_hrd_parameters_present ); + if( sps->vui.b_nal_hrd_parameters_present ) + { + bs_write_ue( s, sps->vui.hrd.i_cpb_cnt - 1 ); + bs_write( s, 4, sps->vui.hrd.i_bit_rate_scale ); + bs_write( s, 4, sps->vui.hrd.i_cpb_size_scale ); + + bs_write_ue( s, sps->vui.hrd.i_bit_rate_value - 1 ); + bs_write_ue( s, sps->vui.hrd.i_cpb_size_value - 1 ); + + bs_write1( s, sps->vui.hrd.b_cbr_hrd ); + + bs_write( s, 5, sps->vui.hrd.i_initial_cpb_removal_delay_length - 1 ); + bs_write( s, 5, sps->vui.hrd.i_cpb_removal_delay_length - 1 ); + bs_write( s, 5, sps->vui.hrd.i_dpb_output_delay_length - 1 ); + bs_write( s, 5, sps->vui.hrd.i_time_offset_length ); + } + + bs_write1( s, sps->vui.b_vcl_hrd_parameters_present ); + + if( sps->vui.b_nal_hrd_parameters_present || sps->vui.b_vcl_hrd_parameters_present ) + bs_write1( s, 0 ); /* low_delay_hrd_flag */ + + bs_write1( s, sps->vui.b_pic_struct_present ); + bs_write1( s, sps->vui.b_bitstream_restriction ); + if( sps->vui.b_bitstream_restriction ) + { + bs_write1( s, sps->vui.b_motion_vectors_over_pic_boundaries ); + bs_write_ue( s, sps->vui.i_max_bytes_per_pic_denom ); + bs_write_ue( s, sps->vui.i_max_bits_per_mb_denom ); + bs_write_ue( s, sps->vui.i_log2_max_mv_length_horizontal ); + bs_write_ue( s, sps->vui.i_log2_max_mv_length_vertical ); + bs_write_ue( s, sps->vui.i_num_reorder_frames ); + bs_write_ue( s, sps->vui.i_max_dec_frame_buffering ); + } + } + + bs_rbsp_trailing( s ); + bs_flush( s ); +} + +void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *sps ) +{ + pps->i_id = i_id; + pps->i_sps_id = sps->i_id; + pps->b_cabac = param->b_cabac; + + pps->b_pic_order = !param->i_avcintra_class && param->b_interlaced; + pps->i_num_slice_groups = 1; + + pps->i_num_ref_idx_l0_default_active = param->i_frame_reference; + pps->i_num_ref_idx_l1_default_active = 1; + + pps->b_weighted_pred = param->analyse.i_weighted_pred > 0; + pps->b_weighted_bipred = param->analyse.b_weighted_bipred ? 2 : 0; + + pps->i_pic_init_qp = param->rc.i_rc_method == X264_RC_ABR || param->b_stitchable ? 26 + QP_BD_OFFSET : SPEC_QP( param->rc.i_qp_constant ); + pps->i_pic_init_qs = 26 + QP_BD_OFFSET; + + pps->i_chroma_qp_index_offset = param->analyse.i_chroma_qp_offset; + pps->b_deblocking_filter_control = 1; + pps->b_constrained_intra_pred = param->b_constrained_intra; + pps->b_redundant_pic_cnt = 0; + + pps->b_transform_8x8_mode = param->analyse.b_transform_8x8 ? 1 : 0; + + pps->i_cqm_preset = param->i_cqm_preset; + + switch( pps->i_cqm_preset ) + { + case X264_CQM_FLAT: + for( int i = 0; i < 8; i++ ) + pps->scaling_list[i] = x264_cqm_flat16; + break; + case X264_CQM_JVT: + for( int i = 0; i < 8; i++ ) + pps->scaling_list[i] = x264_cqm_jvt[i]; + break; + case X264_CQM_CUSTOM: + /* match the transposed DCT & zigzag */ + transpose( param->cqm_4iy, 4 ); + transpose( param->cqm_4py, 4 ); + transpose( param->cqm_4ic, 4 ); + transpose( param->cqm_4pc, 4 ); + transpose( param->cqm_8iy, 8 ); + transpose( param->cqm_8py, 8 ); + transpose( param->cqm_8ic, 8 ); + transpose( param->cqm_8pc, 8 ); + pps->scaling_list[CQM_4IY] = param->cqm_4iy; + pps->scaling_list[CQM_4PY] = param->cqm_4py; + pps->scaling_list[CQM_4IC] = param->cqm_4ic; + pps->scaling_list[CQM_4PC] = param->cqm_4pc; + pps->scaling_list[CQM_8IY+4] = param->cqm_8iy; + pps->scaling_list[CQM_8PY+4] = param->cqm_8py; + pps->scaling_list[CQM_8IC+4] = param->cqm_8ic; + pps->scaling_list[CQM_8PC+4] = param->cqm_8pc; + for( int i = 0; i < 8; i++ ) + for( int j = 0; j < (i < 4 ? 16 : 64); j++ ) + if( pps->scaling_list[i][j] == 0 ) + pps->scaling_list[i] = x264_cqm_jvt[i]; + break; + } +} + +void x264_pps_write( bs_t *s, x264_sps_t *sps, x264_pps_t *pps ) +{ + bs_realign( s ); + bs_write_ue( s, pps->i_id ); + bs_write_ue( s, pps->i_sps_id ); + + bs_write1( s, pps->b_cabac ); + bs_write1( s, pps->b_pic_order ); + bs_write_ue( s, pps->i_num_slice_groups - 1 ); + + bs_write_ue( s, pps->i_num_ref_idx_l0_default_active - 1 ); + bs_write_ue( s, pps->i_num_ref_idx_l1_default_active - 1 ); + bs_write1( s, pps->b_weighted_pred ); + bs_write( s, 2, pps->b_weighted_bipred ); + + bs_write_se( s, pps->i_pic_init_qp - 26 - QP_BD_OFFSET ); + bs_write_se( s, pps->i_pic_init_qs - 26 - QP_BD_OFFSET ); + bs_write_se( s, pps->i_chroma_qp_index_offset ); + + bs_write1( s, pps->b_deblocking_filter_control ); + bs_write1( s, pps->b_constrained_intra_pred ); + bs_write1( s, pps->b_redundant_pic_cnt ); + + if( pps->b_transform_8x8_mode || pps->i_cqm_preset != X264_CQM_FLAT ) + { + bs_write1( s, pps->b_transform_8x8_mode ); + bs_write1( s, (pps->i_cqm_preset != X264_CQM_FLAT) ); + if( pps->i_cqm_preset != X264_CQM_FLAT ) + { + scaling_list_write( s, pps, CQM_4IY ); + scaling_list_write( s, pps, CQM_4IC ); + bs_write1( s, 0 ); // Cr = Cb + scaling_list_write( s, pps, CQM_4PY ); + scaling_list_write( s, pps, CQM_4PC ); + bs_write1( s, 0 ); // Cr = Cb + if( pps->b_transform_8x8_mode ) + { + scaling_list_write( s, pps, CQM_8IY+4 ); + scaling_list_write( s, pps, CQM_8PY+4 ); + if( sps->i_chroma_format_idc == CHROMA_444 ) + { + scaling_list_write( s, pps, CQM_8IC+4 ); + scaling_list_write( s, pps, CQM_8PC+4 ); + bs_write1( s, 0 ); // Cr = Cb + bs_write1( s, 0 ); // Cr = Cb + } + } + } + bs_write_se( s, pps->i_chroma_qp_index_offset ); + } + + bs_rbsp_trailing( s ); + bs_flush( s ); +} + +void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt ) +{ + bs_t q; + ALIGNED_4( uint8_t tmp_buf[100] ); + M32( tmp_buf ) = 0; // shut up gcc + bs_init( &q, tmp_buf, 100 ); + + bs_realign( &q ); + + bs_write_ue( &q, recovery_frame_cnt ); // recovery_frame_cnt + bs_write1( &q, 1 ); //exact_match_flag 1 + bs_write1( &q, 0 ); //broken_link_flag 0 + bs_write( &q, 2, 0 ); //changing_slice_group 0 + + bs_align_10( &q ); + bs_flush( &q ); + + x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_RECOVERY_POINT ); +} + +int x264_sei_version_write( x264_t *h, bs_t *s ) +{ + // random ID number generated according to ISO-11578 + static const uint8_t uuid[16] = + { + 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, + 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef + }; + char *opts = x264_param2string( &h->param, 0 ); + char *payload; + int length; + + if( !opts ) + return -1; + CHECKED_MALLOC( payload, 200 + strlen( opts ) ); + + memcpy( payload, uuid, 16 ); + sprintf( payload+16, "x264 - core %d%s - H.264/MPEG-4 AVC codec - " + "Copy%s 2003-2017 - http://www.videolan.org/x264.html - options: %s", + X264_BUILD, X264_VERSION, HAVE_GPL?"left":"right", opts ); + length = strlen(payload)+1; + + x264_sei_write( s, (uint8_t *)payload, length, SEI_USER_DATA_UNREGISTERED ); + + x264_free( opts ); + x264_free( payload ); + return 0; +fail: + x264_free( opts ); + return -1; +} + +void x264_sei_buffering_period_write( x264_t *h, bs_t *s ) +{ + x264_sps_t *sps = h->sps; + bs_t q; + ALIGNED_4( uint8_t tmp_buf[100] ); + M32( tmp_buf ) = 0; // shut up gcc + bs_init( &q, tmp_buf, 100 ); + + bs_realign( &q ); + bs_write_ue( &q, sps->i_id ); + + if( sps->vui.b_nal_hrd_parameters_present ) + { + bs_write( &q, sps->vui.hrd.i_initial_cpb_removal_delay_length, h->initial_cpb_removal_delay ); + bs_write( &q, sps->vui.hrd.i_initial_cpb_removal_delay_length, h->initial_cpb_removal_delay_offset ); + } + + bs_align_10( &q ); + bs_flush( &q ); + + x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_BUFFERING_PERIOD ); +} + +void x264_sei_pic_timing_write( x264_t *h, bs_t *s ) +{ + x264_sps_t *sps = h->sps; + bs_t q; + ALIGNED_4( uint8_t tmp_buf[100] ); + M32( tmp_buf ) = 0; // shut up gcc + bs_init( &q, tmp_buf, 100 ); + + bs_realign( &q ); + + if( sps->vui.b_nal_hrd_parameters_present || sps->vui.b_vcl_hrd_parameters_present ) + { + bs_write( &q, sps->vui.hrd.i_cpb_removal_delay_length, h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset ); + bs_write( &q, sps->vui.hrd.i_dpb_output_delay_length, h->fenc->i_dpb_output_delay ); + } + + if( sps->vui.b_pic_struct_present ) + { + bs_write( &q, 4, h->fenc->i_pic_struct-1 ); // We use index 0 for "Auto" + + // These clock timestamps are not standardised so we don't set them + // They could be time of origin, capture or alternative ideal display + for( int i = 0; i < num_clock_ts[h->fenc->i_pic_struct]; i++ ) + bs_write1( &q, 0 ); // clock_timestamp_flag + } + + bs_align_10( &q ); + bs_flush( &q ); + + x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_PIC_TIMING ); +} + +void x264_sei_frame_packing_write( x264_t *h, bs_t *s ) +{ + int quincunx_sampling_flag = h->param.i_frame_packing == 0; + bs_t q; + ALIGNED_4( uint8_t tmp_buf[100] ); + M32( tmp_buf ) = 0; // shut up gcc + bs_init( &q, tmp_buf, 100 ); + + bs_realign( &q ); + + bs_write_ue( &q, 0 ); // frame_packing_arrangement_id + bs_write1( &q, 0 ); // frame_packing_arrangement_cancel_flag + bs_write ( &q, 7, h->param.i_frame_packing ); // frame_packing_arrangement_type + bs_write1( &q, quincunx_sampling_flag ); // quincunx_sampling_flag + + // 0: views are unrelated, 1: left view is on the left, 2: left view is on the right + bs_write ( &q, 6, h->param.i_frame_packing != 6 ); // content_interpretation_type + + bs_write1( &q, 0 ); // spatial_flipping_flag + bs_write1( &q, 0 ); // frame0_flipped_flag + bs_write1( &q, 0 ); // field_views_flag + bs_write1( &q, h->param.i_frame_packing == 5 && !(h->fenc->i_frame&1) ); // current_frame_is_frame0_flag + bs_write1( &q, 0 ); // frame0_self_contained_flag + bs_write1( &q, 0 ); // frame1_self_contained_flag + if( quincunx_sampling_flag == 0 && h->param.i_frame_packing != 5 ) + { + bs_write( &q, 4, 0 ); // frame0_grid_position_x + bs_write( &q, 4, 0 ); // frame0_grid_position_y + bs_write( &q, 4, 0 ); // frame1_grid_position_x + bs_write( &q, 4, 0 ); // frame1_grid_position_y + } + bs_write( &q, 8, 0 ); // frame_packing_arrangement_reserved_byte + // "frame_packing_arrangement_repetition_period equal to 1 specifies that the frame packing arrangement SEI message persists in output" + // for (i_frame_packing == 5) this will undermine current_frame_is_frame0_flag which must alternate every view sequence + bs_write_ue( &q, h->param.i_frame_packing != 5 ); // frame_packing_arrangement_repetition_period + bs_write1( &q, 0 ); // frame_packing_arrangement_extension_flag + + bs_align_10( &q ); + bs_flush( &q ); + + x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_FRAME_PACKING ); +} + +void x264_filler_write( x264_t *h, bs_t *s, int filler ) +{ + bs_realign( s ); + + for( int i = 0; i < filler; i++ ) + bs_write( s, 8, 0xff ); + + bs_rbsp_trailing( s ); + bs_flush( s ); +} + +void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s ) +{ + x264_slice_header_t *sh = &h->sh_backup; + bs_t q; + ALIGNED_4( uint8_t tmp_buf[100] ); + M32( tmp_buf ) = 0; // shut up gcc + bs_init( &q, tmp_buf, 100 ); + + bs_realign( &q ); + + /* We currently only use this for repeating B-refs, as required by Blu-ray. */ + bs_write1( &q, 0 ); //original_idr_flag + bs_write_ue( &q, sh->i_frame_num ); //original_frame_num + if( !h->sps->b_frame_mbs_only ) + bs_write1( &q, 0 ); //original_field_pic_flag + + bs_write1( &q, sh->i_mmco_command_count > 0 ); + if( sh->i_mmco_command_count > 0 ) + { + for( int i = 0; i < sh->i_mmco_command_count; i++ ) + { + bs_write_ue( &q, 1 ); + bs_write_ue( &q, sh->mmco[i].i_difference_of_pic_nums - 1 ); + } + bs_write_ue( &q, 0 ); + } + + bs_align_10( &q ); + bs_flush( &q ); + + x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_DEC_REF_PIC_MARKING ); +} + +int x264_sei_avcintra_umid_write( x264_t *h, bs_t *s ) +{ + uint8_t data[512]; + const char *msg = "UMID"; + const int len = 497; + + memset( data, 0xff, len ); + memcpy( data, avcintra_uuid, sizeof(avcintra_uuid) ); + memcpy( data+16, msg, strlen(msg) ); + + data[20] = 0x13; + /* These bytes appear to be some sort of frame/seconds counter in certain applications, + * but others jump around, so leave them as zero for now */ + data[22] = data[23] = data[25] = data[26] = 0; + data[28] = 0x14; + data[30] = data[31] = data[33] = data[34] = 0; + data[36] = 0x60; + data[41] = 0x22; /* Believed to be some sort of end of basic UMID identifier */ + data[60] = 0x62; + data[62] = data[63] = data[65] = data[66] = 0; + data[68] = 0x63; + data[70] = data[71] = data[73] = data[74] = 0; + + x264_sei_write( &h->out.bs, data, len, SEI_USER_DATA_UNREGISTERED ); + + return 0; +} + +int x264_sei_avcintra_vanc_write( x264_t *h, bs_t *s, int len ) +{ + uint8_t data[6000]; + const char *msg = "VANC"; + if( len > sizeof(data) ) + { + x264_log( h, X264_LOG_ERROR, "AVC-Intra SEI is too large (%d)\n", len ); + return -1; + } + + memset( data, 0xff, len ); + memcpy( data, avcintra_uuid, sizeof(avcintra_uuid) ); + memcpy( data+16, msg, strlen(msg) ); + + x264_sei_write( &h->out.bs, data, len, SEI_USER_DATA_UNREGISTERED ); + + return 0; +} + +const x264_level_t x264_levels[] = +{ + { 10, 1485, 99, 396, 64, 175, 64, 64, 0, 2, 0, 0, 1 }, + { 9, 1485, 99, 396, 128, 350, 64, 64, 0, 2, 0, 0, 1 }, /* "1b" */ + { 11, 3000, 396, 900, 192, 500, 128, 64, 0, 2, 0, 0, 1 }, + { 12, 6000, 396, 2376, 384, 1000, 128, 64, 0, 2, 0, 0, 1 }, + { 13, 11880, 396, 2376, 768, 2000, 128, 64, 0, 2, 0, 0, 1 }, + { 20, 11880, 396, 2376, 2000, 2000, 128, 64, 0, 2, 0, 0, 1 }, + { 21, 19800, 792, 4752, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, + { 22, 20250, 1620, 8100, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, + { 30, 40500, 1620, 8100, 10000, 10000, 256, 32, 22, 2, 0, 1, 0 }, + { 31, 108000, 3600, 18000, 14000, 14000, 512, 16, 60, 4, 1, 1, 0 }, + { 32, 216000, 5120, 20480, 20000, 20000, 512, 16, 60, 4, 1, 1, 0 }, + { 40, 245760, 8192, 32768, 20000, 25000, 512, 16, 60, 4, 1, 1, 0 }, + { 41, 245760, 8192, 32768, 50000, 62500, 512, 16, 24, 2, 1, 1, 0 }, + { 42, 522240, 8704, 34816, 50000, 62500, 512, 16, 24, 2, 1, 1, 1 }, + { 50, 589824, 22080, 110400, 135000, 135000, 512, 16, 24, 2, 1, 1, 1 }, + { 51, 983040, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, + { 52, 2073600, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, + { 60, 4177920, 139264, 696320, 240000, 240000, 8192, 16, 24, 2, 1, 1, 1 }, + { 61, 8355840, 139264, 696320, 480000, 480000, 8192, 16, 24, 2, 1, 1, 1 }, + { 62, 16711680, 139264, 696320, 800000, 800000, 8192, 16, 24, 2, 1, 1, 1 }, + { 0 } +}; + +#define ERROR(...)\ +{\ + if( verbose )\ + x264_log( h, X264_LOG_WARNING, __VA_ARGS__ );\ + ret = 1;\ +} + +int x264_validate_levels( x264_t *h, int verbose ) +{ + int ret = 0; + int mbs = h->sps->i_mb_width * h->sps->i_mb_height; + int dpb = mbs * h->sps->vui.i_max_dec_frame_buffering; + int cbp_factor = h->sps->i_profile_idc>=PROFILE_HIGH422 ? 16 : + h->sps->i_profile_idc==PROFILE_HIGH10 ? 12 : + h->sps->i_profile_idc==PROFILE_HIGH ? 5 : 4; + + const x264_level_t *l = x264_levels; + while( l->level_idc != 0 && l->level_idc != h->param.i_level_idc ) + l++; + + if( l->frame_size < mbs + || l->frame_size*8 < h->sps->i_mb_width * h->sps->i_mb_width + || l->frame_size*8 < h->sps->i_mb_height * h->sps->i_mb_height ) + ERROR( "frame MB size (%dx%d) > level limit (%d)\n", + h->sps->i_mb_width, h->sps->i_mb_height, l->frame_size ); + if( dpb > l->dpb ) + ERROR( "DPB size (%d frames, %d mbs) > level limit (%d frames, %d mbs)\n", + h->sps->vui.i_max_dec_frame_buffering, dpb, l->dpb / mbs, l->dpb ); + +#define CHECK( name, limit, val ) \ + if( (val) > (limit) ) \ + ERROR( name " (%"PRId64") > level limit (%d)\n", (int64_t)(val), (limit) ); + + CHECK( "VBV bitrate", (l->bitrate * cbp_factor) / 4, h->param.rc.i_vbv_max_bitrate ); + CHECK( "VBV buffer", (l->cpb * cbp_factor) / 4, h->param.rc.i_vbv_buffer_size ); + CHECK( "MV range", l->mv_range, h->param.analyse.i_mv_range ); + CHECK( "interlaced", !l->frame_only, h->param.b_interlaced ); + CHECK( "fake interlaced", !l->frame_only, h->param.b_fake_interlaced ); + + if( h->param.i_fps_den > 0 ) + CHECK( "MB rate", l->mbps, (int64_t)mbs * h->param.i_fps_num / h->param.i_fps_den ); + + /* TODO check the rest of the limits */ + return ret; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/set.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/set.h new file mode 100644 index 00000000..8e11655d --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/set.h @@ -0,0 +1,47 @@ +/***************************************************************************** + * set.h: header writing + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_ENCODER_SET_H +#define X264_ENCODER_SET_H + +void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ); +void x264_sps_init_reconfigurable( x264_sps_t *sps, x264_param_t *param ); +void x264_sps_write( bs_t *s, x264_sps_t *sps ); +void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *sps ); +void x264_pps_write( bs_t *s, x264_sps_t *sps, x264_pps_t *pps ); +void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt ); +int x264_sei_version_write( x264_t *h, bs_t *s ); +int x264_validate_levels( x264_t *h, int verbose ); +void x264_sei_buffering_period_write( x264_t *h, bs_t *s ); +void x264_sei_pic_timing_write( x264_t *h, bs_t *s ); +void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s ); +void x264_sei_frame_packing_write( x264_t *h, bs_t *s ); +int x264_sei_avcintra_umid_write( x264_t *h, bs_t *s ); +int x264_sei_avcintra_vanc_write( x264_t *h, bs_t *s, int len ); +void x264_sei_write( bs_t *s, uint8_t *payload, int payload_size, int payload_type ); +void x264_filler_write( x264_t *h, bs_t *s, int filler ); + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/slicetype-cl.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/slicetype-cl.c new file mode 100644 index 00000000..7768b7cb --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/slicetype-cl.c @@ -0,0 +1,780 @@ +/***************************************************************************** + * slicetype-cl.c: OpenCL slicetype decision code (lowres lookahead) + ***************************************************************************** + * Copyright (C) 2012-2017 x264 project + * + * Authors: Steve Borho + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "macroblock.h" +#include "me.h" + +#if HAVE_OPENCL +#ifdef _WIN32 +#include +#endif + +void x264_weights_analyse( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, int b_lookahead ); + +/* We define CL_QUEUE_THREAD_HANDLE_AMD here because it is not defined + * in the OpenCL headers shipped with NVIDIA drivers. We need to be + * able to compile on an NVIDIA machine and run optimally on an AMD GPU. */ +#define CL_QUEUE_THREAD_HANDLE_AMD 0x403E + +#define OCLCHECK( method, ... )\ +do\ +{\ + if( h->opencl.b_fatal_error )\ + return -1;\ + status = ocl->method( __VA_ARGS__ );\ + if( status != CL_SUCCESS ) {\ + h->param.b_opencl = 0;\ + h->opencl.b_fatal_error = 1;\ + x264_log( h, X264_LOG_ERROR, # method " error '%d'\n", status );\ + return -1;\ + }\ +} while( 0 ) + +void x264_opencl_flush( x264_t *h ) +{ + x264_opencl_function_t *ocl = h->opencl.ocl; + + ocl->clFinish( h->opencl.queue ); + + /* Finish copies from the GPU by copying from the page-locked buffer to + * their final destination */ + for( int i = 0; i < h->opencl.num_copies; i++ ) + memcpy( h->opencl.copies[i].dest, h->opencl.copies[i].src, h->opencl.copies[i].bytes ); + h->opencl.num_copies = 0; + h->opencl.pl_occupancy = 0; +} + +static void *x264_opencl_alloc_locked( x264_t *h, int bytes ) +{ + if( h->opencl.pl_occupancy + bytes >= PAGE_LOCKED_BUF_SIZE ) + x264_opencl_flush( h ); + assert( bytes < PAGE_LOCKED_BUF_SIZE ); + char *ptr = h->opencl.page_locked_ptr + h->opencl.pl_occupancy; + h->opencl.pl_occupancy += bytes; + return ptr; +} + +int x264_opencl_lowres_init( x264_t *h, x264_frame_t *fenc, int lambda ) +{ + if( fenc->b_intra_calculated ) + return 0; + fenc->b_intra_calculated = 1; + + x264_opencl_function_t *ocl = h->opencl.ocl; + int luma_length = fenc->i_stride[0] * fenc->i_lines[0]; + +#define CREATEBUF( out, flags, size )\ + out = ocl->clCreateBuffer( h->opencl.context, (flags), (size), NULL, &status );\ + if( status != CL_SUCCESS ) { h->param.b_opencl = 0; x264_log( h, X264_LOG_ERROR, "clCreateBuffer error '%d'\n", status ); return -1; } +#define CREATEIMAGE( out, flags, pf, width, height )\ + out = ocl->clCreateImage2D( h->opencl.context, (flags), &pf, width, height, 0, NULL, &status );\ + if( status != CL_SUCCESS ) { h->param.b_opencl = 0; x264_log( h, X264_LOG_ERROR, "clCreateImage2D error '%d'\n", status ); return -1; } + + int mb_count = h->mb.i_mb_count; + cl_int status; + + if( !h->opencl.lowres_mv_costs ) + { + /* Allocate shared memory buffers */ + int width = h->mb.i_mb_width * 8 * sizeof(pixel); + int height = h->mb.i_mb_height * 8 * sizeof(pixel); + + cl_image_format pixel_format; + pixel_format.image_channel_order = CL_R; + pixel_format.image_channel_data_type = CL_UNSIGNED_INT32; + CREATEIMAGE( h->opencl.weighted_luma_hpel, CL_MEM_READ_WRITE, pixel_format, width, height ); + + for( int i = 0; i < NUM_IMAGE_SCALES; i++ ) + { + pixel_format.image_channel_order = CL_RGBA; + pixel_format.image_channel_data_type = CL_UNSIGNED_INT8; + CREATEIMAGE( h->opencl.weighted_scaled_images[i], CL_MEM_READ_WRITE, pixel_format, width, height ); + width >>= 1; + height >>= 1; + } + + CREATEBUF( h->opencl.lowres_mv_costs, CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) ); + CREATEBUF( h->opencl.lowres_costs[0], CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) ); + CREATEBUF( h->opencl.lowres_costs[1], CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) ); + CREATEBUF( h->opencl.mv_buffers[0], CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * 2 ); + CREATEBUF( h->opencl.mv_buffers[1], CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * 2 ); + CREATEBUF( h->opencl.mvp_buffer, CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * 2 ); + CREATEBUF( h->opencl.frame_stats[0], CL_MEM_WRITE_ONLY, 4 * sizeof(int) ); + CREATEBUF( h->opencl.frame_stats[1], CL_MEM_WRITE_ONLY, 4 * sizeof(int) ); + CREATEBUF( h->opencl.row_satds[0], CL_MEM_WRITE_ONLY, h->mb.i_mb_height * sizeof(int) ); + CREATEBUF( h->opencl.row_satds[1], CL_MEM_WRITE_ONLY, h->mb.i_mb_height * sizeof(int) ); + CREATEBUF( h->opencl.luma_16x16_image[0], CL_MEM_READ_ONLY, luma_length ); + CREATEBUF( h->opencl.luma_16x16_image[1], CL_MEM_READ_ONLY, luma_length ); + } + + if( !fenc->opencl.intra_cost ) + { + /* Allocate per-frame buffers */ + int width = h->mb.i_mb_width * 8 * sizeof(pixel); + int height = h->mb.i_mb_height * 8 * sizeof(pixel); + + cl_image_format pixel_format; + pixel_format.image_channel_order = CL_R; + pixel_format.image_channel_data_type = CL_UNSIGNED_INT32; + CREATEIMAGE( fenc->opencl.luma_hpel, CL_MEM_READ_WRITE, pixel_format, width, height ); + + for( int i = 0; i < NUM_IMAGE_SCALES; i++ ) + { + pixel_format.image_channel_order = CL_RGBA; + pixel_format.image_channel_data_type = CL_UNSIGNED_INT8; + CREATEIMAGE( fenc->opencl.scaled_image2Ds[i], CL_MEM_READ_WRITE, pixel_format, width, height ); + width >>= 1; + height >>= 1; + } + CREATEBUF( fenc->opencl.inv_qscale_factor, CL_MEM_READ_ONLY, mb_count * sizeof(int16_t) ); + CREATEBUF( fenc->opencl.intra_cost, CL_MEM_WRITE_ONLY, mb_count * sizeof(int16_t) ); + CREATEBUF( fenc->opencl.lowres_mvs0, CL_MEM_READ_WRITE, mb_count * 2 * sizeof(int16_t) * (h->param.i_bframe + 1) ); + CREATEBUF( fenc->opencl.lowres_mvs1, CL_MEM_READ_WRITE, mb_count * 2 * sizeof(int16_t) * (h->param.i_bframe + 1) ); + CREATEBUF( fenc->opencl.lowres_mv_costs0, CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * (h->param.i_bframe + 1) ); + CREATEBUF( fenc->opencl.lowres_mv_costs1, CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * (h->param.i_bframe + 1) ); + } +#undef CREATEBUF +#undef CREATEIMAGE + + /* Copy image to the GPU, downscale to unpadded 8x8, then continue for all scales */ + + char *locked = x264_opencl_alloc_locked( h, luma_length ); + memcpy( locked, fenc->plane[0], luma_length ); + OCLCHECK( clEnqueueWriteBuffer, h->opencl.queue, h->opencl.luma_16x16_image[h->opencl.last_buf], CL_FALSE, 0, luma_length, locked, 0, NULL, NULL ); + + size_t gdim[2]; + if( h->param.rc.i_aq_mode && fenc->i_inv_qscale_factor ) + { + int size = h->mb.i_mb_count * sizeof(int16_t); + locked = x264_opencl_alloc_locked( h, size ); + memcpy( locked, fenc->i_inv_qscale_factor, size ); + OCLCHECK( clEnqueueWriteBuffer, h->opencl.queue, fenc->opencl.inv_qscale_factor, CL_FALSE, 0, size, locked, 0, NULL, NULL ); + } + else + { + /* Fill fenc->opencl.inv_qscale_factor with NOP (256) */ + cl_uint arg = 0; + int16_t value = 256; + OCLCHECK( clSetKernelArg, h->opencl.memset_kernel, arg++, sizeof(cl_mem), &fenc->opencl.inv_qscale_factor ); + OCLCHECK( clSetKernelArg, h->opencl.memset_kernel, arg++, sizeof(int16_t), &value ); + gdim[0] = h->mb.i_mb_count; + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.memset_kernel, 1, NULL, gdim, NULL, 0, NULL, NULL ); + } + + int stride = fenc->i_stride[0]; + cl_uint arg = 0; + OCLCHECK( clSetKernelArg, h->opencl.downscale_hpel_kernel, arg++, sizeof(cl_mem), &h->opencl.luma_16x16_image[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.downscale_hpel_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[0] ); + OCLCHECK( clSetKernelArg, h->opencl.downscale_hpel_kernel, arg++, sizeof(cl_mem), &fenc->opencl.luma_hpel ); + OCLCHECK( clSetKernelArg, h->opencl.downscale_hpel_kernel, arg++, sizeof(int), &stride ); + gdim[0] = 8 * h->mb.i_mb_width; + gdim[1] = 8 * h->mb.i_mb_height; + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.downscale_hpel_kernel, 2, NULL, gdim, NULL, 0, NULL, NULL ); + + for( int i = 0; i < NUM_IMAGE_SCALES - 1; i++ ) + { + /* Workaround for AMD Southern Island: + * + * Alternate kernel instances. No perf impact to this, so we do it for + * all GPUs. It prevents the same kernel from being enqueued + * back-to-back, avoiding a dependency calculation bug in the driver. + */ + cl_kernel kern = i & 1 ? h->opencl.downscale_kernel1 : h->opencl.downscale_kernel2; + + arg = 0; + OCLCHECK( clSetKernelArg, kern, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[i] ); + OCLCHECK( clSetKernelArg, kern, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[i+1] ); + gdim[0] >>= 1; + gdim[1] >>= 1; + if( gdim[0] < 16 || gdim[1] < 16 ) + break; + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, kern, 2, NULL, gdim, NULL, 0, NULL, NULL ); + } + + size_t ldim[2]; + gdim[0] = ((h->mb.i_mb_width + 31)>>5)<<5; + gdim[1] = 8*h->mb.i_mb_height; + ldim[0] = 32; + ldim[1] = 8; + arg = 0; + + /* For presets slow, slower, and placebo, check all 10 intra modes that the + * C lookahead supports. For faster presets, only check the most frequent 8 + * modes + */ + int slow = h->param.analyse.i_subpel_refine > 7; + OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[0] ); + OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(cl_mem), &fenc->opencl.intra_cost ); + OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(cl_mem), &h->opencl.frame_stats[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(int), &lambda ); + OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(int), &h->mb.i_mb_width ); + OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(int), &slow ); + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.intra_kernel, 2, NULL, gdim, ldim, 0, NULL, NULL ); + + gdim[0] = 256; + gdim[1] = h->mb.i_mb_height; + ldim[0] = 256; + ldim[1] = 1; + arg = 0; + OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(cl_mem), &fenc->opencl.intra_cost ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(cl_mem), &fenc->opencl.inv_qscale_factor ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(cl_mem), &h->opencl.row_satds[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(cl_mem), &h->opencl.frame_stats[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(int), &h->mb.i_mb_width ); + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.rowsum_intra_kernel, 2, NULL, gdim, ldim, 0, NULL, NULL ); + + if( h->opencl.num_copies >= MAX_FINISH_COPIES - 4 ) + x264_opencl_flush( h ); + + int size = h->mb.i_mb_count * sizeof(int16_t); + locked = x264_opencl_alloc_locked( h, size ); + OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, fenc->opencl.intra_cost, CL_FALSE, 0, size, locked, 0, NULL, NULL ); + h->opencl.copies[h->opencl.num_copies].dest = fenc->lowres_costs[0][0]; + h->opencl.copies[h->opencl.num_copies].src = locked; + h->opencl.copies[h->opencl.num_copies].bytes = size; + h->opencl.num_copies++; + + size = h->mb.i_mb_height * sizeof(int); + locked = x264_opencl_alloc_locked( h, size ); + OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.row_satds[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL ); + h->opencl.copies[h->opencl.num_copies].dest = fenc->i_row_satds[0][0]; + h->opencl.copies[h->opencl.num_copies].src = locked; + h->opencl.copies[h->opencl.num_copies].bytes = size; + h->opencl.num_copies++; + + size = sizeof(int) * 4; + locked = x264_opencl_alloc_locked( h, size ); + OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.frame_stats[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL ); + h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_cost_est[0][0]; + h->opencl.copies[h->opencl.num_copies].src = locked; + h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int); + h->opencl.num_copies++; + h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_cost_est_aq[0][0]; + h->opencl.copies[h->opencl.num_copies].src = locked + sizeof(int); + h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int); + h->opencl.num_copies++; + + h->opencl.last_buf = !h->opencl.last_buf; + return 0; +} + +/* This function was tested emprically on a number of AMD and NV GPUs. Making a + * function which returns perfect launch dimensions is impossible; some + * applications will have self-tuning code to try many possible variables and + * measure the runtime. Here we simply make an educated guess based on what we + * know GPUs typically prefer. */ +static void x264_optimal_launch_dims( x264_t *h, size_t *gdims, size_t *ldims, const cl_kernel kernel, const cl_device_id device ) +{ + x264_opencl_function_t *ocl = h->opencl.ocl; + size_t max_work_group = 256; /* reasonable defaults for OpenCL 1.0 devices, below APIs may fail */ + size_t preferred_multiple = 64; + cl_uint num_cus = 6; + + ocl->clGetKernelWorkGroupInfo( kernel, device, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &max_work_group, NULL ); + ocl->clGetKernelWorkGroupInfo( kernel, device, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, sizeof(size_t), &preferred_multiple, NULL ); + ocl->clGetDeviceInfo( device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), &num_cus, NULL ); + + ldims[0] = preferred_multiple; + ldims[1] = 8; + + /* make ldims[1] an even divisor of gdims[1] */ + while( gdims[1] & (ldims[1] - 1) ) + { + ldims[0] <<= 1; + ldims[1] >>= 1; + } + /* make total ldims fit under the max work-group dimensions for the device */ + while( ldims[0] * ldims[1] > max_work_group ) + { + if( (ldims[0] <= preferred_multiple) && (ldims[1] > 1) ) + ldims[1] >>= 1; + else + ldims[0] >>= 1; + } + + if( ldims[0] > gdims[0] ) + { + /* remove preferred multiples until we're close to gdims[0] */ + while( gdims[0] + preferred_multiple < ldims[0] ) + ldims[0] -= preferred_multiple; + gdims[0] = ldims[0]; + } + else + { + /* make gdims an even multiple of ldims */ + gdims[0] = (gdims[0]+ldims[0]-1)/ldims[0]; + gdims[0] *= ldims[0]; + } + + /* make ldims smaller to spread work across compute units */ + while( (gdims[0]/ldims[0]) * (gdims[1]/ldims[1]) * 2 <= num_cus ) + { + if( ldims[0] > preferred_multiple ) + ldims[0] >>= 1; + else if( ldims[1] > 1 ) + ldims[1] >>= 1; + else + break; + } + /* for smaller GPUs, try not to abuse their texture cache */ + if( num_cus == 6 && ldims[0] == 64 && ldims[1] == 4 ) + ldims[0] = 32; +} + +int x264_opencl_motionsearch( x264_t *h, x264_frame_t **frames, int b, int ref, int b_islist1, int lambda, const x264_weight_t *w ) +{ + x264_opencl_function_t *ocl = h->opencl.ocl; + x264_frame_t *fenc = frames[b]; + x264_frame_t *fref = frames[ref]; + + cl_mem ref_scaled_images[NUM_IMAGE_SCALES]; + cl_mem ref_luma_hpel; + cl_int status; + + if( w && w->weightfn ) + { + size_t gdims[2]; + + gdims[0] = 8 * h->mb.i_mb_width; + gdims[1] = 8 * h->mb.i_mb_height; + + /* WeightP: Perform a filter on fref->opencl.scaled_image2Ds[] and fref->opencl.luma_hpel */ + for( int i = 0; i < NUM_IMAGE_SCALES; i++ ) + { + cl_uint arg = 0; + OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(cl_mem), &fref->opencl.scaled_image2Ds[i] ); + OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(cl_mem), &h->opencl.weighted_scaled_images[i] ); + OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(int32_t), &w->i_offset ); + OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(int32_t), &w->i_scale ); + OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(int32_t), &w->i_denom ); + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.weightp_scaled_images_kernel, 2, NULL, gdims, NULL, 0, NULL, NULL ); + + gdims[0] >>= 1; + gdims[1] >>= 1; + if( gdims[0] < 16 || gdims[1] < 16 ) + break; + } + + cl_uint arg = 0; + gdims[0] = 8 * h->mb.i_mb_width; + gdims[1] = 8 * h->mb.i_mb_height; + + OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(cl_mem), &fref->opencl.luma_hpel ); + OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(cl_mem), &h->opencl.weighted_luma_hpel ); + OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(int32_t), &w->i_offset ); + OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(int32_t), &w->i_scale ); + OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(int32_t), &w->i_denom ); + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.weightp_hpel_kernel, 2, NULL, gdims, NULL, 0, NULL, NULL ); + + /* Use weighted reference planes for motion search */ + for( int i = 0; i < NUM_IMAGE_SCALES; i++ ) + ref_scaled_images[i] = h->opencl.weighted_scaled_images[i]; + ref_luma_hpel = h->opencl.weighted_luma_hpel; + } + else + { + /* Use unweighted reference planes for motion search */ + for( int i = 0; i < NUM_IMAGE_SCALES; i++ ) + ref_scaled_images[i] = fref->opencl.scaled_image2Ds[i]; + ref_luma_hpel = fref->opencl.luma_hpel; + } + + const int num_iterations[NUM_IMAGE_SCALES] = { 1, 1, 2, 3 }; + int b_first_iteration = 1; + int b_reverse_references = 1; + int A = 1; + + + int mb_per_group = 0; + int cost_local_size = 0; + int mvc_local_size = 0; + int mb_width; + + size_t gdims[2]; + size_t ldims[2]; + + /* scale 0 is 8x8 */ + for( int scale = NUM_IMAGE_SCALES-1; scale >= 0; scale-- ) + { + mb_width = h->mb.i_mb_width >> scale; + gdims[0] = mb_width; + gdims[1] = h->mb.i_mb_height >> scale; + if( gdims[0] < 2 || gdims[1] < 2 ) + continue; + gdims[0] <<= 2; + x264_optimal_launch_dims( h, gdims, ldims, h->opencl.hme_kernel, h->opencl.device ); + + mb_per_group = (ldims[0] >> 2) * ldims[1]; + cost_local_size = 4 * mb_per_group * sizeof(int16_t); + mvc_local_size = 4 * mb_per_group * sizeof(int16_t) * 2; + int scaled_me_range = h->param.analyse.i_me_range >> scale; + int b_shift_index = 1; + + cl_uint arg = 0; + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[scale] ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &ref_scaled_images[scale] ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &h->opencl.mv_buffers[A] ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &h->opencl.mv_buffers[!A] ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &h->opencl.lowres_mv_costs ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), (void*)&h->opencl.mvp_buffer ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, cost_local_size, NULL ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, mvc_local_size, NULL ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &mb_width ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &lambda ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &scaled_me_range ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &scale ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &b_shift_index ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &b_first_iteration ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &b_reverse_references ); + + for( int iter = 0; iter < num_iterations[scale]; iter++ ) + { + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.hme_kernel, 2, NULL, gdims, ldims, 0, NULL, NULL ); + + b_shift_index = 0; + b_first_iteration = 0; + + /* alternate top-left vs bot-right MB references at lower scales, so + * motion field smooths more quickly. */ + if( scale > 2 ) + b_reverse_references ^= 1; + else + b_reverse_references = 0; + A = !A; + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, 2, sizeof(cl_mem), &h->opencl.mv_buffers[A] ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, 3, sizeof(cl_mem), &h->opencl.mv_buffers[!A] ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg - 3, sizeof(int), &b_shift_index ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg - 2, sizeof(int), &b_first_iteration ); + OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg - 1, sizeof(int), &b_reverse_references ); + } + } + + int satd_local_size = mb_per_group * sizeof(uint32_t) * 16; + cl_uint arg = 0; + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[0] ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &ref_luma_hpel ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &h->opencl.mv_buffers[A] ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &h->opencl.lowres_mv_costs ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, cost_local_size, NULL ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, satd_local_size, NULL ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, mvc_local_size, NULL ); + + if( b_islist1 ) + { + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mvs1 ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mv_costs1 ); + } + else + { + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mvs0 ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mv_costs0 ); + } + + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &mb_width ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &lambda ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &b ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &ref ); + OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &b_islist1 ); + + if( h->opencl.b_device_AMD_SI ) + { + /* workaround for AMD Southern Island driver scheduling bug (fixed in + * July 2012), perform meaningless small copy to add a data dependency */ + OCLCHECK( clEnqueueCopyBuffer, h->opencl.queue, h->opencl.mv_buffers[A], h->opencl.mv_buffers[!A], 0, 0, 20, 0, NULL, NULL ); + } + + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.subpel_refine_kernel, 2, NULL, gdims, ldims, 0, NULL, NULL ); + + int mvlen = 2 * sizeof(int16_t) * h->mb.i_mb_count; + + if( h->opencl.num_copies >= MAX_FINISH_COPIES - 1 ) + x264_opencl_flush( h ); + + char *locked = x264_opencl_alloc_locked( h, mvlen ); + h->opencl.copies[h->opencl.num_copies].src = locked; + h->opencl.copies[h->opencl.num_copies].bytes = mvlen; + + if( b_islist1 ) + { + int mvs_offset = mvlen * (ref - b - 1); + OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, fenc->opencl.lowres_mvs1, CL_FALSE, mvs_offset, mvlen, locked, 0, NULL, NULL ); + h->opencl.copies[h->opencl.num_copies].dest = fenc->lowres_mvs[1][ref - b - 1]; + } + else + { + int mvs_offset = mvlen * (b - ref - 1); + OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, fenc->opencl.lowres_mvs0, CL_FALSE, mvs_offset, mvlen, locked, 0, NULL, NULL ); + h->opencl.copies[h->opencl.num_copies].dest = fenc->lowres_mvs[0][b - ref - 1]; + } + + h->opencl.num_copies++; + + return 0; +} + +int x264_opencl_finalize_cost( x264_t *h, int lambda, x264_frame_t **frames, int p0, int p1, int b, int dist_scale_factor ) +{ + x264_opencl_function_t *ocl = h->opencl.ocl; + cl_int status; + x264_frame_t *fenc = frames[b]; + x264_frame_t *fref0 = frames[p0]; + x264_frame_t *fref1 = frames[p1]; + + int bipred_weight = h->param.analyse.b_weighted_bipred ? 64 - (dist_scale_factor >> 2) : 32; + + /* Tasks for this kernel: + * 1. Select least cost mode (intra, ref0, ref1) + * list_used 0, 1, 2, or 3. if B frame, do not allow intra + * 2. if B frame, try bidir predictions. + * 3. lowres_costs[i_mb_xy] = X264_MIN( bcost, LOWRES_COST_MASK ) + (list_used << LOWRES_COST_SHIFT); */ + size_t gdims[2] = { h->mb.i_mb_width, h->mb.i_mb_height }; + size_t ldim_bidir[2]; + size_t *ldims = NULL; + int cost_local_size = 4; + int satd_local_size = 4; + if( b < p1 ) + { + /* For B frames, use 4 threads per MB for BIDIR checks */ + ldims = ldim_bidir; + gdims[0] <<= 2; + x264_optimal_launch_dims( h, gdims, ldims, h->opencl.mode_select_kernel, h->opencl.device ); + int mb_per_group = (ldims[0] >> 2) * ldims[1]; + cost_local_size = 4 * mb_per_group * sizeof(int16_t); + satd_local_size = 16 * mb_per_group * sizeof(uint32_t); + } + + cl_uint arg = 0; + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[0] ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fref0->opencl.luma_hpel ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fref1->opencl.luma_hpel ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mvs0 ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mvs1 ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fref1->opencl.lowres_mvs0 ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mv_costs0 ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mv_costs1 ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.intra_cost ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &h->opencl.lowres_costs[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &h->opencl.frame_stats[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, cost_local_size, NULL ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, satd_local_size, NULL ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &h->mb.i_mb_width ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &bipred_weight ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &dist_scale_factor ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &b ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &p0 ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &p1 ); + OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &lambda ); + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.mode_select_kernel, 2, NULL, gdims, ldims, 0, NULL, NULL ); + + /* Sum costs across rows, atomicAdd down frame */ + size_t gdim[2] = { 256, h->mb.i_mb_height }; + size_t ldim[2] = { 256, 1 }; + + arg = 0; + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(cl_mem), &h->opencl.lowres_costs[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(cl_mem), &fenc->opencl.inv_qscale_factor ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(cl_mem), &h->opencl.row_satds[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(cl_mem), &h->opencl.frame_stats[h->opencl.last_buf] ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &h->mb.i_mb_width ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &h->param.i_bframe_bias ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &b ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &p0 ); + OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &p1 ); + OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.rowsum_inter_kernel, 2, NULL, gdim, ldim, 0, NULL, NULL ); + + if( h->opencl.num_copies >= MAX_FINISH_COPIES - 4 ) + x264_opencl_flush( h ); + + int size = h->mb.i_mb_count * sizeof(int16_t); + char *locked = x264_opencl_alloc_locked( h, size ); + h->opencl.copies[h->opencl.num_copies].src = locked; + h->opencl.copies[h->opencl.num_copies].dest = fenc->lowres_costs[b - p0][p1 - b]; + h->opencl.copies[h->opencl.num_copies].bytes = size; + OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.lowres_costs[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL ); + h->opencl.num_copies++; + + size = h->mb.i_mb_height * sizeof(int); + locked = x264_opencl_alloc_locked( h, size ); + h->opencl.copies[h->opencl.num_copies].src = locked; + h->opencl.copies[h->opencl.num_copies].dest = fenc->i_row_satds[b - p0][p1 - b]; + h->opencl.copies[h->opencl.num_copies].bytes = size; + OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.row_satds[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL ); + h->opencl.num_copies++; + + size = 4 * sizeof(int); + locked = x264_opencl_alloc_locked( h, size ); + OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.frame_stats[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL ); + h->opencl.last_buf = !h->opencl.last_buf; + + h->opencl.copies[h->opencl.num_copies].src = locked; + h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_cost_est[b - p0][p1 - b]; + h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int); + h->opencl.num_copies++; + h->opencl.copies[h->opencl.num_copies].src = locked + sizeof(int); + h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_cost_est_aq[b - p0][p1 - b]; + h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int); + h->opencl.num_copies++; + + if( b == p1 ) // P frames only + { + h->opencl.copies[h->opencl.num_copies].src = locked + 2 * sizeof(int); + h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_intra_mbs[b - p0]; + h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int); + h->opencl.num_copies++; + } + return 0; +} + +void x264_opencl_slicetype_prep( x264_t *h, x264_frame_t **frames, int num_frames, int lambda ) +{ + if( h->param.b_opencl ) + { +#ifdef _WIN32 + /* Temporarily boost priority of this lookahead thread and the OpenCL + * driver's thread until the end of this function. On AMD GPUs this + * greatly reduces the latency of enqueuing kernels and getting results + * on Windows. */ + HANDLE id = GetCurrentThread(); + h->opencl.lookahead_thread_pri = GetThreadPriority( id ); + SetThreadPriority( id, THREAD_PRIORITY_ABOVE_NORMAL ); + x264_opencl_function_t *ocl = h->opencl.ocl; + cl_int status = ocl->clGetCommandQueueInfo( h->opencl.queue, CL_QUEUE_THREAD_HANDLE_AMD, sizeof(HANDLE), &id, NULL ); + if( status == CL_SUCCESS ) + { + h->opencl.opencl_thread_pri = GetThreadPriority( id ); + SetThreadPriority( id, THREAD_PRIORITY_ABOVE_NORMAL ); + } +#endif + + /* precalculate intra and I frames */ + for( int i = 0; i <= num_frames; i++ ) + x264_opencl_lowres_init( h, frames[i], lambda ); + x264_opencl_flush( h ); + + if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS && h->param.i_bframe ) + { + /* For trellis B-Adapt, precompute exhaustive motion searches */ + for( int b = 0; b <= num_frames; b++ ) + { + for( int j = 1; j < h->param.i_bframe; j++ ) + { + int p0 = b - j; + if( p0 >= 0 && frames[b]->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF ) + { + const x264_weight_t *w = x264_weight_none; + + if( h->param.analyse.i_weighted_pred ) + { + x264_emms(); + x264_weights_analyse( h, frames[b], frames[p0], 1 ); + w = frames[b]->weight[0]; + } + frames[b]->lowres_mvs[0][b-p0-1][0][0] = 0; + x264_opencl_motionsearch( h, frames, b, p0, 0, lambda, w ); + } + int p1 = b + j; + if( p1 <= num_frames && frames[b]->lowres_mvs[1][p1-b-1][0][0] == 0x7FFF ) + { + frames[b]->lowres_mvs[1][p1-b-1][0][0] = 0; + x264_opencl_motionsearch( h, frames, b, p1, 1, lambda, NULL ); + } + } + } + + x264_opencl_flush( h ); + } + } +} + + +void x264_opencl_slicetype_end( x264_t *h ) +{ +#ifdef _WIN32 + if( h->param.b_opencl ) + { + HANDLE id = GetCurrentThread(); + SetThreadPriority( id, h->opencl.lookahead_thread_pri ); + x264_opencl_function_t *ocl = h->opencl.ocl; + cl_int status = ocl->clGetCommandQueueInfo( h->opencl.queue, CL_QUEUE_THREAD_HANDLE_AMD, sizeof(HANDLE), &id, NULL ); + if( status == CL_SUCCESS ) + SetThreadPriority( id, h->opencl.opencl_thread_pri ); + } +#endif +} + +int x264_opencl_precalculate_frame_cost( x264_t *h, x264_frame_t **frames, int lambda, int p0, int p1, int b ) +{ + if( (frames[b]->i_cost_est[b-p0][p1-b] >= 0) || (b == p0 && b == p1) ) + return 0; + else + { + int do_search[2]; + int dist_scale_factor = 128; + const x264_weight_t *w = x264_weight_none; + + // avoid duplicating work + frames[b]->i_cost_est[b-p0][p1-b] = 0; + + do_search[0] = b != p0 && frames[b]->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF; + do_search[1] = b != p1 && frames[b]->lowres_mvs[1][p1-b-1][0][0] == 0x7FFF; + if( do_search[0] ) + { + if( h->param.analyse.i_weighted_pred && b == p1 ) + { + x264_emms(); + x264_weights_analyse( h, frames[b], frames[p0], 1 ); + w = frames[b]->weight[0]; + } + frames[b]->lowres_mvs[0][b-p0-1][0][0] = 0; + } + if( do_search[1] ) + frames[b]->lowres_mvs[1][p1-b-1][0][0] = 0; + if( b == p1 ) + frames[b]->i_intra_mbs[b-p0] = 0; + if( p1 != p0 ) + dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0); + + frames[b]->i_cost_est[b-p0][p1-b] = 0; + frames[b]->i_cost_est_aq[b-p0][p1-b] = 0; + + x264_opencl_lowres_init( h, frames[b], lambda ); + + if( do_search[0] ) + { + x264_opencl_lowres_init( h, frames[p0], lambda ); + x264_opencl_motionsearch( h, frames, b, p0, 0, lambda, w ); + } + if( do_search[1] ) + { + x264_opencl_lowres_init( h, frames[p1], lambda ); + x264_opencl_motionsearch( h, frames, b, p1, 1, lambda, NULL ); + } + x264_opencl_finalize_cost( h, lambda, frames, p0, p1, b, dist_scale_factor ); + return 1; + } +} + +#endif diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/slicetype.c b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/slicetype.c new file mode 100644 index 00000000..6c0aaa8c --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/encoder/slicetype.c @@ -0,0 +1,2033 @@ +/***************************************************************************** + * slicetype.c: lookahead analysis + ***************************************************************************** + * Copyright (C) 2005-2017 x264 project + * + * Authors: Fiona Glaser + * Loren Merritt + * Dylan Yudaken + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#include "common/common.h" +#include "macroblock.h" +#include "me.h" + +// Indexed by pic_struct values +static const uint8_t delta_tfi_divisor[10] = { 0, 2, 1, 1, 2, 2, 3, 3, 4, 6 }; + +static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, + x264_frame_t **frames, int p0, int p1, int b ); + +void x264_weights_analyse( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, int b_lookahead ); + +#if HAVE_OPENCL +int x264_opencl_lowres_init( x264_t *h, x264_frame_t *fenc, int lambda ); +int x264_opencl_motionsearch( x264_t *h, x264_frame_t **frames, int b, int ref, int b_islist1, int lambda, const x264_weight_t *w ); +int x264_opencl_finalize_cost( x264_t *h, int lambda, x264_frame_t **frames, int p0, int p1, int b, int dist_scale_factor ); +int x264_opencl_precalculate_frame_cost( x264_t *h, x264_frame_t **frames, int lambda, int p0, int p1, int b ); +void x264_opencl_flush( x264_t *h ); +void x264_opencl_slicetype_prep( x264_t *h, x264_frame_t **frames, int num_frames, int lambda ); +void x264_opencl_slicetype_end( x264_t *h ); +#endif + +static void x264_lowres_context_init( x264_t *h, x264_mb_analysis_t *a ) +{ + a->i_qp = X264_LOOKAHEAD_QP; + a->i_lambda = x264_lambda_tab[ a->i_qp ]; + x264_mb_analyse_load_costs( h, a ); + if( h->param.analyse.i_subpel_refine > 1 ) + { + h->mb.i_me_method = X264_MIN( X264_ME_HEX, h->param.analyse.i_me_method ); + h->mb.i_subpel_refine = 4; + } + else + { + h->mb.i_me_method = X264_ME_DIA; + h->mb.i_subpel_refine = 2; + } + h->mb.b_chroma_me = 0; +} + +/* makes a non-h264 weight (i.e. fix7), into an h264 weight */ +static void x264_weight_get_h264( int weight_nonh264, int offset, x264_weight_t *w ) +{ + w->i_offset = offset; + w->i_denom = 7; + w->i_scale = weight_nonh264; + while( w->i_denom > 0 && (w->i_scale > 127) ) + { + w->i_denom--; + w->i_scale >>= 1; + } + w->i_scale = X264_MIN( w->i_scale, 127 ); +} + +static NOINLINE pixel *x264_weight_cost_init_luma( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, pixel *dest ) +{ + int ref0_distance = fenc->i_frame - ref->i_frame - 1; + /* Note: this will never run during lookahead as weights_analyse is only called if no + * motion search has been done. */ + if( fenc->lowres_mvs[0][ref0_distance][0][0] != 0x7FFF ) + { + int i_stride = fenc->i_stride_lowres; + int i_lines = fenc->i_lines_lowres; + int i_width = fenc->i_width_lowres; + int i_mb_xy = 0; + pixel *p = dest; + + for( int y = 0; y < i_lines; y += 8, p += i_stride*8 ) + for( int x = 0; x < i_width; x += 8, i_mb_xy++ ) + { + int mvx = fenc->lowres_mvs[0][ref0_distance][i_mb_xy][0]; + int mvy = fenc->lowres_mvs[0][ref0_distance][i_mb_xy][1]; + h->mc.mc_luma( p+x, i_stride, ref->lowres, i_stride, + mvx+(x<<2), mvy+(y<<2), 8, 8, x264_weight_none ); + } + x264_emms(); + return dest; + } + x264_emms(); + return ref->lowres[0]; +} + +/* How data is organized for 4:2:0/4:2:2 chroma weightp: + * [U: ref] [U: fenc] + * [V: ref] [V: fenc] + * fenc = ref + offset + * v = u + stride * chroma height */ + +static NOINLINE void x264_weight_cost_init_chroma( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, pixel *dstu, pixel *dstv ) +{ + int ref0_distance = fenc->i_frame - ref->i_frame - 1; + int i_stride = fenc->i_stride[1]; + int i_offset = i_stride / 2; + int i_lines = fenc->i_lines[1]; + int i_width = fenc->i_width[1]; + int v_shift = CHROMA_V_SHIFT; + int cw = 8*h->mb.i_mb_width; + int ch = 16*h->mb.i_mb_height >> v_shift; + int height = 16 >> v_shift; + + if( fenc->lowres_mvs[0][ref0_distance][0][0] != 0x7FFF ) + { + x264_frame_expand_border_chroma( h, ref, 1 ); + for( int y = 0, mb_xy = 0, pel_offset_y = 0; y < i_lines; y += height, pel_offset_y = y*i_stride ) + for( int x = 0, pel_offset_x = 0; x < i_width; x += 8, mb_xy++, pel_offset_x += 8 ) + { + pixel *pixu = dstu + pel_offset_y + pel_offset_x; + pixel *pixv = dstv + pel_offset_y + pel_offset_x; + pixel *src1 = ref->plane[1] + pel_offset_y + pel_offset_x*2; /* NV12/NV16 */ + int mvx = fenc->lowres_mvs[0][ref0_distance][mb_xy][0]; + int mvy = fenc->lowres_mvs[0][ref0_distance][mb_xy][1]; + h->mc.mc_chroma( pixu, pixv, i_stride, src1, i_stride, mvx, 2*mvy>>v_shift, 8, height ); + } + } + else + h->mc.plane_copy_deinterleave( dstu, i_stride, dstv, i_stride, ref->plane[1], i_stride, cw, ch ); + h->mc.plane_copy_deinterleave( dstu+i_offset, i_stride, dstv+i_offset, i_stride, fenc->plane[1], i_stride, cw, ch ); + x264_emms(); +} + +static NOINLINE pixel *x264_weight_cost_init_chroma444( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, pixel *dst, int p ) +{ + int ref0_distance = fenc->i_frame - ref->i_frame - 1; + int i_stride = fenc->i_stride[p]; + int i_lines = fenc->i_lines[p]; + int i_width = fenc->i_width[p]; + + if( fenc->lowres_mvs[0][ref0_distance][0][0] != 0x7FFF ) + { + x264_frame_expand_border_chroma( h, ref, p ); + for( int y = 0, mb_xy = 0, pel_offset_y = 0; y < i_lines; y += 16, pel_offset_y = y*i_stride ) + for( int x = 0, pel_offset_x = 0; x < i_width; x += 16, mb_xy++, pel_offset_x += 16 ) + { + pixel *pix = dst + pel_offset_y + pel_offset_x; + pixel *src = ref->plane[p] + pel_offset_y + pel_offset_x; + int mvx = fenc->lowres_mvs[0][ref0_distance][mb_xy][0] / 2; + int mvy = fenc->lowres_mvs[0][ref0_distance][mb_xy][1] / 2; + /* We don't want to calculate hpels for fenc frames, so we round the motion + * vectors to fullpel here. It's not too bad, I guess? */ + h->mc.copy_16x16_unaligned( pix, i_stride, src+mvx+mvy*i_stride, i_stride, 16 ); + } + x264_emms(); + return dst; + } + x264_emms(); + return ref->plane[p]; +} + +static int x264_weight_slice_header_cost( x264_t *h, x264_weight_t *w, int b_chroma ) +{ + /* Add cost of weights in the slice header. */ + int lambda = x264_lambda_tab[X264_LOOKAHEAD_QP]; + /* 4 times higher, because chroma is analyzed at full resolution. */ + if( b_chroma ) + lambda *= 4; + int numslices; + if( h->param.i_slice_count ) + numslices = h->param.i_slice_count; + else if( h->param.i_slice_max_mbs ) + numslices = (h->mb.i_mb_width * h->mb.i_mb_height + h->param.i_slice_max_mbs-1) / h->param.i_slice_max_mbs; + else + numslices = 1; + /* FIXME: find a way to account for --slice-max-size? + * Multiply by 2 as there will be a duplicate. 10 bits added as if there is a weighted frame, then an additional duplicate is used. + * Cut denom cost in half if chroma, since it's shared between the two chroma planes. */ + int denom_cost = bs_size_ue( w[0].i_denom ) * (2 - b_chroma); + return lambda * numslices * ( 10 + denom_cost + 2 * (bs_size_se( w[0].i_scale ) + bs_size_se( w[0].i_offset )) ); +} + +static NOINLINE unsigned int x264_weight_cost_luma( x264_t *h, x264_frame_t *fenc, pixel *src, x264_weight_t *w ) +{ + unsigned int cost = 0; + int i_stride = fenc->i_stride_lowres; + int i_lines = fenc->i_lines_lowres; + int i_width = fenc->i_width_lowres; + pixel *fenc_plane = fenc->lowres[0]; + ALIGNED_ARRAY_16( pixel, buf,[8*8] ); + int pixoff = 0; + int i_mb = 0; + + if( w ) + { + for( int y = 0; y < i_lines; y += 8, pixoff = y*i_stride ) + for( int x = 0; x < i_width; x += 8, i_mb++, pixoff += 8) + { + w->weightfn[8>>2]( buf, 8, &src[pixoff], i_stride, w, 8 ); + int cmp = h->pixf.mbcmp[PIXEL_8x8]( buf, 8, &fenc_plane[pixoff], i_stride ); + cost += X264_MIN( cmp, fenc->i_intra_cost[i_mb] ); + } + cost += x264_weight_slice_header_cost( h, w, 0 ); + } + else + for( int y = 0; y < i_lines; y += 8, pixoff = y*i_stride ) + for( int x = 0; x < i_width; x += 8, i_mb++, pixoff += 8 ) + { + int cmp = h->pixf.mbcmp[PIXEL_8x8]( &src[pixoff], i_stride, &fenc_plane[pixoff], i_stride ); + cost += X264_MIN( cmp, fenc->i_intra_cost[i_mb] ); + } + x264_emms(); + return cost; +} + +static NOINLINE unsigned int x264_weight_cost_chroma( x264_t *h, x264_frame_t *fenc, pixel *ref, x264_weight_t *w ) +{ + unsigned int cost = 0; + int i_stride = fenc->i_stride[1]; + int i_lines = fenc->i_lines[1]; + int i_width = fenc->i_width[1]; + pixel *src = ref + (i_stride >> 1); + ALIGNED_ARRAY_16( pixel, buf, [8*16] ); + int pixoff = 0; + int height = 16 >> CHROMA_V_SHIFT; + if( w ) + { + for( int y = 0; y < i_lines; y += height, pixoff = y*i_stride ) + for( int x = 0; x < i_width; x += 8, pixoff += 8 ) + { + w->weightfn[8>>2]( buf, 8, &ref[pixoff], i_stride, w, height ); + /* The naive and seemingly sensible algorithm is to use mbcmp as in luma. + * But testing shows that for chroma the DC coefficient is by far the most + * important part of the coding cost. Thus a more useful chroma weight is + * obtained by comparing each block's DC coefficient instead of the actual + * pixels. */ + cost += h->pixf.asd8( buf, 8, &src[pixoff], i_stride, height ); + } + cost += x264_weight_slice_header_cost( h, w, 1 ); + } + else + for( int y = 0; y < i_lines; y += height, pixoff = y*i_stride ) + for( int x = 0; x < i_width; x += 8, pixoff += 8 ) + cost += h->pixf.asd8( &ref[pixoff], i_stride, &src[pixoff], i_stride, height ); + x264_emms(); + return cost; +} + +static NOINLINE unsigned int x264_weight_cost_chroma444( x264_t *h, x264_frame_t *fenc, pixel *ref, x264_weight_t *w, int p ) +{ + unsigned int cost = 0; + int i_stride = fenc->i_stride[p]; + int i_lines = fenc->i_lines[p]; + int i_width = fenc->i_width[p]; + pixel *src = fenc->plane[p]; + ALIGNED_ARRAY_64( pixel, buf, [16*16] ); + int pixoff = 0; + if( w ) + { + for( int y = 0; y < i_lines; y += 16, pixoff = y*i_stride ) + for( int x = 0; x < i_width; x += 16, pixoff += 16 ) + { + w->weightfn[16>>2]( buf, 16, &ref[pixoff], i_stride, w, 16 ); + cost += h->pixf.mbcmp[PIXEL_16x16]( buf, 16, &src[pixoff], i_stride ); + } + cost += x264_weight_slice_header_cost( h, w, 1 ); + } + else + for( int y = 0; y < i_lines; y += 16, pixoff = y*i_stride ) + for( int x = 0; x < i_width; x += 16, pixoff += 16 ) + cost += h->pixf.mbcmp[PIXEL_16x16]( &ref[pixoff], i_stride, &src[pixoff], i_stride ); + x264_emms(); + return cost; +} + +void x264_weights_analyse( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, int b_lookahead ) +{ + int i_delta_index = fenc->i_frame - ref->i_frame - 1; + /* epsilon is chosen to require at least a numerator of 127 (with denominator = 128) */ + const float epsilon = 1.f/128.f; + x264_weight_t *weights = fenc->weight[0]; + SET_WEIGHT( weights[0], 0, 1, 0, 0 ); + SET_WEIGHT( weights[1], 0, 1, 0, 0 ); + SET_WEIGHT( weights[2], 0, 1, 0, 0 ); + int chroma_initted = 0; + float guess_scale[3]; + float fenc_mean[3]; + float ref_mean[3]; + for( int plane = 0; plane <= 2*!b_lookahead; plane++ ) + { + float fenc_var = fenc->i_pixel_ssd[plane] + !ref->i_pixel_ssd[plane]; + float ref_var = ref->i_pixel_ssd[plane] + !ref->i_pixel_ssd[plane]; + guess_scale[plane] = sqrtf( fenc_var / ref_var ); + fenc_mean[plane] = (float)fenc->i_pixel_sum[plane] / (fenc->i_lines[!!plane] * fenc->i_width[!!plane]) / (1 << (BIT_DEPTH - 8)); + ref_mean[plane] = (float) ref->i_pixel_sum[plane] / (fenc->i_lines[!!plane] * fenc->i_width[!!plane]) / (1 << (BIT_DEPTH - 8)); + } + + int chroma_denom = 7; + if( !b_lookahead ) + { + /* make sure both our scale factors fit */ + while( chroma_denom > 0 ) + { + float thresh = 127.f / (1< 127 ) + { + weights[1].weightfn = weights[2].weightfn = NULL; + break; + } + } + else + x264_weight_get_h264( round( guess_scale[plane] * 128 ), 0, &weights[plane] ); + + found = 0; + mindenom = weights[plane].i_denom; + minscale = weights[plane].i_scale; + minoff = 0; + + pixel *mcbuf; + if( !plane ) + { + if( !fenc->b_intra_calculated ) + { + x264_mb_analysis_t a; + x264_lowres_context_init( h, &a ); + x264_slicetype_frame_cost( h, &a, &fenc, 0, 0, 0 ); + } + mcbuf = x264_weight_cost_init_luma( h, fenc, ref, h->mb.p_weight_buf[0] ); + origscore = minscore = x264_weight_cost_luma( h, fenc, mcbuf, NULL ); + } + else + { + if( CHROMA444 ) + { + mcbuf = x264_weight_cost_init_chroma444( h, fenc, ref, h->mb.p_weight_buf[0], plane ); + origscore = minscore = x264_weight_cost_chroma444( h, fenc, mcbuf, NULL, plane ); + } + else + { + pixel *dstu = h->mb.p_weight_buf[0]; + pixel *dstv = h->mb.p_weight_buf[0]+fenc->i_stride[1]*fenc->i_lines[1]; + if( !chroma_initted++ ) + x264_weight_cost_init_chroma( h, fenc, ref, dstu, dstv ); + mcbuf = plane == 1 ? dstu : dstv; + origscore = minscore = x264_weight_cost_chroma( h, fenc, mcbuf, NULL ); + } + } + + if( !minscore ) + continue; + + /* Picked somewhat arbitrarily */ + static const uint8_t weight_check_distance[][2] = + { + {0,0},{0,0},{0,1},{0,1}, + {0,1},{0,1},{0,1},{1,1}, + {1,1},{2,1},{2,1},{4,2} + }; + int scale_dist = b_lookahead ? 0 : weight_check_distance[h->param.analyse.i_subpel_refine][0]; + int offset_dist = b_lookahead ? 0 : weight_check_distance[h->param.analyse.i_subpel_refine][1]; + + int start_scale = x264_clip3( minscale - scale_dist, 0, 127 ); + int end_scale = x264_clip3( minscale + scale_dist, 0, 127 ); + for( int i_scale = start_scale; i_scale <= end_scale; i_scale++ ) + { + int cur_scale = i_scale; + int cur_offset = fenc_mean[plane] - ref_mean[plane] * cur_scale / (1 << mindenom) + 0.5f * b_lookahead; + if( cur_offset < - 128 || cur_offset > 127 ) + { + /* Rescale considering the constraints on cur_offset. We do it in this order + * because scale has a much wider range than offset (because of denom), so + * it should almost never need to be clamped. */ + cur_offset = x264_clip3( cur_offset, -128, 127 ); + cur_scale = (1 << mindenom) * (fenc_mean[plane] - cur_offset) / ref_mean[plane] + 0.5f; + cur_scale = x264_clip3( cur_scale, 0, 127 ); + } + int start_offset = x264_clip3( cur_offset - offset_dist, -128, 127 ); + int end_offset = x264_clip3( cur_offset + offset_dist, -128, 127 ); + for( int i_off = start_offset; i_off <= end_offset; i_off++ ) + { + SET_WEIGHT( weights[plane], 1, cur_scale, mindenom, i_off ); + unsigned int s; + if( plane ) + { + if( CHROMA444 ) + s = x264_weight_cost_chroma444( h, fenc, mcbuf, &weights[plane], plane ); + else + s = x264_weight_cost_chroma( h, fenc, mcbuf, &weights[plane] ); + } + else + s = x264_weight_cost_luma( h, fenc, mcbuf, &weights[plane] ); + COPY4_IF_LT( minscore, s, minscale, cur_scale, minoff, i_off, found, 1 ); + + // Don't check any more offsets if the previous one had a lower cost than the current one + if( minoff == start_offset && i_off != start_offset ) + break; + } + } + x264_emms(); + + /* Use a smaller denominator if possible */ + if( !plane ) + { + while( mindenom > 0 && !(minscale&1) ) + { + mindenom--; + minscale >>= 1; + } + } + + /* FIXME: More analysis can be done here on SAD vs. SATD termination. */ + /* 0.2% termination derived experimentally to avoid weird weights in frames that are mostly intra. */ + if( !found || (minscale == 1 << mindenom && minoff == 0) || (float)minscore / origscore > 0.998f ) + { + SET_WEIGHT( weights[plane], 0, 1, 0, 0 ); + continue; + } + else + SET_WEIGHT( weights[plane], 1, minscale, mindenom, minoff ); + + if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_FAKE && weights[0].weightfn && !plane ) + fenc->f_weighted_cost_delta[i_delta_index] = (float)minscore / origscore; + } + + /* Optimize and unify denominator */ + if( weights[1].weightfn || weights[2].weightfn ) + { + int denom = weights[1].weightfn ? weights[1].i_denom : weights[2].i_denom; + int both_weighted = weights[1].weightfn && weights[2].weightfn; + /* If only one plane is weighted, the other has an implicit scale of 1< 0 && !(weights[1].weightfn && (weights[1].i_scale&1)) + && !(weights[2].weightfn && (weights[2].i_scale&1))) ) + { + denom--; + for( int i = 1; i <= 2; i++ ) + if( weights[i].weightfn ) + { + weights[i].i_scale >>= 1; + weights[i].i_denom = denom; + } + } + } + for( int i = 1; i <= 2; i++ ) + if( weights[i].weightfn ) + h->mc.weight_cache( h, &weights[i] ); + + if( weights[0].weightfn && b_lookahead ) + { + //scale lowres in lookahead for slicetype_frame_cost + pixel *src = ref->buffer_lowres[0]; + pixel *dst = h->mb.p_weight_buf[0]; + int width = ref->i_width_lowres + PADH*2; + int height = ref->i_lines_lowres + PADV*2; + x264_weight_scale_plane( h, dst, ref->i_stride_lowres, src, ref->i_stride_lowres, + width, height, &weights[0] ); + fenc->weighted[0] = h->mb.p_weight_buf[0] + PADH + ref->i_stride_lowres * PADV; + } +} + +/* Output buffers are separated by 128 bytes to avoid false sharing of cachelines + * in multithreaded lookahead. */ +#define PAD_SIZE 32 +/* cost_est, cost_est_aq, intra_mbs, num rows */ +#define NUM_INTS 4 +#define COST_EST 0 +#define COST_EST_AQ 1 +#define INTRA_MBS 2 +#define NUM_ROWS 3 +#define ROW_SATD (NUM_INTS + (h->mb.i_mb_y - h->i_threadslice_start)) + +static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, + x264_frame_t **frames, int p0, int p1, int b, + int dist_scale_factor, int do_search[2], const x264_weight_t *w, + int *output_inter, int *output_intra ) +{ + x264_frame_t *fref0 = frames[p0]; + x264_frame_t *fref1 = frames[p1]; + x264_frame_t *fenc = frames[b]; + const int b_bidir = (b < p1); + const int i_mb_x = h->mb.i_mb_x; + const int i_mb_y = h->mb.i_mb_y; + const int i_mb_stride = h->mb.i_mb_width; + const int i_mb_xy = i_mb_x + i_mb_y * i_mb_stride; + const int i_stride = fenc->i_stride_lowres; + const int i_pel_offset = 8 * (i_mb_x + i_mb_y * i_stride); + const int i_bipred_weight = h->param.analyse.b_weighted_bipred ? 64 - (dist_scale_factor>>2) : 32; + int16_t (*fenc_mvs[2])[2] = { &fenc->lowres_mvs[0][b-p0-1][i_mb_xy], &fenc->lowres_mvs[1][p1-b-1][i_mb_xy] }; + int (*fenc_costs[2]) = { &fenc->lowres_mv_costs[0][b-p0-1][i_mb_xy], &fenc->lowres_mv_costs[1][p1-b-1][i_mb_xy] }; + int b_frame_score_mb = (i_mb_x > 0 && i_mb_x < h->mb.i_mb_width - 1 && + i_mb_y > 0 && i_mb_y < h->mb.i_mb_height - 1) || + h->mb.i_mb_width <= 2 || h->mb.i_mb_height <= 2; + + ALIGNED_ARRAY_16( pixel, pix1,[9*FDEC_STRIDE] ); + pixel *pix2 = pix1+8; + x264_me_t m[2]; + int i_bcost = COST_MAX; + int list_used = 0; + /* A small, arbitrary bias to avoid VBV problems caused by zero-residual lookahead blocks. */ + int lowres_penalty = 4; + + h->mb.pic.p_fenc[0] = h->mb.pic.fenc_buf; + h->mc.copy[PIXEL_8x8]( h->mb.pic.p_fenc[0], FENC_STRIDE, &fenc->lowres[0][i_pel_offset], i_stride, 8 ); + + if( p0 == p1 ) + goto lowres_intra_mb; + + int mv_range = 2 * h->param.analyse.i_mv_range; + // no need for h->mb.mv_min[] + h->mb.mv_min_spel[0] = X264_MAX( 4*(-8*h->mb.i_mb_x - 12), -mv_range ); + h->mb.mv_max_spel[0] = X264_MIN( 4*(8*(h->mb.i_mb_width - h->mb.i_mb_x - 1) + 12), mv_range-1 ); + h->mb.mv_limit_fpel[0][0] = h->mb.mv_min_spel[0] >> 2; + h->mb.mv_limit_fpel[1][0] = h->mb.mv_max_spel[0] >> 2; + if( h->mb.i_mb_x >= h->mb.i_mb_width - 2 ) + { + h->mb.mv_min_spel[1] = X264_MAX( 4*(-8*h->mb.i_mb_y - 12), -mv_range ); + h->mb.mv_max_spel[1] = X264_MIN( 4*(8*( h->mb.i_mb_height - h->mb.i_mb_y - 1) + 12), mv_range-1 ); + h->mb.mv_limit_fpel[0][1] = h->mb.mv_min_spel[1] >> 2; + h->mb.mv_limit_fpel[1][1] = h->mb.mv_max_spel[1] >> 2; + } + +#define LOAD_HPELS_LUMA(dst, src) \ + { \ + (dst)[0] = &(src)[0][i_pel_offset]; \ + (dst)[1] = &(src)[1][i_pel_offset]; \ + (dst)[2] = &(src)[2][i_pel_offset]; \ + (dst)[3] = &(src)[3][i_pel_offset]; \ + } +#define LOAD_WPELS_LUMA(dst,src) \ + (dst) = &(src)[i_pel_offset]; + +#define CLIP_MV( mv ) \ + { \ + mv[0] = x264_clip3( mv[0], h->mb.mv_min_spel[0], h->mb.mv_max_spel[0] ); \ + mv[1] = x264_clip3( mv[1], h->mb.mv_min_spel[1], h->mb.mv_max_spel[1] ); \ + } +#define TRY_BIDIR( mv0, mv1, penalty ) \ + { \ + int i_cost; \ + if( h->param.analyse.i_subpel_refine <= 1 ) \ + { \ + int hpel_idx1 = (((mv0)[0]&2)>>1) + ((mv0)[1]&2); \ + int hpel_idx2 = (((mv1)[0]&2)>>1) + ((mv1)[1]&2); \ + pixel *src1 = m[0].p_fref[hpel_idx1] + ((mv0)[0]>>2) + ((mv0)[1]>>2) * m[0].i_stride[0]; \ + pixel *src2 = m[1].p_fref[hpel_idx2] + ((mv1)[0]>>2) + ((mv1)[1]>>2) * m[1].i_stride[0]; \ + h->mc.avg[PIXEL_8x8]( pix1, 16, src1, m[0].i_stride[0], src2, m[1].i_stride[0], i_bipred_weight ); \ + } \ + else \ + { \ + intptr_t stride1 = 16, stride2 = 16; \ + pixel *src1, *src2; \ + src1 = h->mc.get_ref( pix1, &stride1, m[0].p_fref, m[0].i_stride[0], \ + (mv0)[0], (mv0)[1], 8, 8, w ); \ + src2 = h->mc.get_ref( pix2, &stride2, m[1].p_fref, m[1].i_stride[0], \ + (mv1)[0], (mv1)[1], 8, 8, w ); \ + h->mc.avg[PIXEL_8x8]( pix1, 16, src1, stride1, src2, stride2, i_bipred_weight ); \ + } \ + i_cost = penalty * a->i_lambda + h->pixf.mbcmp[PIXEL_8x8]( \ + m[0].p_fenc[0], FENC_STRIDE, pix1, 16 ); \ + COPY2_IF_LT( i_bcost, i_cost, list_used, 3 ); \ + } + + m[0].i_pixel = PIXEL_8x8; + m[0].p_cost_mv = a->p_cost_mv; + m[0].i_stride[0] = i_stride; + m[0].p_fenc[0] = h->mb.pic.p_fenc[0]; + m[0].weight = w; + m[0].i_ref = 0; + LOAD_HPELS_LUMA( m[0].p_fref, fref0->lowres ); + m[0].p_fref_w = m[0].p_fref[0]; + if( w[0].weightfn ) + LOAD_WPELS_LUMA( m[0].p_fref_w, fenc->weighted[0] ); + + if( b_bidir ) + { + ALIGNED_ARRAY_8( int16_t, dmv,[2],[2] ); + + m[1].i_pixel = PIXEL_8x8; + m[1].p_cost_mv = a->p_cost_mv; + m[1].i_stride[0] = i_stride; + m[1].p_fenc[0] = h->mb.pic.p_fenc[0]; + m[1].i_ref = 0; + m[1].weight = x264_weight_none; + LOAD_HPELS_LUMA( m[1].p_fref, fref1->lowres ); + m[1].p_fref_w = m[1].p_fref[0]; + + if( fref1->lowres_mvs[0][p1-p0-1][0][0] != 0x7FFF ) + { + int16_t *mvr = fref1->lowres_mvs[0][p1-p0-1][i_mb_xy]; + dmv[0][0] = ( mvr[0] * dist_scale_factor + 128 ) >> 8; + dmv[0][1] = ( mvr[1] * dist_scale_factor + 128 ) >> 8; + dmv[1][0] = dmv[0][0] - mvr[0]; + dmv[1][1] = dmv[0][1] - mvr[1]; + CLIP_MV( dmv[0] ); + CLIP_MV( dmv[1] ); + if( h->param.analyse.i_subpel_refine <= 1 ) + M64( dmv ) &= ~0x0001000100010001ULL; /* mv & ~1 */ + } + else + M64( dmv ) = 0; + + TRY_BIDIR( dmv[0], dmv[1], 0 ); + if( M64( dmv ) ) + { + int i_cost; + h->mc.avg[PIXEL_8x8]( pix1, 16, m[0].p_fref[0], m[0].i_stride[0], m[1].p_fref[0], m[1].i_stride[0], i_bipred_weight ); + i_cost = h->pixf.mbcmp[PIXEL_8x8]( m[0].p_fenc[0], FENC_STRIDE, pix1, 16 ); + COPY2_IF_LT( i_bcost, i_cost, list_used, 3 ); + } + } + + for( int l = 0; l < 1 + b_bidir; l++ ) + { + if( do_search[l] ) + { + int i_mvc = 0; + int16_t (*fenc_mv)[2] = fenc_mvs[l]; + ALIGNED_4( int16_t mvc[4][2] ); + + /* Reverse-order MV prediction. */ + M32( mvc[0] ) = 0; + M32( mvc[2] ) = 0; +#define MVC(mv) { CP32( mvc[i_mvc], mv ); i_mvc++; } + if( i_mb_x < h->mb.i_mb_width - 1 ) + MVC( fenc_mv[1] ); + if( i_mb_y < h->i_threadslice_end - 1 ) + { + MVC( fenc_mv[i_mb_stride] ); + if( i_mb_x > 0 ) + MVC( fenc_mv[i_mb_stride-1] ); + if( i_mb_x < h->mb.i_mb_width - 1 ) + MVC( fenc_mv[i_mb_stride+1] ); + } +#undef MVC + if( i_mvc <= 1 ) + CP32( m[l].mvp, mvc[0] ); + else + x264_median_mv( m[l].mvp, mvc[0], mvc[1], mvc[2] ); + + /* Fast skip for cases of near-zero residual. Shortcut: don't bother except in the mv0 case, + * since anything else is likely to have enough residual to not trigger the skip. */ + if( !M32( m[l].mvp ) ) + { + m[l].cost = h->pixf.mbcmp[PIXEL_8x8]( m[l].p_fenc[0], FENC_STRIDE, m[l].p_fref[0], m[l].i_stride[0] ); + if( m[l].cost < 64 ) + { + M32( m[l].mv ) = 0; + goto skip_motionest; + } + } + + x264_me_search( h, &m[l], mvc, i_mvc ); + m[l].cost -= a->p_cost_mv[0]; // remove mvcost from skip mbs + if( M32( m[l].mv ) ) + m[l].cost += 5 * a->i_lambda; + +skip_motionest: + CP32( fenc_mvs[l], m[l].mv ); + *fenc_costs[l] = m[l].cost; + } + else + { + CP32( m[l].mv, fenc_mvs[l] ); + m[l].cost = *fenc_costs[l]; + } + COPY2_IF_LT( i_bcost, m[l].cost, list_used, l+1 ); + } + + if( b_bidir && ( M32( m[0].mv ) || M32( m[1].mv ) ) ) + TRY_BIDIR( m[0].mv, m[1].mv, 5 ); + +lowres_intra_mb: + if( !fenc->b_intra_calculated ) + { + ALIGNED_ARRAY_16( pixel, edge,[36] ); + pixel *pix = &pix1[8+FDEC_STRIDE]; + pixel *src = &fenc->lowres[0][i_pel_offset]; + const int intra_penalty = 5 * a->i_lambda; + int satds[3]; + int pixoff = 4 / sizeof(pixel); + + /* Avoid store forwarding stalls by writing larger chunks */ + memcpy( pix-FDEC_STRIDE, src-i_stride, 16 * sizeof(pixel) ); + for( int i = -1; i < 8; i++ ) + M32( &pix[i*FDEC_STRIDE-pixoff] ) = M32( &src[i*i_stride-pixoff] ); + + h->pixf.intra_mbcmp_x3_8x8c( h->mb.pic.p_fenc[0], pix, satds ); + int i_icost = X264_MIN3( satds[0], satds[1], satds[2] ); + + if( h->param.analyse.i_subpel_refine > 1 ) + { + h->predict_8x8c[I_PRED_CHROMA_P]( pix ); + int satd = h->pixf.mbcmp[PIXEL_8x8]( h->mb.pic.p_fenc[0], FENC_STRIDE, pix, FDEC_STRIDE ); + i_icost = X264_MIN( i_icost, satd ); + h->predict_8x8_filter( pix, edge, ALL_NEIGHBORS, ALL_NEIGHBORS ); + for( int i = 3; i < 9; i++ ) + { + h->predict_8x8[i]( pix, edge ); + satd = h->pixf.mbcmp[PIXEL_8x8]( h->mb.pic.p_fenc[0], FENC_STRIDE, pix, FDEC_STRIDE ); + i_icost = X264_MIN( i_icost, satd ); + } + } + + i_icost = ((i_icost + intra_penalty) >> (BIT_DEPTH - 8)) + lowres_penalty; + fenc->i_intra_cost[i_mb_xy] = i_icost; + int i_icost_aq = i_icost; + if( h->param.rc.i_aq_mode ) + i_icost_aq = (i_icost_aq * fenc->i_inv_qscale_factor[i_mb_xy] + 128) >> 8; + output_intra[ROW_SATD] += i_icost_aq; + if( b_frame_score_mb ) + { + output_intra[COST_EST] += i_icost; + output_intra[COST_EST_AQ] += i_icost_aq; + } + } + i_bcost = (i_bcost >> (BIT_DEPTH - 8)) + lowres_penalty; + + /* forbid intra-mbs in B-frames, because it's rare and not worth checking */ + /* FIXME: Should we still forbid them now that we cache intra scores? */ + if( !b_bidir ) + { + int i_icost = fenc->i_intra_cost[i_mb_xy]; + int b_intra = i_icost < i_bcost; + if( b_intra ) + { + i_bcost = i_icost; + list_used = 0; + } + if( b_frame_score_mb ) + output_inter[INTRA_MBS] += b_intra; + } + + /* In an I-frame, we've already added the results above in the intra section. */ + if( p0 != p1 ) + { + int i_bcost_aq = i_bcost; + if( h->param.rc.i_aq_mode ) + i_bcost_aq = (i_bcost_aq * fenc->i_inv_qscale_factor[i_mb_xy] + 128) >> 8; + output_inter[ROW_SATD] += i_bcost_aq; + if( b_frame_score_mb ) + { + /* Don't use AQ-weighted costs for slicetype decision, only for ratecontrol. */ + output_inter[COST_EST] += i_bcost; + output_inter[COST_EST_AQ] += i_bcost_aq; + } + } + + fenc->lowres_costs[b-p0][p1-b][i_mb_xy] = X264_MIN( i_bcost, LOWRES_COST_MASK ) + (list_used << LOWRES_COST_SHIFT); +} +#undef TRY_BIDIR + +#define NUM_MBS\ + (h->mb.i_mb_width > 2 && h->mb.i_mb_height > 2 ?\ + (h->mb.i_mb_width - 2) * (h->mb.i_mb_height - 2) :\ + h->mb.i_mb_width * h->mb.i_mb_height) + +typedef struct +{ + x264_t *h; + x264_mb_analysis_t *a; + x264_frame_t **frames; + int p0; + int p1; + int b; + int dist_scale_factor; + int *do_search; + const x264_weight_t *w; + int *output_inter; + int *output_intra; +} x264_slicetype_slice_t; + +static void x264_slicetype_slice_cost( x264_slicetype_slice_t *s ) +{ + x264_t *h = s->h; + + /* Lowres lookahead goes backwards because the MVs are used as predictors in the main encode. + * This considerably improves MV prediction overall. */ + + /* The edge mbs seem to reduce the predictive quality of the + * whole frame's score, but are needed for a spatial distribution. */ + int do_edges = h->param.rc.b_mb_tree || h->param.rc.i_vbv_buffer_size || h->mb.i_mb_width <= 2 || h->mb.i_mb_height <= 2; + + int start_y = X264_MIN( h->i_threadslice_end - 1, h->mb.i_mb_height - 2 + do_edges ); + int end_y = X264_MAX( h->i_threadslice_start, 1 - do_edges ); + int start_x = h->mb.i_mb_width - 2 + do_edges; + int end_x = 1 - do_edges; + + for( h->mb.i_mb_y = start_y; h->mb.i_mb_y >= end_y; h->mb.i_mb_y-- ) + for( h->mb.i_mb_x = start_x; h->mb.i_mb_x >= end_x; h->mb.i_mb_x-- ) + x264_slicetype_mb_cost( h, s->a, s->frames, s->p0, s->p1, s->b, s->dist_scale_factor, + s->do_search, s->w, s->output_inter, s->output_intra ); +} + +static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, + x264_frame_t **frames, int p0, int p1, int b ) +{ + int i_score = 0; + int do_search[2]; + const x264_weight_t *w = x264_weight_none; + x264_frame_t *fenc = frames[b]; + + /* Check whether we already evaluated this frame + * If we have tried this frame as P, then we have also tried + * the preceding frames as B. (is this still true?) */ + /* Also check that we already calculated the row SATDs for the current frame. */ + if( fenc->i_cost_est[b-p0][p1-b] >= 0 && (!h->param.rc.i_vbv_buffer_size || fenc->i_row_satds[b-p0][p1-b][0] != -1) ) + i_score = fenc->i_cost_est[b-p0][p1-b]; + else + { + int dist_scale_factor = 128; + + /* For each list, check to see whether we have lowres motion-searched this reference frame before. */ + do_search[0] = b != p0 && fenc->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF; + do_search[1] = b != p1 && fenc->lowres_mvs[1][p1-b-1][0][0] == 0x7FFF; + if( do_search[0] ) + { + if( h->param.analyse.i_weighted_pred && b == p1 ) + { + x264_emms(); + x264_weights_analyse( h, fenc, frames[p0], 1 ); + w = fenc->weight[0]; + } + fenc->lowres_mvs[0][b-p0-1][0][0] = 0; + } + if( do_search[1] ) fenc->lowres_mvs[1][p1-b-1][0][0] = 0; + + if( p1 != p0 ) + dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0); + + int output_buf_size = h->mb.i_mb_height + (NUM_INTS + PAD_SIZE) * h->param.i_lookahead_threads; + int *output_inter[X264_LOOKAHEAD_THREAD_MAX+1]; + int *output_intra[X264_LOOKAHEAD_THREAD_MAX+1]; + output_inter[0] = h->scratch_buffer2; + output_intra[0] = output_inter[0] + output_buf_size; + +#if HAVE_OPENCL + if( h->param.b_opencl ) + { + x264_opencl_lowres_init(h, fenc, a->i_lambda ); + if( do_search[0] ) + { + x264_opencl_lowres_init( h, frames[p0], a->i_lambda ); + x264_opencl_motionsearch( h, frames, b, p0, 0, a->i_lambda, w ); + } + if( do_search[1] ) + { + x264_opencl_lowres_init( h, frames[p1], a->i_lambda ); + x264_opencl_motionsearch( h, frames, b, p1, 1, a->i_lambda, NULL ); + } + if( b != p0 ) + x264_opencl_finalize_cost( h, a->i_lambda, frames, p0, p1, b, dist_scale_factor ); + x264_opencl_flush( h ); + + i_score = fenc->i_cost_est[b-p0][p1-b]; + } + else +#endif + { + if( h->param.i_lookahead_threads > 1 ) + { + x264_slicetype_slice_t s[X264_LOOKAHEAD_THREAD_MAX]; + + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) + { + x264_t *t = h->lookahead_thread[i]; + + /* FIXME move this somewhere else */ + t->mb.i_me_method = h->mb.i_me_method; + t->mb.i_subpel_refine = h->mb.i_subpel_refine; + t->mb.b_chroma_me = h->mb.b_chroma_me; + + s[i] = (x264_slicetype_slice_t){ t, a, frames, p0, p1, b, dist_scale_factor, do_search, w, + output_inter[i], output_intra[i] }; + + t->i_threadslice_start = ((h->mb.i_mb_height * i + h->param.i_lookahead_threads/2) / h->param.i_lookahead_threads); + t->i_threadslice_end = ((h->mb.i_mb_height * (i+1) + h->param.i_lookahead_threads/2) / h->param.i_lookahead_threads); + + int thread_height = t->i_threadslice_end - t->i_threadslice_start; + int thread_output_size = thread_height + NUM_INTS; + memset( output_inter[i], 0, thread_output_size * sizeof(int) ); + memset( output_intra[i], 0, thread_output_size * sizeof(int) ); + output_inter[i][NUM_ROWS] = output_intra[i][NUM_ROWS] = thread_height; + + output_inter[i+1] = output_inter[i] + thread_output_size + PAD_SIZE; + output_intra[i+1] = output_intra[i] + thread_output_size + PAD_SIZE; + + x264_threadpool_run( h->lookaheadpool, (void*)x264_slicetype_slice_cost, &s[i] ); + } + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) + x264_threadpool_wait( h->lookaheadpool, &s[i] ); + } + else + { + h->i_threadslice_start = 0; + h->i_threadslice_end = h->mb.i_mb_height; + memset( output_inter[0], 0, (output_buf_size - PAD_SIZE) * sizeof(int) ); + memset( output_intra[0], 0, (output_buf_size - PAD_SIZE) * sizeof(int) ); + output_inter[0][NUM_ROWS] = output_intra[0][NUM_ROWS] = h->mb.i_mb_height; + x264_slicetype_slice_t s = (x264_slicetype_slice_t){ h, a, frames, p0, p1, b, dist_scale_factor, do_search, w, + output_inter[0], output_intra[0] }; + x264_slicetype_slice_cost( &s ); + } + + /* Sum up accumulators */ + if( b == p1 ) + fenc->i_intra_mbs[b-p0] = 0; + if( !fenc->b_intra_calculated ) + { + fenc->i_cost_est[0][0] = 0; + fenc->i_cost_est_aq[0][0] = 0; + } + fenc->i_cost_est[b-p0][p1-b] = 0; + fenc->i_cost_est_aq[b-p0][p1-b] = 0; + + int *row_satd_inter = fenc->i_row_satds[b-p0][p1-b]; + int *row_satd_intra = fenc->i_row_satds[0][0]; + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) + { + if( b == p1 ) + fenc->i_intra_mbs[b-p0] += output_inter[i][INTRA_MBS]; + if( !fenc->b_intra_calculated ) + { + fenc->i_cost_est[0][0] += output_intra[i][COST_EST]; + fenc->i_cost_est_aq[0][0] += output_intra[i][COST_EST_AQ]; + } + + fenc->i_cost_est[b-p0][p1-b] += output_inter[i][COST_EST]; + fenc->i_cost_est_aq[b-p0][p1-b] += output_inter[i][COST_EST_AQ]; + + if( h->param.rc.i_vbv_buffer_size ) + { + int row_count = output_inter[i][NUM_ROWS]; + memcpy( row_satd_inter, output_inter[i] + NUM_INTS, row_count * sizeof(int) ); + if( !fenc->b_intra_calculated ) + memcpy( row_satd_intra, output_intra[i] + NUM_INTS, row_count * sizeof(int) ); + row_satd_inter += row_count; + row_satd_intra += row_count; + } + } + + i_score = fenc->i_cost_est[b-p0][p1-b]; + if( b != p1 ) + i_score = (uint64_t)i_score * 100 / (120 + h->param.i_bframe_bias); + else + fenc->b_intra_calculated = 1; + + fenc->i_cost_est[b-p0][p1-b] = i_score; + x264_emms(); + } + } + + return i_score; +} + +/* If MB-tree changes the quantizers, we need to recalculate the frame cost without + * re-running lookahead. */ +static int x264_slicetype_frame_cost_recalculate( x264_t *h, x264_frame_t **frames, int p0, int p1, int b ) +{ + int i_score = 0; + int *row_satd = frames[b]->i_row_satds[b-p0][p1-b]; + float *qp_offset = IS_X264_TYPE_B(frames[b]->i_type) ? frames[b]->f_qp_offset_aq : frames[b]->f_qp_offset; + x264_emms(); + for( h->mb.i_mb_y = h->mb.i_mb_height - 1; h->mb.i_mb_y >= 0; h->mb.i_mb_y-- ) + { + row_satd[ h->mb.i_mb_y ] = 0; + for( h->mb.i_mb_x = h->mb.i_mb_width - 1; h->mb.i_mb_x >= 0; h->mb.i_mb_x-- ) + { + int i_mb_xy = h->mb.i_mb_x + h->mb.i_mb_y*h->mb.i_mb_stride; + int i_mb_cost = frames[b]->lowres_costs[b-p0][p1-b][i_mb_xy] & LOWRES_COST_MASK; + float qp_adj = qp_offset[i_mb_xy]; + i_mb_cost = (i_mb_cost * x264_exp2fix8(qp_adj) + 128) >> 8; + row_satd[ h->mb.i_mb_y ] += i_mb_cost; + if( (h->mb.i_mb_y > 0 && h->mb.i_mb_y < h->mb.i_mb_height - 1 && + h->mb.i_mb_x > 0 && h->mb.i_mb_x < h->mb.i_mb_width - 1) || + h->mb.i_mb_width <= 2 || h->mb.i_mb_height <= 2 ) + { + i_score += i_mb_cost; + } + } + } + return i_score; +} + +/* Trade off precision in mbtree for increased range */ +#define MBTREE_PRECISION 0.5f + +static void x264_macroblock_tree_finish( x264_t *h, x264_frame_t *frame, float average_duration, int ref0_distance ) +{ + int fps_factor = round( CLIP_DURATION(average_duration) / CLIP_DURATION(frame->f_duration) * 256 / MBTREE_PRECISION ); + float weightdelta = 0.0; + if( ref0_distance && frame->f_weighted_cost_delta[ref0_distance-1] > 0 ) + weightdelta = (1.0 - frame->f_weighted_cost_delta[ref0_distance-1]); + + /* Allow the strength to be adjusted via qcompress, since the two + * concepts are very similar. */ + float strength = 5.0f * (1.0f - h->param.rc.f_qcompress); + for( int mb_index = 0; mb_index < h->mb.i_mb_count; mb_index++ ) + { + int intra_cost = (frame->i_intra_cost[mb_index] * frame->i_inv_qscale_factor[mb_index] + 128) >> 8; + if( intra_cost ) + { + int propagate_cost = (frame->i_propagate_cost[mb_index] * fps_factor + 128) >> 8; + float log2_ratio = x264_log2(intra_cost + propagate_cost) - x264_log2(intra_cost) + weightdelta; + frame->f_qp_offset[mb_index] = frame->f_qp_offset_aq[mb_index] - strength * log2_ratio; + } + } +} + +static void x264_macroblock_tree_propagate( x264_t *h, x264_frame_t **frames, float average_duration, int p0, int p1, int b, int referenced ) +{ + uint16_t *ref_costs[2] = {frames[p0]->i_propagate_cost,frames[p1]->i_propagate_cost}; + int dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0); + int i_bipred_weight = h->param.analyse.b_weighted_bipred ? 64 - (dist_scale_factor>>2) : 32; + int16_t (*mvs[2])[2] = { frames[b]->lowres_mvs[0][b-p0-1], frames[b]->lowres_mvs[1][p1-b-1] }; + int bipred_weights[2] = {i_bipred_weight, 64 - i_bipred_weight}; + int16_t *buf = h->scratch_buffer; + uint16_t *propagate_cost = frames[b]->i_propagate_cost; + uint16_t *lowres_costs = frames[b]->lowres_costs[b-p0][p1-b]; + + x264_emms(); + float fps_factor = CLIP_DURATION(frames[b]->f_duration) / (CLIP_DURATION(average_duration) * 256.0f) * MBTREE_PRECISION; + + /* For non-reffed frames the source costs are always zero, so just memset one row and re-use it. */ + if( !referenced ) + memset( frames[b]->i_propagate_cost, 0, h->mb.i_mb_width * sizeof(uint16_t) ); + + for( h->mb.i_mb_y = 0; h->mb.i_mb_y < h->mb.i_mb_height; h->mb.i_mb_y++ ) + { + int mb_index = h->mb.i_mb_y*h->mb.i_mb_stride; + h->mc.mbtree_propagate_cost( buf, propagate_cost, + frames[b]->i_intra_cost+mb_index, lowres_costs+mb_index, + frames[b]->i_inv_qscale_factor+mb_index, &fps_factor, h->mb.i_mb_width ); + if( referenced ) + propagate_cost += h->mb.i_mb_width; + + h->mc.mbtree_propagate_list( h, ref_costs[0], &mvs[0][mb_index], buf, &lowres_costs[mb_index], + bipred_weights[0], h->mb.i_mb_y, h->mb.i_mb_width, 0 ); + if( b != p1 ) + { + h->mc.mbtree_propagate_list( h, ref_costs[1], &mvs[1][mb_index], buf, &lowres_costs[mb_index], + bipred_weights[1], h->mb.i_mb_y, h->mb.i_mb_width, 1 ); + } + } + + if( h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead && referenced ) + x264_macroblock_tree_finish( h, frames[b], average_duration, b == p1 ? b - p0 : 0 ); +} + +static void x264_macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int num_frames, int b_intra ) +{ + int idx = !b_intra; + int last_nonb, cur_nonb = 1; + int bframes = 0; + + x264_emms(); + float total_duration = 0.0; + for( int j = 0; j <= num_frames; j++ ) + total_duration += frames[j]->f_duration; + float average_duration = total_duration / (num_frames + 1); + + int i = num_frames; + + if( b_intra ) + x264_slicetype_frame_cost( h, a, frames, 0, 0, 0 ); + + while( i > 0 && IS_X264_TYPE_B( frames[i]->i_type ) ) + i--; + last_nonb = i; + + /* Lookaheadless MB-tree is not a theoretically distinct case; the same extrapolation could + * be applied to the end of a lookahead buffer of any size. However, it's most needed when + * lookahead=0, so that's what's currently implemented. */ + if( !h->param.rc.i_lookahead ) + { + if( b_intra ) + { + memset( frames[0]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); + memcpy( frames[0]->f_qp_offset, frames[0]->f_qp_offset_aq, h->mb.i_mb_count * sizeof(float) ); + return; + } + XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost ); + memset( frames[0]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); + } + else + { + if( last_nonb < idx ) + return; + memset( frames[last_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); + } + + while( i-- > idx ) + { + cur_nonb = i; + while( IS_X264_TYPE_B( frames[cur_nonb]->i_type ) && cur_nonb > 0 ) + cur_nonb--; + if( cur_nonb < idx ) + break; + x264_slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, last_nonb ); + memset( frames[cur_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); + bframes = last_nonb - cur_nonb - 1; + if( h->param.i_bframe_pyramid && bframes > 1 ) + { + int middle = (bframes + 1)/2 + cur_nonb; + x264_slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, middle ); + memset( frames[middle]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); + while( i > cur_nonb ) + { + int p0 = i > middle ? middle : cur_nonb; + int p1 = i < middle ? middle : last_nonb; + if( i != middle ) + { + x264_slicetype_frame_cost( h, a, frames, p0, p1, i ); + x264_macroblock_tree_propagate( h, frames, average_duration, p0, p1, i, 0 ); + } + i--; + } + x264_macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, middle, 1 ); + } + else + { + while( i > cur_nonb ) + { + x264_slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, i ); + x264_macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, i, 0 ); + i--; + } + } + x264_macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, last_nonb, 1 ); + last_nonb = cur_nonb; + } + + if( !h->param.rc.i_lookahead ) + { + x264_slicetype_frame_cost( h, a, frames, 0, last_nonb, last_nonb ); + x264_macroblock_tree_propagate( h, frames, average_duration, 0, last_nonb, last_nonb, 1 ); + XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost ); + } + + x264_macroblock_tree_finish( h, frames[last_nonb], average_duration, last_nonb ); + if( h->param.i_bframe_pyramid && bframes > 1 && !h->param.rc.i_vbv_buffer_size ) + x264_macroblock_tree_finish( h, frames[last_nonb+(bframes+1)/2], average_duration, 0 ); +} + +static int x264_vbv_frame_cost( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int b ) +{ + int cost = x264_slicetype_frame_cost( h, a, frames, p0, p1, b ); + if( h->param.rc.i_aq_mode ) + { + if( h->param.rc.b_mb_tree ) + return x264_slicetype_frame_cost_recalculate( h, frames, p0, p1, b ); + else + return frames[b]->i_cost_est_aq[b-p0][p1-b]; + } + return cost; +} + +static void x264_calculate_durations( x264_t *h, x264_frame_t *cur_frame, x264_frame_t *prev_frame, int64_t *i_cpb_delay, int64_t *i_coded_fields ) +{ + cur_frame->i_cpb_delay = *i_cpb_delay; + cur_frame->i_dpb_output_delay = cur_frame->i_field_cnt - *i_coded_fields; + + // add a correction term for frame reordering + cur_frame->i_dpb_output_delay += h->sps->vui.i_num_reorder_frames*2; + + // fix possible negative dpb_output_delay because of pulldown changes and reordering + if( cur_frame->i_dpb_output_delay < 0 ) + { + cur_frame->i_cpb_delay += cur_frame->i_dpb_output_delay; + cur_frame->i_dpb_output_delay = 0; + if( prev_frame ) + prev_frame->i_cpb_duration += cur_frame->i_dpb_output_delay; + } + + // don't reset cpb delay for IDR frames when using intra-refresh + if( cur_frame->b_keyframe && !h->param.b_intra_refresh ) + *i_cpb_delay = 0; + + *i_cpb_delay += cur_frame->i_duration; + *i_coded_fields += cur_frame->i_duration; + cur_frame->i_cpb_duration = cur_frame->i_duration; +} + +static void x264_vbv_lookahead( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int num_frames, int keyframe ) +{ + int last_nonb = 0, cur_nonb = 1, idx = 0; + x264_frame_t *prev_frame = NULL; + int prev_frame_idx = 0; + while( cur_nonb < num_frames && IS_X264_TYPE_B( frames[cur_nonb]->i_type ) ) + cur_nonb++; + int next_nonb = keyframe ? last_nonb : cur_nonb; + + if( frames[cur_nonb]->i_coded_fields_lookahead >= 0 ) + { + h->i_coded_fields_lookahead = frames[cur_nonb]->i_coded_fields_lookahead; + h->i_cpb_delay_lookahead = frames[cur_nonb]->i_cpb_delay_lookahead; + } + + while( cur_nonb < num_frames ) + { + /* P/I cost: This shouldn't include the cost of next_nonb */ + if( next_nonb != cur_nonb ) + { + int p0 = IS_X264_TYPE_I( frames[cur_nonb]->i_type ) ? cur_nonb : last_nonb; + frames[next_nonb]->i_planned_satd[idx] = x264_vbv_frame_cost( h, a, frames, p0, cur_nonb, cur_nonb ); + frames[next_nonb]->i_planned_type[idx] = frames[cur_nonb]->i_type; + frames[cur_nonb]->i_coded_fields_lookahead = h->i_coded_fields_lookahead; + frames[cur_nonb]->i_cpb_delay_lookahead = h->i_cpb_delay_lookahead; + x264_calculate_durations( h, frames[cur_nonb], prev_frame, &h->i_cpb_delay_lookahead, &h->i_coded_fields_lookahead ); + if( prev_frame ) + { + frames[next_nonb]->f_planned_cpb_duration[prev_frame_idx] = (double)prev_frame->i_cpb_duration * + h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + } + frames[next_nonb]->f_planned_cpb_duration[idx] = (double)frames[cur_nonb]->i_cpb_duration * + h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + prev_frame = frames[cur_nonb]; + prev_frame_idx = idx; + idx++; + } + /* Handle the B-frames: coded order */ + for( int i = last_nonb+1; i < cur_nonb; i++, idx++ ) + { + frames[next_nonb]->i_planned_satd[idx] = x264_vbv_frame_cost( h, a, frames, last_nonb, cur_nonb, i ); + frames[next_nonb]->i_planned_type[idx] = X264_TYPE_B; + frames[i]->i_coded_fields_lookahead = h->i_coded_fields_lookahead; + frames[i]->i_cpb_delay_lookahead = h->i_cpb_delay_lookahead; + x264_calculate_durations( h, frames[i], prev_frame, &h->i_cpb_delay_lookahead, &h->i_coded_fields_lookahead ); + if( prev_frame ) + { + frames[next_nonb]->f_planned_cpb_duration[prev_frame_idx] = (double)prev_frame->i_cpb_duration * + h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + } + frames[next_nonb]->f_planned_cpb_duration[idx] = (double)frames[i]->i_cpb_duration * + h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + prev_frame = frames[i]; + prev_frame_idx = idx; + } + last_nonb = cur_nonb; + cur_nonb++; + while( cur_nonb <= num_frames && IS_X264_TYPE_B( frames[cur_nonb]->i_type ) ) + cur_nonb++; + } + frames[next_nonb]->i_planned_type[idx] = X264_TYPE_AUTO; +} + +static int x264_slicetype_path_cost( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, char *path, int threshold ) +{ + int loc = 1; + int cost = 0; + int cur_nonb = 0; + path--; /* Since the 1st path element is really the second frame */ + while( path[loc] ) + { + int next_nonb = loc; + /* Find the location of the next non-B-frame. */ + while( path[next_nonb] == 'B' ) + next_nonb++; + + /* Add the cost of the non-B-frame found above */ + if( path[next_nonb] == 'P' ) + cost += x264_slicetype_frame_cost( h, a, frames, cur_nonb, next_nonb, next_nonb ); + else /* I-frame */ + cost += x264_slicetype_frame_cost( h, a, frames, next_nonb, next_nonb, next_nonb ); + /* Early terminate if the cost we have found is larger than the best path cost so far */ + if( cost > threshold ) + break; + + if( h->param.i_bframe_pyramid && next_nonb - cur_nonb > 2 ) + { + int middle = cur_nonb + (next_nonb - cur_nonb)/2; + cost += x264_slicetype_frame_cost( h, a, frames, cur_nonb, next_nonb, middle ); + for( int next_b = loc; next_b < middle && cost < threshold; next_b++ ) + cost += x264_slicetype_frame_cost( h, a, frames, cur_nonb, middle, next_b ); + for( int next_b = middle+1; next_b < next_nonb && cost < threshold; next_b++ ) + cost += x264_slicetype_frame_cost( h, a, frames, middle, next_nonb, next_b ); + } + else + for( int next_b = loc; next_b < next_nonb && cost < threshold; next_b++ ) + cost += x264_slicetype_frame_cost( h, a, frames, cur_nonb, next_nonb, next_b ); + + loc = next_nonb + 1; + cur_nonb = next_nonb; + } + return cost; +} + +/* Viterbi/trellis slicetype decision algorithm. */ +/* Uses strings due to the fact that the speed of the control functions is + negligible compared to the cost of running slicetype_frame_cost, and because + it makes debugging easier. */ +static void x264_slicetype_path( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int length, char (*best_paths)[X264_LOOKAHEAD_MAX+1] ) +{ + char paths[2][X264_LOOKAHEAD_MAX+1]; + int num_paths = X264_MIN( h->param.i_bframe+1, length ); + int best_cost = COST_MAX; + int best_possible = 0; + int idx = 0; + + /* Iterate over all currently possible paths */ + for( int path = 0; path < num_paths; path++ ) + { + /* Add suffixes to the current path */ + int len = length - (path + 1); + memcpy( paths[idx], best_paths[len % (X264_BFRAME_MAX+1)], len ); + memset( paths[idx]+len, 'B', path ); + strcpy( paths[idx]+len+path, "P" ); + + int possible = 1; + for( int i = 1; i <= length; i++ ) + { + int i_type = frames[i]->i_type; + if( i_type == X264_TYPE_AUTO ) + continue; + if( IS_X264_TYPE_B( i_type ) ) + possible = possible && (i < len || i == length || paths[idx][i-1] == 'B'); + else + { + possible = possible && (i < len || paths[idx][i-1] != 'B'); + paths[idx][i-1] = IS_X264_TYPE_I( i_type ) ? 'I' : 'P'; + } + } + + if( possible || !best_possible ) + { + if( possible && !best_possible ) + best_cost = COST_MAX; + /* Calculate the actual cost of the current path */ + int cost = x264_slicetype_path_cost( h, a, frames, paths[idx], best_cost ); + if( cost < best_cost ) + { + best_cost = cost; + best_possible = possible; + idx ^= 1; + } + } + } + + /* Store the best path. */ + memcpy( best_paths[length % (X264_BFRAME_MAX+1)], paths[idx^1], length ); +} + +static int scenecut_internal( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int real_scenecut ) +{ + x264_frame_t *frame = frames[p1]; + + /* Don't do scenecuts on the right view of a frame-packed video. */ + if( real_scenecut && h->param.i_frame_packing == 5 && (frame->i_frame&1) ) + return 0; + + x264_slicetype_frame_cost( h, a, frames, p0, p1, p1 ); + + int icost = frame->i_cost_est[0][0]; + int pcost = frame->i_cost_est[p1-p0][0]; + float f_bias; + int i_gop_size = frame->i_frame - h->lookahead->i_last_keyframe; + float f_thresh_max = h->param.i_scenecut_threshold / 100.0; + /* magic numbers pulled out of thin air */ + float f_thresh_min = f_thresh_max * 0.25; + int res; + + if( h->param.i_keyint_min == h->param.i_keyint_max ) + f_thresh_min = f_thresh_max; + if( i_gop_size <= h->param.i_keyint_min / 4 || h->param.b_intra_refresh ) + f_bias = f_thresh_min / 4; + else if( i_gop_size <= h->param.i_keyint_min ) + f_bias = f_thresh_min * i_gop_size / h->param.i_keyint_min; + else + { + f_bias = f_thresh_min + + ( f_thresh_max - f_thresh_min ) + * ( i_gop_size - h->param.i_keyint_min ) + / ( h->param.i_keyint_max - h->param.i_keyint_min ); + } + + res = pcost >= (1.0 - f_bias) * icost; + if( res && real_scenecut ) + { + int imb = frame->i_intra_mbs[p1-p0]; + int pmb = NUM_MBS - imb; + x264_log( h, X264_LOG_DEBUG, "scene cut at %d Icost:%d Pcost:%d ratio:%.4f bias:%.4f gop:%d (imb:%d pmb:%d)\n", + frame->i_frame, + icost, pcost, 1. - (double)pcost / icost, + f_bias, i_gop_size, imb, pmb ); + } + return res; +} + +static int scenecut( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int real_scenecut, int num_frames, int i_max_search ) +{ + /* Only do analysis during a normal scenecut check. */ + if( real_scenecut && h->param.i_bframe ) + { + int origmaxp1 = p0 + 1; + /* Look ahead to avoid coding short flashes as scenecuts. */ + if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS ) + /* Don't analyse any more frames than the trellis would have covered. */ + origmaxp1 += h->param.i_bframe; + else + origmaxp1++; + int maxp1 = X264_MIN( origmaxp1, num_frames ); + + /* Where A and B are scenes: AAAAAABBBAAAAAA + * If BBB is shorter than (maxp1-p0), it is detected as a flash + * and not considered a scenecut. */ + for( int curp1 = p1; curp1 <= maxp1; curp1++ ) + if( !scenecut_internal( h, a, frames, p0, curp1, 0 ) ) + /* Any frame in between p0 and cur_p1 cannot be a real scenecut. */ + for( int i = curp1; i > p0; i-- ) + frames[i]->b_scenecut = 0; + + /* Where A-F are scenes: AAAAABBCCDDEEFFFFFF + * If each of BB ... EE are shorter than (maxp1-p0), they are + * detected as flashes and not considered scenecuts. + * Instead, the first F frame becomes a scenecut. + * If the video ends before F, no frame becomes a scenecut. */ + for( int curp0 = p0; curp0 <= maxp1; curp0++ ) + if( origmaxp1 > i_max_search || (curp0 < maxp1 && scenecut_internal( h, a, frames, curp0, maxp1, 0 )) ) + /* If cur_p0 is the p0 of a scenecut, it cannot be the p1 of a scenecut. */ + frames[curp0]->b_scenecut = 0; + } + + /* Ignore frames that are part of a flash, i.e. cannot be real scenecuts. */ + if( !frames[p1]->b_scenecut ) + return 0; + return scenecut_internal( h, a, frames, p0, p1, real_scenecut ); +} + +#define IS_X264_TYPE_AUTO_OR_I(x) ((x)==X264_TYPE_AUTO || IS_X264_TYPE_I(x)) +#define IS_X264_TYPE_AUTO_OR_B(x) ((x)==X264_TYPE_AUTO || IS_X264_TYPE_B(x)) + +void x264_slicetype_analyse( x264_t *h, int intra_minigop ) +{ + x264_mb_analysis_t a; + x264_frame_t *frames[X264_LOOKAHEAD_MAX+3] = { NULL, }; + int num_frames, orig_num_frames, keyint_limit, framecnt; + int i_max_search = X264_MIN( h->lookahead->next.i_size, X264_LOOKAHEAD_MAX ); + int vbv_lookahead = h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead; + /* For determinism we should limit the search to the number of frames lookahead has for sure + * in h->lookahead->next.list buffer, except at the end of stream. + * For normal calls with (intra_minigop == 0) that is h->lookahead->i_slicetype_length + 1 frames. + * And for I-frame calls (intra_minigop != 0) we already removed intra_minigop frames from there. */ + if( h->param.b_deterministic ) + i_max_search = X264_MIN( i_max_search, h->lookahead->i_slicetype_length + 1 - intra_minigop ); + int keyframe = !!intra_minigop; + + assert( h->frames.b_have_lowres ); + + if( !h->lookahead->last_nonb ) + return; + frames[0] = h->lookahead->last_nonb; + for( framecnt = 0; framecnt < i_max_search; framecnt++ ) + frames[framecnt+1] = h->lookahead->next.list[framecnt]; + + x264_lowres_context_init( h, &a ); + + if( !framecnt ) + { + if( h->param.rc.b_mb_tree ) + x264_macroblock_tree( h, &a, frames, 0, keyframe ); + return; + } + + keyint_limit = h->param.i_keyint_max - frames[0]->i_frame + h->lookahead->i_last_keyframe - 1; + orig_num_frames = num_frames = h->param.b_intra_refresh ? framecnt : X264_MIN( framecnt, keyint_limit ); + + /* This is important psy-wise: if we have a non-scenecut keyframe, + * there will be significant visual artifacts if the frames just before + * go down in quality due to being referenced less, despite it being + * more RD-optimal. */ + if( (h->param.analyse.b_psy && h->param.rc.b_mb_tree) || vbv_lookahead ) + num_frames = framecnt; + else if( h->param.b_open_gop && num_frames < framecnt ) + num_frames++; + else if( num_frames == 0 ) + { + frames[1]->i_type = X264_TYPE_I; + return; + } + + if( IS_X264_TYPE_AUTO_OR_I( frames[1]->i_type ) && + h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) ) + { + if( frames[1]->i_type == X264_TYPE_AUTO ) + frames[1]->i_type = X264_TYPE_I; + return; + } + +#if HAVE_OPENCL + x264_opencl_slicetype_prep( h, frames, num_frames, a.i_lambda ); +#endif + + /* Replace forced keyframes with I/IDR-frames */ + for( int j = 1; j <= num_frames; j++ ) + { + if( frames[j]->i_type == X264_TYPE_KEYFRAME ) + frames[j]->i_type = h->param.b_open_gop ? X264_TYPE_I : X264_TYPE_IDR; + } + + /* Close GOP at IDR-frames */ + for( int j = 2; j <= num_frames; j++ ) + { + if( frames[j]->i_type == X264_TYPE_IDR && IS_X264_TYPE_AUTO_OR_B( frames[j-1]->i_type ) ) + frames[j-1]->i_type = X264_TYPE_P; + } + + int num_analysed_frames = num_frames; + int reset_start; + + if( h->param.i_bframe ) + { + if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS ) + { + if( num_frames > 1 ) + { + char best_paths[X264_BFRAME_MAX+1][X264_LOOKAHEAD_MAX+1] = {"","P"}; + int best_path_index = num_frames % (X264_BFRAME_MAX+1); + + /* Perform the frametype analysis. */ + for( int j = 2; j <= num_frames; j++ ) + x264_slicetype_path( h, &a, frames, j, best_paths ); + + /* Load the results of the analysis into the frame types. */ + for( int j = 1; j < num_frames; j++ ) + { + if( best_paths[best_path_index][j-1] != 'B' ) + { + if( IS_X264_TYPE_AUTO_OR_B( frames[j]->i_type ) ) + frames[j]->i_type = X264_TYPE_P; + } + else + { + if( frames[j]->i_type == X264_TYPE_AUTO ) + frames[j]->i_type = X264_TYPE_B; + } + } + } + } + else if( h->param.i_bframe_adaptive == X264_B_ADAPT_FAST ) + { + int last_nonb = 0; + int num_bframes = h->param.i_bframe; + char path[X264_LOOKAHEAD_MAX+1]; + for( int j = 1; j < num_frames; j++ ) + { + if( j-1 > 0 && IS_X264_TYPE_B( frames[j-1]->i_type ) ) + num_bframes--; + else + { + last_nonb = j-1; + num_bframes = h->param.i_bframe; + } + if( !num_bframes ) + { + if( IS_X264_TYPE_AUTO_OR_B( frames[j]->i_type ) ) + frames[j]->i_type = X264_TYPE_P; + continue; + } + + if( frames[j]->i_type != X264_TYPE_AUTO ) + continue; + + if( IS_X264_TYPE_B( frames[j+1]->i_type ) ) + { + frames[j]->i_type = X264_TYPE_P; + continue; + } + + int bframes = j - last_nonb - 1; + memset( path, 'B', bframes ); + strcpy( path+bframes, "PP" ); + int cost_p = x264_slicetype_path_cost( h, &a, frames+last_nonb, path, COST_MAX ); + strcpy( path+bframes, "BP" ); + int cost_b = x264_slicetype_path_cost( h, &a, frames+last_nonb, path, cost_p ); + + if( cost_b < cost_p ) + frames[j]->i_type = X264_TYPE_B; + else + frames[j]->i_type = X264_TYPE_P; + } + } + else + { + int num_bframes = h->param.i_bframe; + for( int j = 1; j < num_frames; j++ ) + { + if( !num_bframes ) + { + if( IS_X264_TYPE_AUTO_OR_B( frames[j]->i_type ) ) + frames[j]->i_type = X264_TYPE_P; + } + else if( frames[j]->i_type == X264_TYPE_AUTO ) + { + if( IS_X264_TYPE_B( frames[j+1]->i_type ) ) + frames[j]->i_type = X264_TYPE_P; + else + frames[j]->i_type = X264_TYPE_B; + } + if( IS_X264_TYPE_B( frames[j]->i_type ) ) + num_bframes--; + else + num_bframes = h->param.i_bframe; + } + } + if( IS_X264_TYPE_AUTO_OR_B( frames[num_frames]->i_type ) ) + frames[num_frames]->i_type = X264_TYPE_P; + + int num_bframes = 0; + while( num_bframes < num_frames && IS_X264_TYPE_B( frames[num_bframes+1]->i_type ) ) + num_bframes++; + + /* Check scenecut on the first minigop. */ + for( int j = 1; j < num_bframes+1; j++ ) + { + if( frames[j]->i_forced_type == X264_TYPE_AUTO && IS_X264_TYPE_AUTO_OR_I( frames[j+1]->i_forced_type ) && + h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, j+1, 0, orig_num_frames, i_max_search ) ) + { + frames[j]->i_type = X264_TYPE_P; + num_analysed_frames = j; + break; + } + } + + reset_start = keyframe ? 1 : X264_MIN( num_bframes+2, num_analysed_frames+1 ); + } + else + { + for( int j = 1; j <= num_frames; j++ ) + if( IS_X264_TYPE_AUTO_OR_B( frames[j]->i_type ) ) + frames[j]->i_type = X264_TYPE_P; + reset_start = !keyframe + 1; + } + + /* Perform the actual macroblock tree analysis. + * Don't go farther than the maximum keyframe interval; this helps in short GOPs. */ + if( h->param.rc.b_mb_tree ) + x264_macroblock_tree( h, &a, frames, X264_MIN(num_frames, h->param.i_keyint_max), keyframe ); + + /* Enforce keyframe limit. */ + if( !h->param.b_intra_refresh ) + { + int last_keyframe = h->lookahead->i_last_keyframe; + int last_possible = 0; + for( int j = 1; j <= num_frames; j++ ) + { + x264_frame_t *frm = frames[j]; + int keyframe_dist = frm->i_frame - last_keyframe; + + if( IS_X264_TYPE_AUTO_OR_I( frm->i_forced_type ) ) + { + if( h->param.b_open_gop || !IS_X264_TYPE_B( frames[j-1]->i_forced_type ) ) + last_possible = j; + } + if( keyframe_dist >= h->param.i_keyint_max ) + { + if( last_possible != 0 && last_possible != j ) + { + j = last_possible; + frm = frames[j]; + keyframe_dist = frm->i_frame - last_keyframe; + } + last_possible = 0; + if( frm->i_type != X264_TYPE_IDR ) + frm->i_type = h->param.b_open_gop ? X264_TYPE_I : X264_TYPE_IDR; + } + if( frm->i_type == X264_TYPE_I && keyframe_dist >= h->param.i_keyint_min ) + { + if( h->param.b_open_gop ) + { + last_keyframe = frm->i_frame; + if( h->param.b_bluray_compat ) + { + // Use bluray order + int bframes = 0; + while( bframes < j-1 && IS_X264_TYPE_B( frames[j-1-bframes]->i_type ) ) + bframes++; + last_keyframe -= bframes; + } + } + else if( frm->i_forced_type != X264_TYPE_I ) + frm->i_type = X264_TYPE_IDR; + } + if( frm->i_type == X264_TYPE_IDR ) + { + last_keyframe = frm->i_frame; + if( j > 1 && IS_X264_TYPE_B( frames[j-1]->i_type ) ) + frames[j-1]->i_type = X264_TYPE_P; + } + } + } + + if( vbv_lookahead ) + x264_vbv_lookahead( h, &a, frames, num_frames, keyframe ); + + /* Restore frametypes for all frames that haven't actually been decided yet. */ + for( int j = reset_start; j <= num_frames; j++ ) + frames[j]->i_type = frames[j]->i_forced_type; + +#if HAVE_OPENCL + x264_opencl_slicetype_end( h ); +#endif +} + +void x264_slicetype_decide( x264_t *h ) +{ + x264_frame_t *frames[X264_BFRAME_MAX+2]; + x264_frame_t *frm; + int bframes; + int brefs; + + if( !h->lookahead->next.i_size ) + return; + + int lookahead_size = h->lookahead->next.i_size; + + for( int i = 0; i < h->lookahead->next.i_size; i++ ) + { + if( h->param.b_vfr_input ) + { + if( lookahead_size-- > 1 ) + h->lookahead->next.list[i]->i_duration = 2 * (h->lookahead->next.list[i+1]->i_pts - h->lookahead->next.list[i]->i_pts); + else + h->lookahead->next.list[i]->i_duration = h->i_prev_duration; + } + else + h->lookahead->next.list[i]->i_duration = delta_tfi_divisor[h->lookahead->next.list[i]->i_pic_struct]; + h->i_prev_duration = h->lookahead->next.list[i]->i_duration; + h->lookahead->next.list[i]->f_duration = (double)h->lookahead->next.list[i]->i_duration + * h->sps->vui.i_num_units_in_tick + / h->sps->vui.i_time_scale; + + if( h->lookahead->next.list[i]->i_frame > h->i_disp_fields_last_frame && lookahead_size > 0 ) + { + h->lookahead->next.list[i]->i_field_cnt = h->i_disp_fields; + h->i_disp_fields += h->lookahead->next.list[i]->i_duration; + h->i_disp_fields_last_frame = h->lookahead->next.list[i]->i_frame; + } + else if( lookahead_size == 0 ) + { + h->lookahead->next.list[i]->i_field_cnt = h->i_disp_fields; + h->lookahead->next.list[i]->i_duration = h->i_prev_duration; + } + } + + if( h->param.rc.b_stat_read ) + { + /* Use the frame types from the first pass */ + for( int i = 0; i < h->lookahead->next.i_size; i++ ) + h->lookahead->next.list[i]->i_type = + x264_ratecontrol_slice_type( h, h->lookahead->next.list[i]->i_frame ); + } + else if( (h->param.i_bframe && h->param.i_bframe_adaptive) + || h->param.i_scenecut_threshold + || h->param.rc.b_mb_tree + || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead) ) + x264_slicetype_analyse( h, 0 ); + + for( bframes = 0, brefs = 0;; bframes++ ) + { + frm = h->lookahead->next.list[bframes]; + + if( frm->i_forced_type != X264_TYPE_AUTO && frm->i_type != frm->i_forced_type && + !(frm->i_forced_type == X264_TYPE_KEYFRAME && IS_X264_TYPE_I( frm->i_type )) ) + { + x264_log( h, X264_LOG_WARNING, "forced frame type (%d) at %d was changed to frame type (%d)\n", + frm->i_forced_type, frm->i_frame, frm->i_type ); + } + + if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && + brefs == h->param.i_bframe_pyramid ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s \n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid] ); + } + /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available. + smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it. */ + else if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL && + brefs && h->param.i_frame_reference <= (brefs+3) ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference ); + } + + if( frm->i_type == X264_TYPE_KEYFRAME ) + frm->i_type = h->param.b_open_gop ? X264_TYPE_I : X264_TYPE_IDR; + + /* Limit GOP size */ + if( (!h->param.b_intra_refresh || frm->i_frame == 0) && frm->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_max ) + { + if( frm->i_type == X264_TYPE_AUTO || frm->i_type == X264_TYPE_I ) + frm->i_type = h->param.b_open_gop && h->lookahead->i_last_keyframe >= 0 ? X264_TYPE_I : X264_TYPE_IDR; + int warn = frm->i_type != X264_TYPE_IDR; + if( warn && h->param.b_open_gop ) + warn &= frm->i_type != X264_TYPE_I; + if( warn ) + { + x264_log( h, X264_LOG_WARNING, "specified frame type (%d) at %d is not compatible with keyframe interval\n", frm->i_type, frm->i_frame ); + frm->i_type = h->param.b_open_gop && h->lookahead->i_last_keyframe >= 0 ? X264_TYPE_I : X264_TYPE_IDR; + } + } + if( frm->i_type == X264_TYPE_I && frm->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_min ) + { + if( h->param.b_open_gop ) + { + h->lookahead->i_last_keyframe = frm->i_frame; // Use display order + if( h->param.b_bluray_compat ) + h->lookahead->i_last_keyframe -= bframes; // Use bluray order + frm->b_keyframe = 1; + } + else + frm->i_type = X264_TYPE_IDR; + } + if( frm->i_type == X264_TYPE_IDR ) + { + /* Close GOP */ + h->lookahead->i_last_keyframe = frm->i_frame; + frm->b_keyframe = 1; + if( bframes > 0 ) + { + bframes--; + h->lookahead->next.list[bframes]->i_type = X264_TYPE_P; + } + } + + if( bframes == h->param.i_bframe || + !h->lookahead->next.list[bframes+1] ) + { + if( IS_X264_TYPE_B( frm->i_type ) ) + x264_log( h, X264_LOG_WARNING, "specified frame type is not compatible with max B-frames\n" ); + if( frm->i_type == X264_TYPE_AUTO + || IS_X264_TYPE_B( frm->i_type ) ) + frm->i_type = X264_TYPE_P; + } + + if( frm->i_type == X264_TYPE_BREF ) + brefs++; + + if( frm->i_type == X264_TYPE_AUTO ) + frm->i_type = X264_TYPE_B; + + else if( !IS_X264_TYPE_B( frm->i_type ) ) break; + } + + if( bframes ) + h->lookahead->next.list[bframes-1]->b_last_minigop_bframe = 1; + h->lookahead->next.list[bframes]->i_bframes = bframes; + + /* insert a bref into the sequence */ + if( h->param.i_bframe_pyramid && bframes > 1 && !brefs ) + { + h->lookahead->next.list[(bframes-1)/2]->i_type = X264_TYPE_BREF; + brefs++; + } + + /* calculate the frame costs ahead of time for x264_rc_analyse_slice while we still have lowres */ + if( h->param.rc.i_rc_method != X264_RC_CQP ) + { + x264_mb_analysis_t a; + int p0, p1, b; + p1 = b = bframes + 1; + + x264_lowres_context_init( h, &a ); + + frames[0] = h->lookahead->last_nonb; + memcpy( &frames[1], h->lookahead->next.list, (bframes+1) * sizeof(x264_frame_t*) ); + if( IS_X264_TYPE_I( h->lookahead->next.list[bframes]->i_type ) ) + p0 = bframes + 1; + else // P + p0 = 0; + + x264_slicetype_frame_cost( h, &a, frames, p0, p1, b ); + + if( (p0 != p1 || bframes) && h->param.rc.i_vbv_buffer_size ) + { + /* We need the intra costs for row SATDs. */ + x264_slicetype_frame_cost( h, &a, frames, b, b, b ); + + /* We need B-frame costs for row SATDs. */ + p0 = 0; + for( b = 1; b <= bframes; b++ ) + { + if( frames[b]->i_type == X264_TYPE_B ) + for( p1 = b; frames[p1]->i_type == X264_TYPE_B; ) + p1++; + else + p1 = bframes + 1; + x264_slicetype_frame_cost( h, &a, frames, p0, p1, b ); + if( frames[b]->i_type == X264_TYPE_BREF ) + p0 = b; + } + } + } + + /* Analyse for weighted P frames */ + if( !h->param.rc.b_stat_read && h->lookahead->next.list[bframes]->i_type == X264_TYPE_P + && h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE ) + { + x264_emms(); + x264_weights_analyse( h, h->lookahead->next.list[bframes], h->lookahead->last_nonb, 0 ); + } + + /* shift sequence to coded order. + use a small temporary list to avoid shifting the entire next buffer around */ + int i_coded = h->lookahead->next.list[0]->i_frame; + if( bframes ) + { + int idx_list[] = { brefs+1, 1 }; + for( int i = 0; i < bframes; i++ ) + { + int idx = idx_list[h->lookahead->next.list[i]->i_type == X264_TYPE_BREF]++; + frames[idx] = h->lookahead->next.list[i]; + frames[idx]->i_reordered_pts = h->lookahead->next.list[idx]->i_pts; + } + frames[0] = h->lookahead->next.list[bframes]; + frames[0]->i_reordered_pts = h->lookahead->next.list[0]->i_pts; + memcpy( h->lookahead->next.list, frames, (bframes+1) * sizeof(x264_frame_t*) ); + } + + for( int i = 0; i <= bframes; i++ ) + { + h->lookahead->next.list[i]->i_coded = i_coded++; + if( i ) + { + x264_calculate_durations( h, h->lookahead->next.list[i], h->lookahead->next.list[i-1], &h->i_cpb_delay, &h->i_coded_fields ); + h->lookahead->next.list[0]->f_planned_cpb_duration[i-1] = (double)h->lookahead->next.list[i]->i_cpb_duration * + h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + } + else + x264_calculate_durations( h, h->lookahead->next.list[i], NULL, &h->i_cpb_delay, &h->i_coded_fields ); + } +} + +int x264_rc_analyse_slice( x264_t *h ) +{ + int p0 = 0, p1, b; + int cost; + x264_emms(); + + if( IS_X264_TYPE_I(h->fenc->i_type) ) + p1 = b = 0; + else if( h->fenc->i_type == X264_TYPE_P ) + p1 = b = h->fenc->i_bframes + 1; + else //B + { + p1 = (h->fref_nearest[1]->i_poc - h->fref_nearest[0]->i_poc)/2; + b = (h->fenc->i_poc - h->fref_nearest[0]->i_poc)/2; + } + /* We don't need to assign p0/p1 since we are not performing any real analysis here. */ + x264_frame_t **frames = &h->fenc - b; + + /* cost should have been already calculated by x264_slicetype_decide */ + cost = frames[b]->i_cost_est[b-p0][p1-b]; + assert( cost >= 0 ); + + if( h->param.rc.b_mb_tree && !h->param.rc.b_stat_read ) + { + cost = x264_slicetype_frame_cost_recalculate( h, frames, p0, p1, b ); + if( b && h->param.rc.i_vbv_buffer_size ) + x264_slicetype_frame_cost_recalculate( h, frames, b, b, b ); + } + /* In AQ, use the weighted score instead. */ + else if( h->param.rc.i_aq_mode ) + cost = frames[b]->i_cost_est_aq[b-p0][p1-b]; + + h->fenc->i_row_satd = h->fenc->i_row_satds[b-p0][p1-b]; + h->fdec->i_row_satd = h->fdec->i_row_satds[b-p0][p1-b]; + h->fdec->i_satd = cost; + memcpy( h->fdec->i_row_satd, h->fenc->i_row_satd, h->mb.i_mb_height * sizeof(int) ); + if( !IS_X264_TYPE_I(h->fenc->i_type) ) + memcpy( h->fdec->i_row_satds[0][0], h->fenc->i_row_satds[0][0], h->mb.i_mb_height * sizeof(int) ); + + if( h->param.b_intra_refresh && h->param.rc.i_vbv_buffer_size && h->fenc->i_type == X264_TYPE_P ) + { + int ip_factor = 256 * h->param.rc.f_ip_factor; /* fix8 */ + for( int y = 0; y < h->mb.i_mb_height; y++ ) + { + int mb_xy = y * h->mb.i_mb_stride + h->fdec->i_pir_start_col; + for( int x = h->fdec->i_pir_start_col; x <= h->fdec->i_pir_end_col; x++, mb_xy++ ) + { + int intra_cost = (h->fenc->i_intra_cost[mb_xy] * ip_factor + 128) >> 8; + int inter_cost = h->fenc->lowres_costs[b-p0][p1-b][mb_xy] & LOWRES_COST_MASK; + int diff = intra_cost - inter_cost; + if( h->param.rc.i_aq_mode ) + h->fdec->i_row_satd[y] += (diff * frames[b]->i_inv_qscale_factor[mb_xy] + 128) >> 8; + else + h->fdec->i_row_satd[y] += diff; + cost += diff; + } + } + } + + return cost; +} diff --git a/vendor/github.com/gen2brain/x264-go/x264c/external/x264/x264.h b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/x264.h new file mode 100644 index 00000000..21c2c18d --- /dev/null +++ b/vendor/github.com/gen2brain/x264-go/x264c/external/x264/x264.h @@ -0,0 +1,964 @@ +/***************************************************************************** + * x264.h: x264 public header + ***************************************************************************** + * Copyright (C) 2003-2017 x264 project + * + * Authors: Laurent Aimar + * Loren Merritt + * Fiona Glaser + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. + *****************************************************************************/ + +#ifndef X264_X264_H +#define X264_X264_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_STDINT_H) && !defined(_STDINT_H_) && !defined(_STDINT_H_INCLUDED) && !defined(_STDINT) &&\ + !defined(_SYS_STDINT_H_) && !defined(_INTTYPES_H) && !defined(_INTTYPES_H_) && !defined(_INTTYPES) +# ifdef _MSC_VER +# pragma message("You must include stdint.h or inttypes.h before x264.h") +# else +# warning You must include stdint.h or inttypes.h before x264.h +# endif +#endif + +#include + +//#include "x264_config.h" + +#define X264_VERSION "" + +#define X264_BUILD 152 + +/* Application developers planning to link against a shared library version of + * libx264 from a Microsoft Visual Studio or similar development environment + * will need to define X264_API_IMPORTS before including this header. + * This clause does not apply to MinGW, similar development environments, or non + * Windows platforms. */ +#ifdef X264_API_IMPORTS +#define X264_API __declspec(dllimport) +#else +#define X264_API +#endif + +/* x264_t: + * opaque handler for encoder */ +typedef struct x264_t x264_t; + +/**************************************************************************** + * NAL structure and functions + ****************************************************************************/ + +enum nal_unit_type_e +{ + NAL_UNKNOWN = 0, + NAL_SLICE = 1, + NAL_SLICE_DPA = 2, + NAL_SLICE_DPB = 3, + NAL_SLICE_DPC = 4, + NAL_SLICE_IDR = 5, /* ref_idc != 0 */ + NAL_SEI = 6, /* ref_idc == 0 */ + NAL_SPS = 7, + NAL_PPS = 8, + NAL_AUD = 9, + NAL_FILLER = 12, + /* ref_idc == 0 for 6,9,10,11,12 */ +}; +enum nal_priority_e +{ + NAL_PRIORITY_DISPOSABLE = 0, + NAL_PRIORITY_LOW = 1, + NAL_PRIORITY_HIGH = 2, + NAL_PRIORITY_HIGHEST = 3, +}; + +/* The data within the payload is already NAL-encapsulated; the ref_idc and type + * are merely in the struct for easy access by the calling application. + * All data returned in an x264_nal_t, including the data in p_payload, is no longer + * valid after the next call to x264_encoder_encode. Thus it must be used or copied + * before calling x264_encoder_encode or x264_encoder_headers again. */ +typedef struct x264_nal_t +{ + int i_ref_idc; /* nal_priority_e */ + int i_type; /* nal_unit_type_e */ + int b_long_startcode; + int i_first_mb; /* If this NAL is a slice, the index of the first MB in the slice. */ + int i_last_mb; /* If this NAL is a slice, the index of the last MB in the slice. */ + + /* Size of payload (including any padding) in bytes. */ + int i_payload; + /* If param->b_annexb is set, Annex-B bytestream with startcode. + * Otherwise, startcode is replaced with a 4-byte size. + * This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */ + uint8_t *p_payload; + + /* Size of padding in bytes. */ + int i_padding; +} x264_nal_t; + +/**************************************************************************** + * Encoder parameters + ****************************************************************************/ +/* CPU flags */ + +/* x86 */ +#define X264_CPU_MMX (1<<0) +#define X264_CPU_MMX2 (1<<1) /* MMX2 aka MMXEXT aka ISSE */ +#define X264_CPU_MMXEXT X264_CPU_MMX2 +#define X264_CPU_SSE (1<<2) +#define X264_CPU_SSE2 (1<<3) +#define X264_CPU_LZCNT (1<<4) +#define X264_CPU_SSE3 (1<<5) +#define X264_CPU_SSSE3 (1<<6) +#define X264_CPU_SSE4 (1<<7) /* SSE4.1 */ +#define X264_CPU_SSE42 (1<<8) /* SSE4.2 */ +#define X264_CPU_AVX (1<<9) /* Requires OS support even if YMM registers aren't used */ +#define X264_CPU_XOP (1<<10) /* AMD XOP */ +#define X264_CPU_FMA4 (1<<11) /* AMD FMA4 */ +#define X264_CPU_FMA3 (1<<12) +#define X264_CPU_BMI1 (1<<13) +#define X264_CPU_BMI2 (1<<14) +#define X264_CPU_AVX2 (1<<15) +#define X264_CPU_AVX512 (1<<16) /* AVX-512 {F, CD, BW, DQ, VL}, requires OS support */ +/* x86 modifiers */ +#define X264_CPU_CACHELINE_32 (1<<17) /* avoid memory loads that span the border between two cachelines */ +#define X264_CPU_CACHELINE_64 (1<<18) /* 32/64 is the size of a cacheline in bytes */ +#define X264_CPU_SSE2_IS_SLOW (1<<19) /* avoid most SSE2 functions on Athlon64 */ +#define X264_CPU_SSE2_IS_FAST (1<<20) /* a few functions are only faster on Core2 and Phenom */ +#define X264_CPU_SLOW_SHUFFLE (1<<21) /* The Conroe has a slow shuffle unit (relative to overall SSE performance) */ +#define X264_CPU_STACK_MOD4 (1<<22) /* if stack is only mod4 and not mod16 */ +#define X264_CPU_SLOW_ATOM (1<<23) /* The Atom is terrible: slow SSE unaligned loads, slow + * SIMD multiplies, slow SIMD variable shifts, slow pshufb, + * cacheline split penalties -- gather everything here that + * isn't shared by other CPUs to avoid making half a dozen + * new SLOW flags. */ +#define X264_CPU_SLOW_PSHUFB (1<<24) /* such as on the Intel Atom */ +#define X264_CPU_SLOW_PALIGNR (1<<25) /* such as on the AMD Bobcat */ + +/* PowerPC */ +#define X264_CPU_ALTIVEC 0x0000001 + +/* ARM and AArch64 */ +#define X264_CPU_ARMV6 0x0000001 +#define X264_CPU_NEON 0x0000002 /* ARM NEON */ +#define X264_CPU_FAST_NEON_MRC 0x0000004 /* Transfer from NEON to ARM register is fast (Cortex-A9) */ +#define X264_CPU_ARMV8 0x0000008 + +/* MIPS */ +#define X264_CPU_MSA 0x0000001 /* MIPS MSA */ + +/* Analyse flags */ +#define X264_ANALYSE_I4x4 0x0001 /* Analyse i4x4 */ +#define X264_ANALYSE_I8x8 0x0002 /* Analyse i8x8 (requires 8x8 transform) */ +#define X264_ANALYSE_PSUB16x16 0x0010 /* Analyse p16x8, p8x16 and p8x8 */ +#define X264_ANALYSE_PSUB8x8 0x0020 /* Analyse p8x4, p4x8, p4x4 */ +#define X264_ANALYSE_BSUB16x16 0x0100 /* Analyse b16x8, b8x16 and b8x8 */ +#define X264_DIRECT_PRED_NONE 0 +#define X264_DIRECT_PRED_SPATIAL 1 +#define X264_DIRECT_PRED_TEMPORAL 2 +#define X264_DIRECT_PRED_AUTO 3 +#define X264_ME_DIA 0 +#define X264_ME_HEX 1 +#define X264_ME_UMH 2 +#define X264_ME_ESA 3 +#define X264_ME_TESA 4 +#define X264_CQM_FLAT 0 +#define X264_CQM_JVT 1 +#define X264_CQM_CUSTOM 2 +#define X264_RC_CQP 0 +#define X264_RC_CRF 1 +#define X264_RC_ABR 2 +#define X264_QP_AUTO 0 +#define X264_AQ_NONE 0 +#define X264_AQ_VARIANCE 1 +#define X264_AQ_AUTOVARIANCE 2 +#define X264_AQ_AUTOVARIANCE_BIASED 3 +#define X264_B_ADAPT_NONE 0 +#define X264_B_ADAPT_FAST 1 +#define X264_B_ADAPT_TRELLIS 2 +#define X264_WEIGHTP_NONE 0 +#define X264_WEIGHTP_SIMPLE 1 +#define X264_WEIGHTP_SMART 2 +#define X264_B_PYRAMID_NONE 0 +#define X264_B_PYRAMID_STRICT 1 +#define X264_B_PYRAMID_NORMAL 2 +#define X264_KEYINT_MIN_AUTO 0 +#define X264_KEYINT_MAX_INFINITE (1<<30) + +static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 }; +static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", "tesa", 0 }; +static const char * const x264_b_pyramid_names[] = { "none", "strict", "normal", 0 }; +static const char * const x264_overscan_names[] = { "undef", "show", "crop", 0 }; +static const char * const x264_vidformat_names[] = { "component", "pal", "ntsc", "secam", "mac", "undef", 0 }; +static const char * const x264_fullrange_names[] = { "off", "on", 0 }; +static const char * const x264_colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", "bt2020", "smpte428", + "smpte431", "smpte432", 0 }; +static const char * const x264_transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100", "log316", + "iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", "smpte2084", "smpte428", 0 }; +static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", "bt2020nc", "bt2020c", + "smpte2085", 0 }; +static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 }; + +/* Colorspace type */ +#define X264_CSP_MASK 0x00ff /* */ +#define X264_CSP_NONE 0x0000 /* Invalid mode */ +#define X264_CSP_I420 0x0001 /* yuv 4:2:0 planar */ +#define X264_CSP_YV12 0x0002 /* yvu 4:2:0 planar */ +#define X264_CSP_NV12 0x0003 /* yuv 4:2:0, with one y plane and one packed u+v */ +#define X264_CSP_NV21 0x0004 /* yuv 4:2:0, with one y plane and one packed v+u */ +#define X264_CSP_I422 0x0005 /* yuv 4:2:2 planar */ +#define X264_CSP_YV16 0x0006 /* yvu 4:2:2 planar */ +#define X264_CSP_NV16 0x0007 /* yuv 4:2:2, with one y plane and one packed u+v */ +#define X264_CSP_YUYV 0x0008 /* yuyv 4:2:2 packed */ +#define X264_CSP_UYVY 0x0009 /* uyvy 4:2:2 packed */ +#define X264_CSP_V210 0x000a /* 10-bit yuv 4:2:2 packed in 32 */ +#define X264_CSP_I444 0x000b /* yuv 4:4:4 planar */ +#define X264_CSP_YV24 0x000c /* yvu 4:4:4 planar */ +#define X264_CSP_BGR 0x000d /* packed bgr 24bits */ +#define X264_CSP_BGRA 0x000e /* packed bgr 32bits */ +#define X264_CSP_RGB 0x000f /* packed rgb 24bits */ +#define X264_CSP_MAX 0x0010 /* end of list */ +#define X264_CSP_VFLIP 0x1000 /* the csp is vertically flipped */ +#define X264_CSP_HIGH_DEPTH 0x2000 /* the csp has a depth of 16 bits per pixel component */ + +/* Slice type */ +#define X264_TYPE_AUTO 0x0000 /* Let x264 choose the right type */ +#define X264_TYPE_IDR 0x0001 +#define X264_TYPE_I 0x0002 +#define X264_TYPE_P 0x0003 +#define X264_TYPE_BREF 0x0004 /* Non-disposable B-frame */ +#define X264_TYPE_B 0x0005 +#define X264_TYPE_KEYFRAME 0x0006 /* IDR or I depending on b_open_gop option */ +#define IS_X264_TYPE_I(x) ((x)==X264_TYPE_I || (x)==X264_TYPE_IDR || (x)==X264_TYPE_KEYFRAME) +#define IS_X264_TYPE_B(x) ((x)==X264_TYPE_B || (x)==X264_TYPE_BREF) + +/* Log level */ +#define X264_LOG_NONE (-1) +#define X264_LOG_ERROR 0 +#define X264_LOG_WARNING 1 +#define X264_LOG_INFO 2 +#define X264_LOG_DEBUG 3 + +/* Threading */ +#define X264_THREADS_AUTO 0 /* Automatically select optimal number of threads */ +#define X264_SYNC_LOOKAHEAD_AUTO (-1) /* Automatically select optimal lookahead thread buffer size */ + +/* HRD */ +#define X264_NAL_HRD_NONE 0 +#define X264_NAL_HRD_VBR 1 +#define X264_NAL_HRD_CBR 2 + +/* Zones: override ratecontrol or other options for specific sections of the video. + * See x264_encoder_reconfig() for which options can be changed. + * If zones overlap, whichever comes later in the list takes precedence. */ +typedef struct x264_zone_t +{ + int i_start, i_end; /* range of frame numbers */ + int b_force_qp; /* whether to use qp vs bitrate factor */ + int i_qp; + float f_bitrate_factor; + struct x264_param_t *param; +} x264_zone_t; + +typedef struct x264_param_t +{ + /* CPU flags */ + unsigned int cpu; + int i_threads; /* encode multiple frames in parallel */ + int i_lookahead_threads; /* multiple threads for lookahead analysis */ + int b_sliced_threads; /* Whether to use slice-based threading. */ + int b_deterministic; /* whether to allow non-deterministic optimizations when threaded */ + int b_cpu_independent; /* force canonical behavior rather than cpu-dependent optimal algorithms */ + int i_sync_lookahead; /* threaded lookahead buffer */ + + /* Video Properties */ + int i_width; + int i_height; + int i_csp; /* CSP of encoded bitstream */ + int i_level_idc; + int i_frame_total; /* number of frames to encode if known, else 0 */ + + /* NAL HRD + * Uses Buffering and Picture Timing SEIs to signal HRD + * The HRD in H.264 was not designed with VFR in mind. + * It is therefore not recommendeded to use NAL HRD with VFR. + * Furthermore, reconfiguring the VBV (via x264_encoder_reconfig) + * will currently generate invalid HRD. */ + int i_nal_hrd; + + struct + { + /* they will be reduced to be 0 < x <= 65535 and prime */ + int i_sar_height; + int i_sar_width; + + int i_overscan; /* 0=undef, 1=no overscan, 2=overscan */ + + /* see h264 annex E for the values of the following */ + int i_vidformat; + int b_fullrange; + int i_colorprim; + int i_transfer; + int i_colmatrix; + int i_chroma_loc; /* both top & bottom */ + } vui; + + /* Bitstream parameters */ + int i_frame_reference; /* Maximum number of reference frames */ + int i_dpb_size; /* Force a DPB size larger than that implied by B-frames and reference frames. + * Useful in combination with interactive error resilience. */ + int i_keyint_max; /* Force an IDR keyframe at this interval */ + int i_keyint_min; /* Scenecuts closer together than this are coded as I, not IDR. */ + int i_scenecut_threshold; /* how aggressively to insert extra I frames */ + int b_intra_refresh; /* Whether or not to use periodic intra refresh instead of IDR frames. */ + + int i_bframe; /* how many b-frame between 2 references pictures */ + int i_bframe_adaptive; + int i_bframe_bias; + int i_bframe_pyramid; /* Keep some B-frames as references: 0=off, 1=strict hierarchical, 2=normal */ + int b_open_gop; + int b_bluray_compat; + int i_avcintra_class; + + int b_deblocking_filter; + int i_deblocking_filter_alphac0; /* [-6, 6] -6 light filter, 6 strong */ + int i_deblocking_filter_beta; /* [-6, 6] idem */ + + int b_cabac; + int i_cabac_init_idc; + + int b_interlaced; + int b_constrained_intra; + + int i_cqm_preset; + char *psz_cqm_file; /* filename (in UTF-8) of CQM file, JM format */ + uint8_t cqm_4iy[16]; /* used only if i_cqm_preset == X264_CQM_CUSTOM */ + uint8_t cqm_4py[16]; + uint8_t cqm_4ic[16]; + uint8_t cqm_4pc[16]; + uint8_t cqm_8iy[64]; + uint8_t cqm_8py[64]; + uint8_t cqm_8ic[64]; + uint8_t cqm_8pc[64]; + + /* Log */ + void (*pf_log)( void *, int i_level, const char *psz, va_list ); + void *p_log_private; + int i_log_level; + int b_full_recon; /* fully reconstruct frames, even when not necessary for encoding. Implied by psz_dump_yuv */ + char *psz_dump_yuv; /* filename (in UTF-8) for reconstructed frames */ + + /* Encoder analyser parameters */ + struct + { + unsigned int intra; /* intra partitions */ + unsigned int inter; /* inter partitions */ + + int b_transform_8x8; + int i_weighted_pred; /* weighting for P-frames */ + int b_weighted_bipred; /* implicit weighting for B-frames */ + int i_direct_mv_pred; /* spatial vs temporal mv prediction */ + int i_chroma_qp_offset; + + int i_me_method; /* motion estimation algorithm to use (X264_ME_*) */ + int i_me_range; /* integer pixel motion estimation search range (from predicted mv) */ + int i_mv_range; /* maximum length of a mv (in pixels). -1 = auto, based on level */ + int i_mv_range_thread; /* minimum space between threads. -1 = auto, based on number of threads. */ + int i_subpel_refine; /* subpixel motion estimation quality */ + int b_chroma_me; /* chroma ME for subpel and mode decision in P-frames */ + int b_mixed_references; /* allow each mb partition to have its own reference number */ + int i_trellis; /* trellis RD quantization */ + int b_fast_pskip; /* early SKIP detection on P-frames */ + int b_dct_decimate; /* transform coefficient thresholding on P-frames */ + int i_noise_reduction; /* adaptive pseudo-deadzone */ + float f_psy_rd; /* Psy RD strength */ + float f_psy_trellis; /* Psy trellis strength */ + int b_psy; /* Toggle all psy optimizations */ + + int b_mb_info; /* Use input mb_info data in x264_picture_t */ + int b_mb_info_update; /* Update the values in mb_info according to the results of encoding. */ + + /* the deadzone size that will be used in luma quantization */ + int i_luma_deadzone[2]; /* {inter, intra} */ + + int b_psnr; /* compute and print PSNR stats */ + int b_ssim; /* compute and print SSIM stats */ + } analyse; + + /* Rate control parameters */ + struct + { + int i_rc_method; /* X264_RC_* */ + + int i_qp_constant; /* 0 to (51 + 6*(x264_bit_depth-8)). 0=lossless */ + int i_qp_min; /* min allowed QP value */ + int i_qp_max; /* max allowed QP value */ + int i_qp_step; /* max QP step between frames */ + + int i_bitrate; + float f_rf_constant; /* 1pass VBR, nominal QP */ + float f_rf_constant_max; /* In CRF mode, maximum CRF as caused by VBV */ + float f_rate_tolerance; + int i_vbv_max_bitrate; + int i_vbv_buffer_size; + float f_vbv_buffer_init; /* <=1: fraction of buffer_size. >1: kbit */ + float f_ip_factor; + float f_pb_factor; + + /* VBV filler: force CBR VBV and use filler bytes to ensure hard-CBR. + * Implied by NAL-HRD CBR. */ + int b_filler; + + int i_aq_mode; /* psy adaptive QP. (X264_AQ_*) */ + float f_aq_strength; + int b_mb_tree; /* Macroblock-tree ratecontrol. */ + int i_lookahead; + + /* 2pass */ + int b_stat_write; /* Enable stat writing in psz_stat_out */ + char *psz_stat_out; /* output filename (in UTF-8) of the 2pass stats file */ + int b_stat_read; /* Read stat from psz_stat_in and use it */ + char *psz_stat_in; /* input filename (in UTF-8) of the 2pass stats file */ + + /* 2pass params (same as ffmpeg ones) */ + float f_qcompress; /* 0.0 => cbr, 1.0 => constant qp */ + float f_qblur; /* temporally blur quants */ + float f_complexity_blur; /* temporally blur complexity */ + x264_zone_t *zones; /* ratecontrol overrides */ + int i_zones; /* number of zone_t's */ + char *psz_zones; /* alternate method of specifying zones */ + } rc; + + /* Cropping Rectangle parameters: added to those implicitly defined by + non-mod16 video resolutions. */ + struct + { + unsigned int i_left; + unsigned int i_top; + unsigned int i_right; + unsigned int i_bottom; + } crop_rect; + + /* frame packing arrangement flag */ + int i_frame_packing; + + /* Muxing parameters */ + int b_aud; /* generate access unit delimiters */ + int b_repeat_headers; /* put SPS/PPS before each keyframe */ + int b_annexb; /* if set, place start codes (4 bytes) before NAL units, + * otherwise place size (4 bytes) before NAL units. */ + int i_sps_id; /* SPS and PPS id number */ + int b_vfr_input; /* VFR input. If 1, use timebase and timestamps for ratecontrol purposes. + * If 0, use fps only. */ + int b_pulldown; /* use explicity set timebase for CFR */ + uint32_t i_fps_num; + uint32_t i_fps_den; + uint32_t i_timebase_num; /* Timebase numerator */ + uint32_t i_timebase_den; /* Timebase denominator */ + + int b_tff; + + /* Pulldown: + * The correct pic_struct must be passed with each input frame. + * The input timebase should be the timebase corresponding to the output framerate. This should be constant. + * e.g. for 3:2 pulldown timebase should be 1001/30000 + * The PTS passed with each frame must be the PTS of the frame after pulldown is applied. + * Frame doubling and tripling require b_vfr_input set to zero (see H.264 Table D-1) + * + * Pulldown changes are not clearly defined in H.264. Therefore, it is the calling app's responsibility to manage this. + */ + + int b_pic_struct; + + /* Fake Interlaced. + * + * Used only when b_interlaced=0. Setting this flag makes it possible to flag the stream as PAFF interlaced yet + * encode all frames progessively. It is useful for encoding 25p and 30p Blu-Ray streams. + */ + + int b_fake_interlaced; + + /* Don't optimize header parameters based on video content, e.g. ensure that splitting an input video, compressing + * each part, and stitching them back together will result in identical SPS/PPS. This is necessary for stitching + * with container formats that don't allow multiple SPS/PPS. */ + int b_stitchable; + + int b_opencl; /* use OpenCL when available */ + int i_opencl_device; /* specify count of GPU devices to skip, for CLI users */ + void *opencl_device_id; /* pass explicit cl_device_id as void*, for API users */ + char *psz_clbin_file; /* filename (in UTF-8) of the compiled OpenCL kernel cache file */ + + /* Slicing parameters */ + int i_slice_max_size; /* Max size per slice in bytes; includes estimated NAL overhead. */ + int i_slice_max_mbs; /* Max number of MBs per slice; overrides i_slice_count. */ + int i_slice_min_mbs; /* Min number of MBs per slice */ + int i_slice_count; /* Number of slices per frame: forces rectangular slices. */ + int i_slice_count_max; /* Absolute cap on slices per frame; stops applying slice-max-size + * and slice-max-mbs if this is reached. */ + + /* Optional callback for freeing this x264_param_t when it is done being used. + * Only used when the x264_param_t sits in memory for an indefinite period of time, + * i.e. when an x264_param_t is passed to x264_t in an x264_picture_t or in zones. + * Not used when x264_encoder_reconfig is called directly. */ + void (*param_free)( void* ); + + /* Optional low-level callback for low-latency encoding. Called for each output NAL unit + * immediately after the NAL unit is finished encoding. This allows the calling application + * to begin processing video data (e.g. by sending packets over a network) before the frame + * is done encoding. + * + * This callback MUST do the following in order to work correctly: + * 1) Have available an output buffer of at least size nal->i_payload*3/2 + 5 + 64. + * 2) Call x264_nal_encode( h, dst, nal ), where dst is the output buffer. + * After these steps, the content of nal is valid and can be used in the same way as if + * the NAL unit were output by x264_encoder_encode. + * + * This does not need to be synchronous with the encoding process: the data pointed to + * by nal (both before and after x264_nal_encode) will remain valid until the next + * x264_encoder_encode call. The callback must be re-entrant. + * + * This callback does not work with frame-based threads; threads must be disabled + * or sliced-threads enabled. This callback also does not work as one would expect + * with HRD -- since the buffering period SEI cannot be calculated until the frame + * is finished encoding, it will not be sent via this callback. + * + * Note also that the NALs are not necessarily returned in order when sliced threads is + * enabled. Accordingly, the variable i_first_mb and i_last_mb are available in + * x264_nal_t to help the calling application reorder the slices if necessary. + * + * When this callback is enabled, x264_encoder_encode does not return valid NALs; + * the calling application is expected to acquire all output NALs through the callback. + * + * It is generally sensible to combine this callback with a use of slice-max-mbs or + * slice-max-size. + * + * The opaque pointer is the opaque pointer from the input frame associated with this + * NAL unit. This helps distinguish between nalu_process calls from different sources, + * e.g. if doing multiple encodes in one process. + */ + void (*nalu_process)( x264_t *h, x264_nal_t *nal, void *opaque ); +} x264_param_t; + +void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal ); + +/**************************************************************************** + * H.264 level restriction information + ****************************************************************************/ + +typedef struct x264_level_t +{ + uint8_t level_idc; + uint32_t mbps; /* max macroblock processing rate (macroblocks/sec) */ + uint32_t frame_size; /* max frame size (macroblocks) */ + uint32_t dpb; /* max decoded picture buffer (mbs) */ + uint32_t bitrate; /* max bitrate (kbit/sec) */ + uint32_t cpb; /* max vbv buffer (kbit) */ + uint16_t mv_range; /* max vertical mv component range (pixels) */ + uint8_t mvs_per_2mb; /* max mvs per 2 consecutive mbs. */ + uint8_t slice_rate; /* ?? */ + uint8_t mincr; /* min compression ratio */ + uint8_t bipred8x8; /* limit bipred to >=8x8 */ + uint8_t direct8x8; /* limit b_direct to >=8x8 */ + uint8_t frame_only; /* forbid interlacing */ +} x264_level_t; + +/* all of the levels defined in the standard, terminated by .level_idc=0 */ +X264_API extern const x264_level_t x264_levels[]; + +/**************************************************************************** + * Basic parameter handling functions + ****************************************************************************/ + +/* x264_param_default: + * fill x264_param_t with default values and do CPU detection */ +void x264_param_default( x264_param_t * ); + +/* x264_param_parse: + * set one parameter by name. + * returns 0 on success, or returns one of the following errors. + * note: BAD_VALUE occurs only if it can't even parse the value, + * numerical range is not checked until x264_encoder_open() or + * x264_encoder_reconfig(). + * value=NULL means "true" for boolean options, but is a BAD_VALUE for non-booleans. */ +#define X264_PARAM_BAD_NAME (-1) +#define X264_PARAM_BAD_VALUE (-2) +int x264_param_parse( x264_param_t *, const char *name, const char *value ); + +/**************************************************************************** + * Advanced parameter handling functions + ****************************************************************************/ + +/* These functions expose the full power of x264's preset-tune-profile system for + * easy adjustment of large numbers of internal parameters. + * + * In order to replicate x264CLI's option handling, these functions MUST be called + * in the following order: + * 1) x264_param_default_preset + * 2) Custom user options (via param_parse or directly assigned variables) + * 3) x264_param_apply_fastfirstpass + * 4) x264_param_apply_profile + * + * Additionally, x264CLI does not apply step 3 if the preset chosen is "placebo" + * or --slow-firstpass is set. */ + +/* x264_param_default_preset: + * The same as x264_param_default, but also use the passed preset and tune + * to modify the default settings. + * (either can be NULL, which implies no preset or no tune, respectively) + * + * Currently available presets are, ordered from fastest to slowest: */ +static const char * const x264_preset_names[] = { "ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow", "placebo", 0 }; + +/* The presets can also be indexed numerically, as in: + * x264_param_default_preset( ¶m, "3", ... ) + * with ultrafast mapping to "0" and placebo mapping to "9". This mapping may + * of course change if new presets are added in between, but will always be + * ordered from fastest to slowest. + * + * Warning: the speed of these presets scales dramatically. Ultrafast is a full + * 100 times faster than placebo! + * + * Currently available tunings are: */ +static const char * const x264_tune_names[] = { "film", "animation", "grain", "stillimage", "psnr", "ssim", "fastdecode", "zerolatency", 0 }; + +/* Multiple tunings can be used if separated by a delimiter in ",./-+", + * however multiple psy tunings cannot be used. + * film, animation, grain, stillimage, psnr, and ssim are psy tunings. + * + * returns 0 on success, negative on failure (e.g. invalid preset/tune name). */ +int x264_param_default_preset( x264_param_t *, const char *preset, const char *tune ); + +/* x264_param_apply_fastfirstpass: + * If first-pass mode is set (rc.b_stat_read == 0, rc.b_stat_write == 1), + * modify the encoder settings to disable options generally not useful on + * the first pass. */ +void x264_param_apply_fastfirstpass( x264_param_t * ); + +/* x264_param_apply_profile: + * Applies the restrictions of the given profile. + * Currently available profiles are, from most to least restrictive: */ +static const char * const x264_profile_names[] = { "baseline", "main", "high", "high10", "high422", "high444", 0 }; + +/* (can be NULL, in which case the function will do nothing) + * + * Does NOT guarantee that the given profile will be used: if the restrictions + * of "High" are applied to settings that are already Baseline-compatible, the + * stream will remain baseline. In short, it does not increase settings, only + * decrease them. + * + * returns 0 on success, negative on failure (e.g. invalid profile name). */ +int x264_param_apply_profile( x264_param_t *, const char *profile ); + +/**************************************************************************** + * Picture structures and functions + ****************************************************************************/ + +/* x264_bit_depth: + * Specifies the number of bits per pixel that x264 uses. This is also the + * bit depth that x264 encodes in. If this value is > 8, x264 will read + * two bytes of input data for each pixel sample, and expect the upper + * (16-x264_bit_depth) bits to be zero. + * Note: The flag X264_CSP_HIGH_DEPTH must be used to specify the + * colorspace depth as well. */ +X264_API extern const int x264_bit_depth; + +/* x264_chroma_format: + * Specifies the chroma formats that x264 supports encoding. When this + * value is non-zero, then it represents a X264_CSP_* that is the only + * chroma format that x264 supports encoding. If the value is 0 then + * there are no restrictions. */ +X264_API extern const int x264_chroma_format; + +enum pic_struct_e +{ + PIC_STRUCT_AUTO = 0, // automatically decide (default) + PIC_STRUCT_PROGRESSIVE = 1, // progressive frame + // "TOP" and "BOTTOM" are not supported in x264 (PAFF only) + PIC_STRUCT_TOP_BOTTOM = 4, // top field followed by bottom + PIC_STRUCT_BOTTOM_TOP = 5, // bottom field followed by top + PIC_STRUCT_TOP_BOTTOM_TOP = 6, // top field, bottom field, top field repeated + PIC_STRUCT_BOTTOM_TOP_BOTTOM = 7, // bottom field, top field, bottom field repeated + PIC_STRUCT_DOUBLE = 8, // double frame + PIC_STRUCT_TRIPLE = 9, // triple frame +}; + +typedef struct x264_hrd_t +{ + double cpb_initial_arrival_time; + double cpb_final_arrival_time; + double cpb_removal_time; + + double dpb_output_time; +} x264_hrd_t; + +/* Arbitrary user SEI: + * Payload size is in bytes and the payload pointer must be valid. + * Payload types and syntax can be found in Annex D of the H.264 Specification. + * SEI payload alignment bits as described in Annex D must be included at the + * end of the payload if needed. + * The payload should not be NAL-encapsulated. + * Payloads are written first in order of input, apart from in the case when HRD + * is enabled where payloads are written after the Buffering Period SEI. */ + +typedef struct x264_sei_payload_t +{ + int payload_size; + int payload_type; + uint8_t *payload; +} x264_sei_payload_t; + +typedef struct x264_sei_t +{ + int num_payloads; + x264_sei_payload_t *payloads; + /* In: optional callback to free each payload AND x264_sei_payload_t when used. */ + void (*sei_free)( void* ); +} x264_sei_t; + +typedef struct x264_image_t +{ + int i_csp; /* Colorspace */ + int i_plane; /* Number of image planes */ + int i_stride[4]; /* Strides for each plane */ + uint8_t *plane[4]; /* Pointers to each plane */ +} x264_image_t; + +typedef struct x264_image_properties_t +{ + /* All arrays of data here are ordered as follows: + * each array contains one offset per macroblock, in raster scan order. In interlaced + * mode, top-field MBs and bottom-field MBs are interleaved at the row level. + * Macroblocks are 16x16 blocks of pixels (with respect to the luma plane). For the + * purposes of calculating the number of macroblocks, width and height are rounded up to + * the nearest 16. If in interlaced mode, height is rounded up to the nearest 32 instead. */ + + /* In: an array of quantizer offsets to be applied to this image during encoding. + * These are added on top of the decisions made by x264. + * Offsets can be fractional; they are added before QPs are rounded to integer. + * Adaptive quantization must be enabled to use this feature. Behavior if quant + * offsets differ between encoding passes is undefined. */ + float *quant_offsets; + /* In: optional callback to free quant_offsets when used. + * Useful if one wants to use a different quant_offset array for each frame. */ + void (*quant_offsets_free)( void* ); + + /* In: optional array of flags for each macroblock. + * Allows specifying additional information for the encoder such as which macroblocks + * remain unchanged. Usable flags are listed below. + * x264_param_t.analyse.b_mb_info must be set to use this, since x264 needs to track + * extra data internally to make full use of this information. + * + * Out: if b_mb_info_update is set, x264 will update this array as a result of encoding. + * + * For "MBINFO_CONSTANT", it will remove this flag on any macroblock whose decoded + * pixels have changed. This can be useful for e.g. noting which areas of the + * frame need to actually be blitted. Note: this intentionally ignores the effects + * of deblocking for the current frame, which should be fine unless one needs exact + * pixel-perfect accuracy. + * + * Results for MBINFO_CONSTANT are currently only set for P-frames, and are not + * guaranteed to enumerate all blocks which haven't changed. (There may be false + * negatives, but no false positives.) + */ + uint8_t *mb_info; + /* In: optional callback to free mb_info when used. */ + void (*mb_info_free)( void* ); + + /* The macroblock is constant and remains unchanged from the previous frame. */ + #define X264_MBINFO_CONSTANT (1<<0) + /* More flags may be added in the future. */ + + /* Out: SSIM of the the frame luma (if x264_param_t.b_ssim is set) */ + double f_ssim; + /* Out: Average PSNR of the frame (if x264_param_t.b_psnr is set) */ + double f_psnr_avg; + /* Out: PSNR of Y, U, and V (if x264_param_t.b_psnr is set) */ + double f_psnr[3]; + + /* Out: Average effective CRF of the encoded frame */ + double f_crf_avg; +} x264_image_properties_t; + +typedef struct x264_picture_t +{ + /* In: force picture type (if not auto) + * If x264 encoding parameters are violated in the forcing of picture types, + * x264 will correct the input picture type and log a warning. + * Out: type of the picture encoded */ + int i_type; + /* In: force quantizer for != X264_QP_AUTO */ + int i_qpplus1; + /* In: pic_struct, for pulldown/doubling/etc...used only if b_pic_struct=1. + * use pic_struct_e for pic_struct inputs + * Out: pic_struct element associated with frame */ + int i_pic_struct; + /* Out: whether this frame is a keyframe. Important when using modes that result in + * SEI recovery points being used instead of IDR frames. */ + int b_keyframe; + /* In: user pts, Out: pts of encoded picture (user)*/ + int64_t i_pts; + /* Out: frame dts. When the pts of the first frame is close to zero, + * initial frames may have a negative dts which must be dealt with by any muxer */ + int64_t i_dts; + /* In: custom encoding parameters to be set from this frame forwards + (in coded order, not display order). If NULL, continue using + parameters from the previous frame. Some parameters, such as + aspect ratio, can only be changed per-GOP due to the limitations + of H.264 itself; in this case, the caller must force an IDR frame + if it needs the changed parameter to apply immediately. */ + x264_param_t *param; + /* In: raw image data */ + /* Out: reconstructed image data. x264 may skip part of the reconstruction process, + e.g. deblocking, in frames where it isn't necessary. To force complete + reconstruction, at a small speed cost, set b_full_recon. */ + x264_image_t img; + /* In: optional information to modify encoder decisions for this frame + * Out: information about the encoded frame */ + x264_image_properties_t prop; + /* Out: HRD timing information. Output only when i_nal_hrd is set. */ + x264_hrd_t hrd_timing; + /* In: arbitrary user SEI (e.g subtitles, AFDs) */ + x264_sei_t extra_sei; + /* private user data. copied from input to output frames. */ + void *opaque; +} x264_picture_t; + +/* x264_picture_init: + * initialize an x264_picture_t. Needs to be done if the calling application + * allocates its own x264_picture_t as opposed to using x264_picture_alloc. */ +void x264_picture_init( x264_picture_t *pic ); + +/* x264_picture_alloc: + * alloc data for a picture. You must call x264_picture_clean on it. + * returns 0 on success, or -1 on malloc failure or invalid colorspace. */ +int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height ); + +/* x264_picture_clean: + * free associated resource for a x264_picture_t allocated with + * x264_picture_alloc ONLY */ +void x264_picture_clean( x264_picture_t *pic ); + +/**************************************************************************** + * Encoder functions + ****************************************************************************/ + +/* Force a link error in the case of linking against an incompatible API version. + * Glue #defines exist to force correct macro expansion; the final output of the macro + * is x264_encoder_open_##X264_BUILD (for purposes of dlopen). */ +#define x264_encoder_glue1(x,y) x##y +#define x264_encoder_glue2(x,y) x264_encoder_glue1(x,y) +#define x264_encoder_open x264_encoder_glue2(x264_encoder_open_,X264_BUILD) + +/* x264_encoder_open: + * create a new encoder handler, all parameters from x264_param_t are copied */ +x264_t *x264_encoder_open( x264_param_t * ); + +/* x264_encoder_reconfig: + * various parameters from x264_param_t are copied. + * this takes effect immediately, on whichever frame is encoded next; + * due to delay, this may not be the next frame passed to encoder_encode. + * if the change should apply to some particular frame, use x264_picture_t->param instead. + * returns 0 on success, negative on parameter validation error. + * not all parameters can be changed; see the actual function for a detailed breakdown. + * + * since not all parameters can be changed, moving from preset to preset may not always + * fully copy all relevant parameters, but should still work usably in practice. however, + * more so than for other presets, many of the speed shortcuts used in ultrafast cannot be + * switched out of; using reconfig to switch between ultrafast and other presets is not + * recommended without a more fine-grained breakdown of parameters to take this into account. */ +int x264_encoder_reconfig( x264_t *, x264_param_t * ); +/* x264_encoder_parameters: + * copies the current internal set of parameters to the pointer provided + * by the caller. useful when the calling application needs to know + * how x264_encoder_open has changed the parameters, or the current state + * of the encoder after multiple x264_encoder_reconfig calls. + * note that the data accessible through pointers in the returned param struct + * (e.g. filenames) should not be modified by the calling application. */ +void x264_encoder_parameters( x264_t *, x264_param_t * ); +/* x264_encoder_headers: + * return the SPS and PPS that will be used for the whole stream. + * *pi_nal is the number of NAL units outputted in pp_nal. + * returns the number of bytes in the returned NALs. + * returns negative on error. + * the payloads of all output NALs are guaranteed to be sequential in memory. */ +int x264_encoder_headers( x264_t *, x264_nal_t **pp_nal, int *pi_nal ); +/* x264_encoder_encode: + * encode one picture. + * *pi_nal is the number of NAL units outputted in pp_nal. + * returns the number of bytes in the returned NALs. + * returns negative on error and zero if no NAL units returned. + * the payloads of all output NALs are guaranteed to be sequential in memory. */ +int x264_encoder_encode( x264_t *, x264_nal_t **pp_nal, int *pi_nal, x264_picture_t *pic_in, x264_picture_t *pic_out ); +/* x264_encoder_close: + * close an encoder handler */ +void x264_encoder_close( x264_t * ); +/* x264_encoder_delayed_frames: + * return the number of currently delayed (buffered) frames + * this should be used at the end of the stream, to know when you have all the encoded frames. */ +int x264_encoder_delayed_frames( x264_t * ); +/* x264_encoder_maximum_delayed_frames( x264_t *h ): + * return the maximum number of delayed (buffered) frames that can occur with the current + * parameters. */ +int x264_encoder_maximum_delayed_frames( x264_t *h ); +/* x264_encoder_intra_refresh: + * If an intra refresh is not in progress, begin one with the next P-frame. + * If an intra refresh is in progress, begin one as soon as the current one finishes. + * Requires that b_intra_refresh be set. + * + * Useful for interactive streaming where the client can tell the server that packet loss has + * occurred. In this case, keyint can be set to an extremely high value so that intra refreshes + * only occur when calling x264_encoder_intra_refresh. + * + * In multi-pass encoding, if x264_encoder_intra_refresh is called differently in each pass, + * behavior is undefined. + * + * Should not be called during an x264_encoder_encode. */ +void x264_encoder_intra_refresh( x264_t * ); +/* x264_encoder_invalidate_reference: + * An interactive error resilience tool, designed for use in a low-latency one-encoder-few-clients + * system. When the client has packet loss or otherwise incorrectly decodes a frame, the encoder + * can be told with this command to "forget" the frame and all frames that depend on it, referencing + * only frames that occurred before the loss. This will force a keyframe if no frames are left to + * reference after the aforementioned "forgetting". + * + * It is strongly recommended to use a large i_dpb_size in this case, which allows the encoder to + * keep around extra, older frames to fall back on in case more recent frames are all invalidated. + * Unlike increasing i_frame_reference, this does not increase the number of frames used for motion + * estimation and thus has no speed impact. It is also recommended to set a very large keyframe + * interval, so that keyframes are not used except as necessary for error recovery. + * + * x264_encoder_invalidate_reference is not currently compatible with the use of B-frames or intra + * refresh. + * + * In multi-pass encoding, if x264_encoder_invalidate_reference is called differently in each pass, + * behavior is undefined. + * + * Should not be called during an x264_encoder_encode, but multiple calls can be made simultaneously. + * + * Returns 0 on success, negative on failure. */ +int x264_encoder_invalidate_reference( x264_t *, int64_t pts ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/golang.org/x/sys/windows/svc/go12.c b/vendor/golang.org/x/sys/windows/svc/go12.c new file mode 100644 index 00000000..6f1be1fa --- /dev/null +++ b/vendor/golang.org/x/sys/windows/svc/go12.c @@ -0,0 +1,24 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows +// +build !go1.3 + +// copied from pkg/runtime +typedef unsigned int uint32; +typedef unsigned long long int uint64; +#ifdef _64BIT +typedef uint64 uintptr; +#else +typedef uint32 uintptr; +#endif + +// from sys_386.s or sys_amd64.s +void ·servicemain(void); + +void +·getServiceMain(uintptr *r) +{ + *r = (uintptr)·servicemain; +}