Merge branch 'master' into research Change-Id: Ifbb534b387dfd78a2eab0a3c32cefc4ee5bc82e5
diff --git a/.gitattributes b/.gitattributes index ffc6912..0bb5faf 100644 --- a/.gitattributes +++ b/.gitattributes
@@ -16,3 +16,8 @@ *.pjt -crlf *.vcp -crlf *.inf -crlf +# fft2d is not available through git, and the code +# is checked in verbatim. Do not apply diffing to +# it, otherwise it fails the 'git diff HEAD^ --check' +# test. +third_party/tensorflow_dependencies/fft2d/** -diff
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..fae903e --- /dev/null +++ b/.gitmodules
@@ -0,0 +1,27 @@ +[submodule "third_party/tensorflow"] + path = third_party/tensorflow + url = https://github.com/tensorflow/tensorflow.git +[submodule "third_party/tensorflow_dependencies/absl"] + path = third_party/tensorflow_dependencies/absl + url = https://github.com/abseil/abseil-cpp.git +[submodule "third_party/tensorflow_dependencies/neon_2_sse"] + path = third_party/tensorflow_dependencies/neon_2_sse + url = https://github.com/intel/ARM_NEON_2_x86_SSE.git +[submodule "third_party/tensorflow_dependencies/farmhash"] + path = third_party/tensorflow_dependencies/farmhash + url = https://github.com/google/farmhash +[submodule "third_party/tensorflow_dependencies/eigen"] + path = third_party/tensorflow_dependencies/eigen + url = https://gitlab.com/libeigen/eigen.git +[submodule "third_party/tensorflow_dependencies/flatbuffers"] + path = third_party/tensorflow_dependencies/flatbuffers + url = https://github.com/google/flatbuffers +[submodule "third_party/tensorflow_dependencies/gemmlowp"] + path = third_party/tensorflow_dependencies/gemmlowp + url = https://github.com/google/gemmlowp.git +[submodule "third_party/tensorflow_dependencies/fp16"] + path = third_party/tensorflow_dependencies/fp16 + url = https://github.com/Maratyszcza/FP16.git +[submodule "third_party/tensorflow_dependencies/ruy"] + path = third_party/tensorflow_dependencies/ruy + url = https://github.com/google/ruy.git
diff --git a/CMakeLists.txt b/CMakeLists.txt index 80b6d27..bc8f91d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -155,12 +155,18 @@ "${AOM_ROOT}/common/warnings.h" "${AOM_ROOT}/common/y4minput.c" "${AOM_ROOT}/common/y4minput.h" + "${AOM_ROOT}/common/stream_iter.c" "${AOM_ROOT}/examples/encoder_util.h" "${AOM_ROOT}/examples/encoder_util.c") -list(APPEND AOM_ENCODER_STATS_SOURCES "${AOM_ROOT}/stats/aomstats.c" - "${AOM_ROOT}/stats/aomstats.h" "${AOM_ROOT}/stats/rate_hist.c" - "${AOM_ROOT}/stats/rate_hist.h") +if(CONFIG_SINGLEPASS) + list(APPEND AOM_ENCODER_STATS_SOURCES "${AOM_ROOT}/stats/rate_hist.c" + "${AOM_ROOT}/stats/rate_hist.h") +else() + list(APPEND AOM_ENCODER_STATS_SOURCES "${AOM_ROOT}/stats/aomstats.c" + "${AOM_ROOT}/stats/aomstats.h" "${AOM_ROOT}/stats/rate_hist.c" + "${AOM_ROOT}/stats/rate_hist.h") +endif() list(APPEND AOM_VERSION_SOURCES "${AOM_CONFIG_DIR}/config/aom_version.h") @@ -598,6 +604,23 @@ endif() endif() +if(CONFIG_TENSORFLOW_LITE) + include("${AOM_ROOT}/build/cmake/tensorflow_lite.cmake") + setup_tensorflow_lite() + + if(ENABLE_EXAMPLES) + add_executable(tf_lite_model "${AOM_ROOT}/examples/tf_lite_model.cc") + list(APPEND AOM_EXAMPLE_TARGETS tf_lite_model) + list(APPEND AOM_APP_TARGETS tf_lite_model) + add_dependencies(tf_lite_model tensorflowlite_a) + target_link_libraries( + tf_lite_model + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/libtensorflow-lite.a" + PRIVATE Threads::Threads + PRIVATE ${CMAKE_DL_LIBS}) + endif() +endif() + if(ENABLE_EXAMPLES AND "${CMAKE_GENERATOR}" MATCHES "Makefiles$") # For historical purposes place the example binaries in the example directory.
diff --git a/Sample.cfg b/Sample.cfg index d5dbe66..6092813 100644 --- a/Sample.cfg +++ b/Sample.cfg
@@ -1,35 +1,35 @@ #sample config file -super_block_size = 128 # super block size. 0, 64 or 128 +superblock_size = 128 # super block size. 0, 64 or 128 max_partition_size = 128 # max partition size(8, 16, 32, 64, 128) min_partition_size = 4 # min partition size(4, 8, 16, 32, 64) -disable_rect_partition_type = 0 # disable rectangle partition type -disable_ab_partition_type = 0 # disable AB partition type -disable_1to4_partition_type = 0 # disable 1 to 4 and 4 to 1 partition type -disable_intra_angle_delta = 0 # disable intra angle delta -disable_paeth_intra = 0 # disable paeth intra -disable_smooth_intra = 0 # disable intra smooth mode -disable_intra_edge_filter = 0 # disable intra edge filter -disable_filter_intra = 0 # disable filter intra -disable_intrabc = 0 # disable Intra Block Copy -disable_cfl = 0 # disable chroma from luma prediction -disable_palette = 0 # disable Palette -disable_flip_idtx = 0 # disable flip and identity transform -disable_tx_64x64 = 0 # disable 64x64 transform +enable_rect_partitions = 1 # enable rectangle partition type +enable_ab_partitions = 1 # enable AB partition type +enable_1to4_partitions = 1 # enable 1 to 4 and 4 to 1 partition type +enable_angle_delta = 1 # enable intra angle delta +enable_paeth_intra = 1 # enable paeth intra +enable_smooth_intra = 1 # enable intra smooth mode +enable_intra_edge_filter = 1 # enable intra edge filter +enable_filter_intra = 1 # enable filter intra +enable_intrabc = 1 # enable Intra Block Copy +enable_cfl_intra = 1 # enable chroma from luma prediction +enable_palette = 1 # enable Palette +enable_flip_idtx = 1 # enable flip and identity transform +enable_tx64 = 1 # enable 64x64 transform reduced_tx_type_set = 0 # use reduced transform type set -reduced_reference_set = 0 # use reduced reference frame set -disable_obmc = 0 # disable OBMC -disable_warp_motion = 0 # disable Warped Motion -disable_global_motion = 0 # disable global motion -disable_ref_frame_mv = 0 # disable ref mv -disable_dual_filter = 0 # disable dual interpolation filter -disable_one_sided_comp = 0 # disable one sided compound mode -disable_masked_comp = 0 # disable masked compound prediction -disable_diff_wtd_comp = 0 # disable difference weighted compound mode -disable_inter_inter_wedge = 0 # disable inter/inter wedge comp -disable_dist_wtd_comp = 0 # disable distant weighted compound mode -disable_inter_intra_comp = 0 # disable inter/intra compound mode. -disable_inter_intra_wedge = 0 # disable inter/intra wedge comp -disable_smooth_inter_intra = 0 # disable smooth inter/intra -disable_cdef = 0 # disable CDEF filter -disable_lr = 0 # disable Loop Restoration Filter -disable_trellis_quant = 0 # disable trellis quantization \ No newline at end of file +enable_reduced_reference_set = 0 # use reduced reference frame set +enable_obmc = 1 # enable OBMC +enable_warped_motion = 1 # enable Warped Motion +enable_global_motion = 1 # enable global motion +enable_ref_frame_mvs = 1 # enable ref mv +enable_dual_filter = 1 # enable dual interpolation filter +enable_onesided_comp = 1 # enable one sided compound mode +enable_masked_comp = 1 # enable masked compound prediction +enable_diff_wtd_comp = 1 # enable difference weighted compound mode +enable_interinter_wedge = 1 # enable inter/inter wedge comp +enable_dist_wtd_comp = 1 # enable distant weighted compound mode +enable_interintra_comp = 1 # enable inter/intra compound mode. +enable_interintra_wedge = 1 # enable inter/intra wedge comp +enable_smooth_interintra = 1 # enable smooth inter/intra +enable_cdef = 1 # enable CDEF filter +enable_restoration = 1 # enable Loop Restoration Filter +disable_trellis_quant = 0 # enable trellis quantization \ No newline at end of file
diff --git a/aom/aom_encoder.h b/aom/aom_encoder.h index f36dc4e..5509c3f 100644 --- a/aom/aom_encoder.h +++ b/aom/aom_encoder.h
@@ -30,6 +30,7 @@ extern "C" { #endif +#include "config/aom_config.h" #include "aom/aom_codec.h" /*!\brief Current ABI version number @@ -68,6 +69,8 @@ #define AOM_CODEC_USE_PSNR 0x10000 /**< Calculate PSNR on each frame */ /*!\brief Make the encoder output one partition at a time. */ #define AOM_CODEC_USE_HIGHBITDEPTH 0x40000 /**< Use high bitdepth */ +/*!\brief Print per frame stats. */ +#define AOM_CODEC_USE_PER_FRAME_STATS 0x80000 /**< Enable printing of stats */ /*!\brief Generic fixed size buffer structure * @@ -210,7 +213,7 @@ /*!\brief Superblock size * 0, 64 or 128 */ - unsigned int super_block_size; + unsigned int superblock_size; /*!\brief max partition size * 8, 16, 32, 64, 128 */ @@ -219,126 +222,126 @@ * 8, 16, 32, 64, 128 */ unsigned int min_partition_size; - /*!\brief disable AB Shape partition type + /*!\brief enable AB Shape partition type * */ - unsigned int disable_ab_partition_type; - /*!\brief disable rectangular partition type + unsigned int enable_ab_partitions; + /*!\brief enable rectangular partition type * */ - unsigned int disable_rect_partition_type; - /*!\brief disable 1:4/4:1 partition type + unsigned int enable_rect_partitions; + /*!\brief enable 1:4/4:1 partition type * */ - unsigned int disable_1to4_partition_type; - /*!\brief disable flip and identity transform type + unsigned int enable_1to4_partitions; + /*!\brief enable flip and identity transform type * */ - unsigned int disable_flip_idtx; - /*!\brief disable CDEF filter + unsigned int enable_flip_idtx; + /*!\brief enable CDEF filter * */ - unsigned int disable_cdef; - /*!\brief disable Loop Restoration Filter + unsigned int enable_cdef; + /*!\brief enable Loop Restoration Filter * */ - unsigned int disable_lr; - /*!\brief disable OBMC + unsigned int enable_restoration; + /*!\brief enable OBMC * */ - unsigned int disable_obmc; - /*!\brief disable Warped Motion + unsigned int enable_obmc; + /*!\brief enable Warped Motion * */ - unsigned int disable_warp_motion; - /*!\brief disable global motion + unsigned int enable_warped_motion; + /*!\brief enable global motion * */ - unsigned int disable_global_motion; - /*!\brief disable dist weighted compound + unsigned int enable_global_motion; + /*!\brief enable dist weighted compound * */ - unsigned int disable_dist_wtd_comp; - /*!\brief disable diff weighted compound + unsigned int enable_dist_wtd_comp; + /*!\brief enable diff weighted compound * */ - unsigned int disable_diff_wtd_comp; - /*!\brief disable inter/intra compound + unsigned int enable_diff_wtd_comp; + /*!\brief enable inter/intra compound * */ - unsigned int disable_inter_intra_comp; - /*!\brief disable masked compound + unsigned int enable_interintra_comp; + /*!\brief enable masked compound * */ - unsigned int disable_masked_comp; - /*!\brief disable one sided compound + unsigned int enable_masked_comp; + /*!\brief enable one sided compound * */ - unsigned int disable_one_sided_comp; - /*!\brief disable Palette + unsigned int enable_onesided_comp; + /*!\brief enable Palette * */ - unsigned int disable_palette; - /*!\brief disable Intra Block Copy + unsigned int enable_palette; + /*!\brief enable Intra Block Copy * */ - unsigned int disable_intrabc; - /*!\brief disable chroma from luma + unsigned int enable_intrabc; + /*!\brief enable chroma from luma * */ - unsigned int disable_cfl; - /*!\brief disable intra smooth mode + unsigned int enable_cfl_intra; + /*!\brief enable intra smooth mode * */ - unsigned int disable_smooth_intra; - /*!\brief disable filter intra + unsigned int enable_smooth_intra; + /*!\brief enable filter intra * */ - unsigned int disable_filter_intra; - /*!\brief disable dual filter + unsigned int enable_filter_intra; + /*!\brief enable dual filter * */ - unsigned int disable_dual_filter; - /*!\brief disable intra angle delta + unsigned int enable_dual_filter; + /*!\brief enable intra angle delta * */ - unsigned int disable_intra_angle_delta; - /*!\brief disable intra edge filter + unsigned int enable_angle_delta; + /*!\brief enable intra edge filter * */ - unsigned int disable_intra_edge_filter; - /*!\brief disable 64x64 transform + unsigned int enable_intra_edge_filter; + /*!\brief enable 64x64 transform * */ - unsigned int disable_tx_64x64; - /*!\brief disable smooth inter/intra + unsigned int enable_tx64; + /*!\brief enable smooth inter/intra * */ - unsigned int disable_smooth_inter_intra; - /*!\brief disable inter/inter wedge comp + unsigned int enable_smooth_interintra; + /*!\brief enable inter/inter wedge comp * */ - unsigned int disable_inter_inter_wedge; - /*!\brief disable inter/intra wedge comp + unsigned int enable_interinter_wedge; + /*!\brief enable inter/intra wedge comp * */ - unsigned int disable_inter_intra_wedge; - /*!\brief disable paeth intra + unsigned int enable_interintra_wedge; + /*!\brief enable paeth intra * */ - unsigned int disable_paeth_intra; - /*!\brief disable trellis quantization + unsigned int enable_paeth_intra; + /*!\brief enable trellis quantization * */ unsigned int disable_trellis_quant; - /*!\brief disable ref frame MV + /*!\brief enable ref frame MV * */ - unsigned int disable_ref_frame_mv; + unsigned int enable_ref_frame_mvs; /*!\brief use reduced reference frame set * */ - unsigned int reduced_reference_set; + unsigned int enable_reduced_reference_set; /*!\brief use reduced transform type set * */ @@ -570,7 +573,7 @@ /*!\brief Frame super-resolution q threshold. * * The q level threshold after which superres is used. - * Valid values are 1 to 63. + * Valid values are 1 to 255. * * Used only by AOM_SUPERRES_QTHRESH */ @@ -579,7 +582,7 @@ /*!\brief Keyframe super-resolution q threshold. * * The q level threshold after which superres is used for key frames. - * Valid values are 1 to 63. + * Valid values are 1 to 255. * * Used only by AOM_SUPERRES_QTHRESH */ @@ -595,12 +598,14 @@ */ enum aom_rc_mode rc_end_usage; +#if !CONFIG_SINGLEPASS /*!\brief Two-pass stats buffer. * * A buffer containing all of the stats packets produced in the first * pass, concatenated. */ aom_fixed_buf_t rc_twopass_stats_in; +#endif // !CONFIG_SINGLEPASS /*!\brief first pass mb stats buffer. * @@ -698,6 +703,7 @@ * 2 pass rate control parameters */ +#if !CONFIG_SINGLEPASS /*!\brief Two-pass mode CBR/VBR bias * * Bias, expressed on a scale of 0 to 100, for determining target size @@ -707,6 +713,7 @@ * encoder should "lean." */ unsigned int rc_2pass_vbr_bias_pct; +#endif // !CONFIG_SINGLEPASS /*!\brief Two-pass mode per-GOP minimum bitrate * @@ -859,7 +866,7 @@ * at different levels of the pyramid. * - If 'fixed_qp_offsets' is also provided, encoder will use the given * offsets - * - If not, encoder will select the fixed offsets based on the cq-level + * - If not, encoder will select the fixed offsets based on the --qp * provided. * If a value of 0 is provided and fixed_qp_offset are not provided, encoder * will NOT use fixed QP offsets. @@ -875,7 +882,7 @@ /*!\brief Array of fixed QP offsets * - * This array specifies fixed QP offsets (range: 0 to 63) for frames at + * This array specifies fixed QP offsets (range: 0 to 255) for frames at * different levels of the pyramid. It is a comma-separated list of 5 values: * - QP offset for keyframe * - QP offset for ALTREF frame @@ -884,7 +891,7 @@ * - QP offset for 3rd level internal ARF * Notes: * - QP offset for leaf level frames is not explicitly specified. These frames - * use the worst quality allowed (--cq-level). + * use the worst quality allowed (--qp). * - This option is only relevant for --end-usage=q. */ int fixed_qp_offsets[FIXED_QP_OFFSET_COUNT];
diff --git a/aom/aomcx.h b/aom/aomcx.h index ac69d46..6d852ba 100644 --- a/aom/aomcx.h +++ b/aom/aomcx.h
@@ -227,14 +227,6 @@ */ AOME_GET_LAST_QUANTIZER = AOME_SET_STATIC_THRESHOLD + 2, // 19 - /*!\brief Codec control function to get last quantizer chosen by the encoder, - * int* parameter - * - * Return value uses the 0..63 scale as used by the rc_*_quantizer config - * parameters. - */ - AOME_GET_LAST_QUANTIZER_64 = 20, - /*!\brief Codec control function to set the max no of frames to create arf, * unsigned int parameter */ @@ -255,12 +247,12 @@ /*!\brief Codec control function to set constrained / constant quality level, * unsigned int parameter * - * Valid range: 0..63 + * Valid range: 0..255 * * \attention For this value to be used aom_codec_enc_cfg_t::rc_end_usage * must be set to #AOM_CQ or #AOM_Q. */ - AOME_SET_CQ_LEVEL = 25, + AOME_SET_QP = 25, /*!\brief Codec control function to set max data rate for intra frames, * unsigned int parameter @@ -1270,9 +1262,17 @@ */ AV1E_SET_VBR_CORPUS_COMPLEXITY_LAP = 157, + /*!\brief Control to set the subgop config string. + */ + AV1E_SET_SUBGOP_CONFIG_STR = 158, + + /*!\brief Control to set the subgop config path. + */ + AV1E_SET_SUBGOP_CONFIG_PATH = 159, + /*!\brief Control to get baseline gf interval */ - AV1E_GET_BASELINE_GF_INTERVAL = 158, + AV1E_GET_BASELINE_GF_INTERVAL = 160, }; /*!\brief aom 1-D scaling mode @@ -1452,8 +1452,8 @@ AOM_CTRL_USE_TYPE(AOME_SET_TUNING, int) /* aom_tune_metric */ #define AOM_CTRL_AOME_SET_TUNING -AOM_CTRL_USE_TYPE(AOME_SET_CQ_LEVEL, unsigned int) -#define AOM_CTRL_AOME_SET_CQ_LEVEL +AOM_CTRL_USE_TYPE(AOME_SET_QP, unsigned int) +#define AOM_CTRL_AOME_SET_QP AOM_CTRL_USE_TYPE(AV1E_SET_ROW_MT, unsigned int) #define AOM_CTRL_AV1E_SET_ROW_MT @@ -1473,9 +1473,6 @@ AOM_CTRL_USE_TYPE(AOME_GET_LAST_QUANTIZER, int *) #define AOM_CTRL_AOME_GET_LAST_QUANTIZER -AOM_CTRL_USE_TYPE(AOME_GET_LAST_QUANTIZER_64, int *) -#define AOM_CTRL_AOME_GET_LAST_QUANTIZER_64 - AOM_CTRL_USE_TYPE(AOME_SET_MAX_INTRA_BITRATE_PCT, unsigned int) #define AOM_CTRL_AOME_SET_MAX_INTRA_BITRATE_PCT @@ -1791,6 +1788,12 @@ AOM_CTRL_USE_TYPE(AV1E_SET_VBR_CORPUS_COMPLEXITY_LAP, unsigned int) #define AOM_CTRL_AV1E_SET_VBR_CORPUS_COMPLEXITY_LAP +AOM_CTRL_USE_TYPE(AV1E_SET_SUBGOP_CONFIG_STR, const char *) +#define AOM_CTRL_AV1E_SET_SUBGOP_CONFIG_STR + +AOM_CTRL_USE_TYPE(AV1E_SET_SUBGOP_CONFIG_PATH, const char *) +#define AOM_CTRL_AV1E_SET_SUBGOP_CONFIG_PATH + /*!\endcond */ /*! @} - end defgroup aom_encoder */ #ifdef __cplusplus
diff --git a/aom/src/aom_encoder.c b/aom/src/aom_encoder.c index bb51c93..a998fbd 100644 --- a/aom/src/aom_encoder.c +++ b/aom/src/aom_encoder.c
@@ -91,7 +91,7 @@ /* default values */ if (cfg) { memset(&cfg->encoder_cfg, 0, sizeof(cfg->encoder_cfg)); - cfg->encoder_cfg.super_block_size = 0; // Dynamic + cfg->encoder_cfg.superblock_size = 0; // Dynamic cfg->encoder_cfg.max_partition_size = 128; cfg->encoder_cfg.min_partition_size = 4; cfg->encoder_cfg.disable_trellis_quant = 3;
diff --git a/apps/aomenc.c b/apps/aomenc.c index 581dff9..958913d 100644 --- a/apps/aomenc.c +++ b/apps/aomenc.c
@@ -11,12 +11,11 @@ #include "apps/aomenc.h" -#include "config/aom_config.h" - #include <assert.h> #include <limits.h> #include <math.h> #include <stdarg.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -34,6 +33,8 @@ #include "aom_ports/mem_ops.h" #include "common/args.h" #include "common/ivfenc.h" +#include "common/rawenc.h" +#include "common/stream_iter.h" #include "common/tools_common.h" #include "common/warnings.h" @@ -43,13 +44,23 @@ #include "common/y4minput.h" #include "examples/encoder_util.h" +#if !CONFIG_SINGLEPASS #include "stats/aomstats.h" +#endif // !CONFIG_SINGLEPASS #include "stats/rate_hist.h" #if CONFIG_LIBYUV #include "third_party/libyuv/include/libyuv/scale.h" #endif +#if UINTPTR_MAX == 0xffffffff +#define ENV_BITS "32 bit " +#elif UINTPTR_MAX == 0xffffffffffffffff +#define ENV_BITS "64 bit " +#else +#define ENV_BITS "unknown bit " +#endif + /* Swallow warnings about unused results of fread/fwrite */ static size_t wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { return fread(ptr, size, nmemb, stream); @@ -95,20 +106,6 @@ va_end(ap); } -static int read_frame(struct AvxInputContext *input_ctx, aom_image_t *img) { - FILE *f = input_ctx->file; - y4m_input *y4m = &input_ctx->y4m; - int shortread = 0; - - if (input_ctx->file_type == FILE_TYPE_Y4M) { - if (y4m_input_fetch_frame(y4m, f, img) < 1) return 0; - } else { - shortread = read_yuv_frame(input_ctx, img); - } - - return !shortread; -} - static int file_is_y4m(const char detect[4]) { if (memcmp(detect, "YUV4", 4) == 0) { return 1; @@ -129,6 +126,7 @@ ARG_DEF("D", "debug", 0, "Debug mode (makes output deterministic)"); static const arg_def_t outputfile = ARG_DEF("o", "output", 1, "Output filename"); +static const arg_def_t reconfile = ARG_DEF(NULL, "recon", 1, "Recon filename"); static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, "Input file is YV12 "); static const arg_def_t use_i420 = @@ -138,16 +136,26 @@ static const arg_def_t use_i444 = ARG_DEF(NULL, "i444", 0, "Input file is I444"); static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, "Codec to use"); +#if CONFIG_SINGLEPASS +static const arg_def_t passes = + ARG_DEF("p", "passes", 1, "Number of passes (must be 1)"); +static const arg_def_t pass_arg = ARG_DEF( + NULL, "pass", 1, "Pass to execute (0/1). 0 (default) indicates all passes"); +#else static const arg_def_t passes = ARG_DEF("p", "passes", 1, "Number of passes (1/2)"); static const arg_def_t pass_arg = - ARG_DEF(NULL, "pass", 1, "Pass to execute (1/2)"); + ARG_DEF(NULL, "pass", 1, + "Pass to execute (0/1/2), 0 (default) indicates all passes"); +#endif // CONFIG_SINGLEPASS static const arg_def_t fpf_name = ARG_DEF(NULL, "fpf", 1, "First pass statistics file name"); static const arg_def_t limit = ARG_DEF(NULL, "limit", 1, "Stop encoding after n input frames"); static const arg_def_t skip = ARG_DEF(NULL, "skip", 1, "Skip the first n input frames"); +static const arg_def_t step = ARG_DEF( + NULL, "step", 1, "Encode every n-th frame (after the --skip frames)"); static const arg_def_t good_dl = ARG_DEF(NULL, "good", 0, "Use Good Quality Deadline"); static const arg_def_t rt_dl = @@ -204,12 +212,14 @@ &use_cfg, &debugmode, &outputfile, + &reconfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &skip, + &step, &good_dl, &rt_dl, &quietarg, @@ -320,10 +330,16 @@ ARG_DEF_ENUM(NULL, "end-usage", 1, "Rate control mode", end_usage_enum); static const arg_def_t target_bitrate = ARG_DEF(NULL, "target-bitrate", 1, "Bitrate (kbps)"); -static const arg_def_t min_quantizer = - ARG_DEF(NULL, "min-q", 1, "Minimum (best) quantizer"); -static const arg_def_t max_quantizer = - ARG_DEF(NULL, "max-q", 1, "Maximum (worst) quantizer"); +static const arg_def_t min_qp_level = + ARG_DEF(NULL, "min-qp", 1, "Minimum (best) quantizer"); +static const arg_def_t max_qp_level = + ARG_DEF(NULL, "max-qp", 1, "Maximum (worst) quantizer"); +static const arg_def_t min_q_level = ARG_DEF( + NULL, "min-q", 1, "Minimum (best) quantizer in range 0 to 63 (DEPRECATED)"); +static const arg_def_t max_q_level = + ARG_DEF(NULL, "max-q", 1, + "Maximum (worst) quantizer in range 0 to 63 (DEPRECATED)"); + static const arg_def_t undershoot_pct = ARG_DEF(NULL, "undershoot-pct", 1, "Datarate undershoot (min) target (%)"); static const arg_def_t overshoot_pct = @@ -334,8 +350,10 @@ ARG_DEF(NULL, "buf-initial-sz", 1, "Client initial buffer size (ms)"); static const arg_def_t buf_optimal_sz = ARG_DEF(NULL, "buf-optimal-sz", 1, "Client optimal buffer size (ms)"); +#if !CONFIG_SINGLEPASS static const arg_def_t bias_pct = ARG_DEF(NULL, "bias-pct", 1, "CBR/VBR bias (0=CBR, 100=VBR)"); +#endif // !CONFIG_SINGLEPASS static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1, "GOP min bitrate (% of target)"); static const arg_def_t maxsection_pct = @@ -351,14 +369,16 @@ &superres_kf_qthresh, &end_usage, &target_bitrate, - &min_quantizer, - &max_quantizer, + &min_qp_level, + &max_qp_level, &undershoot_pct, &overshoot_pct, &buf_sz, &buf_initial_sz, &buf_optimal_sz, +#if !CONFIG_SINGLEPASS &bias_pct, +#endif // !CONFIG_SINGLEPASS &minsection_pct, &maxsection_pct, NULL }; @@ -401,8 +421,11 @@ }; static const arg_def_t tune_metric = ARG_DEF_ENUM(NULL, "tune", 1, "Distortion metric tuned with", tuning_enum); +static const arg_def_t qp_level = + ARG_DEF(NULL, "qp", 1, "Constant/Constrained Quality level"); static const arg_def_t cq_level = - ARG_DEF(NULL, "cq-level", 1, "Constant/Constrained Quality level"); + ARG_DEF(NULL, "cq-level", 1, + "Constant/Constrained Quality level in range 0 to 63 (DEPRECATED)"); static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1, "Max I-frame bitrate (pct)"); @@ -806,7 +829,7 @@ static const arg_def_t use_fixed_qp_offsets = ARG_DEF(NULL, "use-fixed-qp-offsets", 1, "Enable fixed QP offsets for frames at different levels of the " - "pyramid. Selected automatically from --cq-level if " + "pyramid. Selected automatically from --qp if " "--fixed-qp-offsets is not provided. If this option is not " "specified (default), offsets are adaptively chosen by the " "encoder."); @@ -824,6 +847,20 @@ "Set average corpus complexity per mb for single pass VBR using lap. " "(0..10000), default is 0"); +static const arg_def_t subgop_config_str = + ARG_DEF(NULL, "subgop-config-str", 1, + "Set specified SubGOP configurations in string format provided " + "for various SubGOP lengths. " + "If this option is not specified (default), the configurations " + "are chosen by the encoder using a default algorithm."); + +static const arg_def_t subgop_config_path = + ARG_DEF(NULL, "subgop-config-path", 1, + "Set specified SubGOP configurations in config file path provided " + "for various SubGOP lengths. " + "If this option is not specified (default), the configurations " + "are chosen by the encoder using a default algorithm."); + static const arg_def_t *av1_args[] = { &cpu_used_av1, &auto_altref, &sharpness, @@ -836,7 +873,7 @@ &arnr_maxframes, &arnr_strength, &tune_metric, - &cq_level, + &qp_level, &max_intra_rate_pct, &max_inter_rate_pct, &gf_cbr_boost_pct, @@ -920,16 +957,11 @@ &set_tier_mask, &set_min_cr, &vbr_corpus_complexity_lap, - &bitdeptharg, - &inbitdeptharg, - &input_chroma_subsampling_x, - &input_chroma_subsampling_y, - &sframe_dist, - &sframe_mode, - &save_as_annexb, #if CONFIG_TUNE_VMAF &vmaf_model_path, #endif + &subgop_config_str, + &subgop_config_path, NULL }; static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, AOME_SET_ENABLEAUTOALTREF, @@ -943,7 +975,7 @@ AOME_SET_ARNR_MAXFRAMES, AOME_SET_ARNR_STRENGTH, AOME_SET_TUNING, - AOME_SET_CQ_LEVEL, + AOME_SET_QP, AOME_SET_MAX_INTRA_BITRATE_PCT, AV1E_SET_MAX_INTER_BITRATE_PCT, AV1E_SET_GF_CBR_BOOST_PCT, @@ -1030,6 +1062,8 @@ #if CONFIG_TUNE_VMAF AV1E_SET_VMAF_MODEL_PATH, #endif + AV1E_SET_SUBGOP_CONFIG_STR, + AV1E_SET_SUBGOP_CONFIG_PATH, 0 }; #endif // CONFIG_AV1_ENCODER @@ -1093,7 +1127,10 @@ struct stream_config { struct aom_codec_enc_cfg cfg; const char *out_fn; + const char *recon_fn; +#if !CONFIG_SINGLEPASS const char *stats_fn; +#endif // !CONFIG_SINGLEPASS stereo_format_t stereo_fmt; int arg_ctrls[ARG_CTRL_CNT_MAX][2]; int arg_ctrl_cnt; @@ -1105,6 +1142,8 @@ #if CONFIG_TUNE_VMAF const char *vmaf_model_path; #endif + const char *subgop_config_str; + const char *subgop_config_path; }; struct stream_state { @@ -1118,12 +1157,14 @@ uint64_t psnr_samples_total; double psnr_totals[4]; int psnr_count; - int counts[64]; + int counts[256]; aom_codec_ctx_t encoder; unsigned int frames_out; uint64_t cx_time; size_t nbytes; +#if !CONFIG_SINGLEPASS stats_io_t stats; +#endif // !CONFIG_SINGLEPASS struct aom_image *img; aom_codec_ctx_t decoder; int mismatch_seen; @@ -1145,7 +1186,7 @@ static void init_config(cfg_options_t *config) { memset(config, 0, sizeof(cfg_options_t)); - config->super_block_size = 0; // Dynamic + config->superblock_size = 0; // Dynamic config->max_partition_size = 128; config->min_partition_size = 4; config->disable_trellis_quant = 3; @@ -1164,9 +1205,15 @@ /* Initialize default parameters */ memset(global, 0, sizeof(*global)); global->codec = get_aom_encoder_by_index(num_encoder - 1); - global->passes = 0; + // Set default passes +#if CONFIG_SINGLEPASS + global->passes = 1; +#else + global->passes = 2; +#endif // CONFIG_SINGLEPASS global->color_type = I420; global->csp = AOM_CSP_UNKNOWN; + global->step_frames = 1; int cfg_included = 0; init_config(&global->encoder_config); @@ -1176,7 +1223,9 @@ if (arg_match(&arg, &use_cfg, argi)) { if (cfg_included) continue; - parse_cfg(arg.val, &global->encoder_config); + if (parse_cfg(arg.val, &global->encoder_config)) { + die("Reading / parsing error for config file: %s\n", arg.val); + } cfg_included = 1; continue; } @@ -1189,14 +1238,8 @@ die("Error: Unrecognized argument (%s) to --codec\n", arg.val); } else if (arg_match(&arg, &passes, argi)) { global->passes = arg_parse_uint(&arg); - - if (global->passes < 1 || global->passes > 2) - die("Error: Invalid number of passes (%d)\n", global->passes); } else if (arg_match(&arg, &pass_arg, argi)) { global->pass = arg_parse_uint(&arg); - - if (global->pass < 1 || global->pass > 2) - die("Error: Invalid pass selected (%d)\n", global->pass); } else if (arg_match(&arg, &input_chroma_sample_position, argi)) { global->csp = arg_parse_enum(&arg); /* Flag is used by later code as well, preserve it. */ @@ -1223,7 +1266,12 @@ global->limit = arg_parse_uint(&arg); else if (arg_match(&arg, &skip, argi)) global->skip_frames = arg_parse_uint(&arg); - else if (arg_match(&arg, &psnrarg, argi)) + else if (arg_match(&arg, &step, argi)) { + global->step_frames = arg_parse_uint(&arg); + if (global->step_frames == 0) { + die("--step must be positive"); + } + } else if (arg_match(&arg, &psnrarg, argi)) global->show_psnr = 1; else if (arg_match(&arg, &recontest, argi)) global->test_decode = arg_parse_enum_or_int(&arg); @@ -1245,6 +1293,22 @@ argj++; } +#if CONFIG_SINGLEPASS + if (global->passes != 1) + die("Error: Invalid number of passes (%d)\n", global->passes); +#else + if (global->passes < 1 || global->passes > 2) + die("Error: Invalid number of passes (%d)\n", global->passes); +#endif // CONFIG_SINGLEPASS +#if CONFIG_SINGLEPASS + if (global->pass < 0 || global->pass > 1) + die("Error: Invalid pass selected (%d)\n", global->pass); +#else + if (global->pass < 0 || global->pass > 2) + die("Error: Invalid pass selected (%d)\n", global->pass); +#endif // CONFIG_SINGLEPASS + +#if !CONFIG_SINGLEPASS if (global->pass) { /* DWIM: Assume the user meant passes=2 if pass=2 is specified */ if (global->pass > global->passes) { @@ -1253,26 +1317,34 @@ global->passes = global->pass; } } +#endif // !CONFIG_SINGLEPASS + /* Validate global config */ if (global->passes == 0) { #if CONFIG_AV1_ENCODER // Make default AV1 passes = 2 until there is a better quality 1-pass // encoder if (global->codec != NULL) +#if CONFIG_SINGLEPASS + global->passes = 1; +#else global->passes = (strcmp(get_short_name_by_aom_encoder(global->codec), "av1") == 0 && global->usage != AOM_USAGE_REALTIME) ? 2 : 1; +#endif // CONFIG_SINGLEPASS #else global->passes = 1; -#endif +#endif // CONFIG_AV1_ENCODER } +#if !CONFIG_SINGLEPASS if (global->usage == AOM_USAGE_REALTIME && global->passes > 1) { warn("Enforcing one-pass encoding in realtime mode\n"); global->passes = 1; } +#endif // !CONFIG_SINGLEPASS } static void open_input_file(struct AvxInputContext *input, @@ -1391,6 +1463,15 @@ return; } + if (key == AV1E_SET_SUBGOP_CONFIG_STR) { + config->subgop_config_str = arg->val; + return; + } + if (key == AV1E_SET_SUBGOP_CONFIG_PATH) { + config->subgop_config_path = arg->val; + return; + } + // For target level, the settings should accumulate rather than overwrite, // so we simply append it. if (key == AV1E_SET_TARGET_SEQ_LEVEL_IDX) { @@ -1420,6 +1501,28 @@ if (j == config->arg_ctrl_cnt) config->arg_ctrl_cnt++; } +// Converts quantizer in deprecated range 0 to 63, to qindex in range 0 to 255. +// Also prints deprecation warning. +static unsigned int get_qindex_from_quantizer_and_warn( + unsigned int quantizer, const char *quantizer_str, const char *qindex_str) { + static const int quantizer_to_qindex[] = { + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, + 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, + 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, + 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, + 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 249, 255, + }; + warn( + "Option '--%s' (range 0 to 63) is DEPRECATED and will be " + "removed in future. Use option '--%s' (range 0 to 255) instead.", + quantizer_str, qindex_str); + if (quantizer > 63) { + fprintf(stderr, "'--%s=%u' out of range (0 to 63)", quantizer_str, + quantizer); + } + return quantizer_to_qindex[quantizer]; +} + static int parse_stream_params(struct AvxEncoderConfig *global, struct stream_state *stream, char **argv) { char **argi, **argj; @@ -1469,8 +1572,10 @@ config->write_ivf = 0; } } +#if !CONFIG_SINGLEPASS } else if (arg_match(&arg, &fpf_name, argi)) { config->stats_fn = arg.val; +#endif // !CONFIG_SINGLEPASS } else if (arg_match(&arg, &use_webm, argi)) { #if CONFIG_WEBM_IO config->write_webm = 1; @@ -1478,6 +1583,8 @@ #else die("Error: --webm specified but webm is disabled."); #endif + } else if (arg_match(&arg, &reconfile, argi)) { + config->recon_fn = arg.val; } else if (arg_match(&arg, &use_ivf, argi)) { config->write_webm = 0; config->write_ivf = 1; @@ -1551,10 +1658,18 @@ config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg); } else if (arg_match(&arg, &target_bitrate, argi)) { config->cfg.rc_target_bitrate = arg_parse_uint(&arg); - } else if (arg_match(&arg, &min_quantizer, argi)) { + } else if (arg_match(&arg, &min_qp_level, argi)) { config->cfg.rc_min_quantizer = arg_parse_uint(&arg); - } else if (arg_match(&arg, &max_quantizer, argi)) { + } else if (arg_match(&arg, &max_qp_level, argi)) { config->cfg.rc_max_quantizer = arg_parse_uint(&arg); + } else if (arg_match(&arg, &min_q_level, argi)) { + const unsigned int min_q_val = arg_parse_uint(&arg); + config->cfg.rc_min_quantizer = + get_qindex_from_quantizer_and_warn(min_q_val, "min-q", "min-qp"); + } else if (arg_match(&arg, &max_q_level, argi)) { + const unsigned int max_q_val = arg_parse_uint(&arg); + config->cfg.rc_max_quantizer = + get_qindex_from_quantizer_and_warn(max_q_val, "max-q", "max-qp"); } else if (arg_match(&arg, &undershoot_pct, argi)) { config->cfg.rc_undershoot_pct = arg_parse_uint(&arg); } else if (arg_match(&arg, &overshoot_pct, argi)) { @@ -1565,10 +1680,12 @@ config->cfg.rc_buf_initial_sz = arg_parse_uint(&arg); } else if (arg_match(&arg, &buf_optimal_sz, argi)) { config->cfg.rc_buf_optimal_sz = arg_parse_uint(&arg); +#if !CONFIG_SINGLEPASS } else if (arg_match(&arg, &bias_pct, argi)) { config->cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg); if (global->passes < 2) warn("option %s ignored in one-pass mode.\n", arg.name); +#endif // !CONFIG_SINGLEPASS } else if (arg_match(&arg, &minsection_pct, argi)) { config->cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg); @@ -1619,6 +1736,15 @@ if (arg_parse_uint(&arg) == 1) { warn("non-zero %s option ignored in realtime mode.\n", arg.name); } + } else if (arg_match(&arg, &cq_level, argi)) { + const unsigned int cq_level_val = arg_parse_uint(&arg); + const int qp_val = + get_qindex_from_quantizer_and_warn(cq_level_val, "cq-level", "qp"); + const int idx = config->arg_ctrl_cnt; + assert(idx < (int)ARG_CTRL_CNT_MAX); + config->arg_ctrls[idx][0] = AOME_SET_QP; + config->arg_ctrls[idx][1] = qp_val; + ++config->arg_ctrl_cnt; } else { int i, match = 0; for (i = 0; ctrl_args[i]; i++) { @@ -1677,6 +1803,7 @@ streami->index, stream->index); } +#if !CONFIG_SINGLEPASS /* Check for two streams sharing a stats file. */ if (streami != stream) { const char *a = stream->config.stats_fn; @@ -1685,6 +1812,7 @@ fatal("Stream %d: duplicate stats file (from stream %d)", streami->index, stream->index); } +#endif // !CONFIG_SINGLEPASS } } @@ -1723,103 +1851,155 @@ } } +static void print_frames_to_code(FILE *f, struct stream_state *stream, + struct AvxEncoderConfig *global) { + const struct aom_codec_enc_cfg *cfg = &stream->config.cfg; + int num_frames = cfg->g_limit / global->step_frames; + // E.g., if step == 3 and limit == 4, then 2 frames are encoded. + // Similar for all cases where limit % step != 0. + if (cfg->g_limit % global->step_frames != 0) { + ++num_frames; + } + fprintf(f, "Frames to be coded : %d - %d (%d frames", + global->skip_frames, global->skip_frames + cfg->g_limit - 1, + num_frames); + if (global->step_frames == 1) { + fprintf(f, ")\n"); + } else { + fprintf(f, ", step size:%d)\n", global->step_frames); + } +} + static void show_stream_config(struct stream_state *stream, struct AvxEncoderConfig *global, struct AvxInputContext *input) { -#define SHOW(field) \ - fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field) - - if (stream->index == 0) { - fprintf(stderr, "Codec: %s\n", aom_codec_iface_name(global->codec)); - fprintf(stderr, "Source file: %s File Type: %s Format: %s\n", - input->filename, file_type_to_string(input->file_type), - image_format_to_string(input->fmt)); + const struct aom_codec_enc_cfg *cfg = &stream->config.cfg; + const cfg_options_t *encoder_cfg = &stream->encoder.config.enc->encoder_cfg; + fprintf(stdout, "Codec : %s\n", + aom_codec_iface_name(global->codec)); + fprintf(stdout, "Executable : aomenc %s\n", ENV_BITS); + fprintf(stdout, "Input file : %s\n", input->filename); + fprintf(stdout, "Output file : %s\n", + stream->config.out_fn); + fprintf(stdout, + "Input format : %s, %s, %dx%d, %3.1f FPS, %d bit\n", + file_type_to_string(input->file_type), + image_format_to_string(input->fmt), input->width, input->height, + (double)global->framerate.num / (double)global->framerate.den, + input->bit_depth); + fprintf(stdout, "Number of threads : %d\n", cfg->g_threads); + print_frames_to_code(stdout, stream, global); + fprintf(stdout, "Operating bit depth : %d\n", cfg->g_bit_depth); + fprintf(stdout, "Num of coding passes : %d\n", global->passes); +#if !CONFIG_SINGLEPASS + if (global->passes > 1) { + fprintf(stdout, "Stats file : %s\n", + stream->config.stats_fn); } - if (stream->next || stream->index) - fprintf(stderr, "\nStream Index: %d\n", stream->index); - fprintf(stderr, "Destination file: %s\n", stream->config.out_fn); - fprintf(stderr, "Coding path: %s\n", - stream->config.use_16bit_internal ? "HBD" : "LBD"); - fprintf(stderr, "Encoder parameters:\n"); - - SHOW(g_usage); - SHOW(g_threads); - SHOW(g_profile); - SHOW(g_w); - SHOW(g_h); - SHOW(g_bit_depth); - SHOW(g_input_bit_depth); - SHOW(g_timebase.num); - SHOW(g_timebase.den); - SHOW(g_error_resilient); - SHOW(g_pass); - SHOW(g_lag_in_frames); - SHOW(large_scale_tile); - SHOW(rc_dropframe_thresh); - SHOW(rc_resize_mode); - SHOW(rc_resize_denominator); - SHOW(rc_resize_kf_denominator); - SHOW(rc_superres_mode); - SHOW(rc_superres_denominator); - SHOW(rc_superres_kf_denominator); - SHOW(rc_superres_qthresh); - SHOW(rc_superres_kf_qthresh); - SHOW(rc_end_usage); - SHOW(rc_target_bitrate); - SHOW(rc_min_quantizer); - SHOW(rc_max_quantizer); - SHOW(rc_undershoot_pct); - SHOW(rc_overshoot_pct); - SHOW(rc_buf_sz); - SHOW(rc_buf_initial_sz); - SHOW(rc_buf_optimal_sz); - SHOW(rc_2pass_vbr_bias_pct); - SHOW(rc_2pass_vbr_minsection_pct); - SHOW(rc_2pass_vbr_maxsection_pct); - SHOW(fwd_kf_enabled); - SHOW(kf_mode); - SHOW(kf_min_dist); - SHOW(kf_max_dist); - -#define SHOW_PARAMS(field) \ - fprintf(stderr, " %-28s = %d\n", #field, \ - stream->config.cfg.encoder_cfg.field) - if (global->encoder_config.init_by_cfg_file) { - SHOW_PARAMS(super_block_size); - SHOW_PARAMS(max_partition_size); - SHOW_PARAMS(min_partition_size); - SHOW_PARAMS(disable_ab_partition_type); - SHOW_PARAMS(disable_rect_partition_type); - SHOW_PARAMS(disable_1to4_partition_type); - SHOW_PARAMS(disable_flip_idtx); - SHOW_PARAMS(disable_cdef); - SHOW_PARAMS(disable_lr); - SHOW_PARAMS(disable_obmc); - SHOW_PARAMS(disable_warp_motion); - SHOW_PARAMS(disable_global_motion); - SHOW_PARAMS(disable_dist_wtd_comp); - SHOW_PARAMS(disable_diff_wtd_comp); - SHOW_PARAMS(disable_inter_intra_comp); - SHOW_PARAMS(disable_masked_comp); - SHOW_PARAMS(disable_one_sided_comp); - SHOW_PARAMS(disable_palette); - SHOW_PARAMS(disable_intrabc); - SHOW_PARAMS(disable_cfl); - SHOW_PARAMS(disable_smooth_intra); - SHOW_PARAMS(disable_filter_intra); - SHOW_PARAMS(disable_dual_filter); - SHOW_PARAMS(disable_intra_angle_delta); - SHOW_PARAMS(disable_intra_edge_filter); - SHOW_PARAMS(disable_tx_64x64); - SHOW_PARAMS(disable_smooth_inter_intra); - SHOW_PARAMS(disable_inter_inter_wedge); - SHOW_PARAMS(disable_inter_intra_wedge); - SHOW_PARAMS(disable_paeth_intra); - SHOW_PARAMS(disable_trellis_quant); - SHOW_PARAMS(disable_ref_frame_mv); - SHOW_PARAMS(reduced_reference_set); - SHOW_PARAMS(reduced_tx_type_set); +#endif // !CONFIG_SINGLEPASS + fprintf(stdout, "Lag in frames : %d\n", + cfg->g_lag_in_frames); + if (cfg->kf_min_dist != cfg->kf_max_dist) { + fprintf(stdout, "Key frame distance : %d - %d\n", + cfg->kf_min_dist, cfg->kf_max_dist); + } else { + fprintf(stdout, "Key frame distance : %d\n", cfg->kf_min_dist); } + if (encoder_cfg->superblock_size != 0) { + fprintf(stdout, "Super block size : %d\n", + encoder_cfg->superblock_size); + } else { + fprintf(stdout, "Super block size : Dynamic\n"); + } + fprintf(stdout, "Partition size : %d - %d\n", + encoder_cfg->min_partition_size, encoder_cfg->max_partition_size); + + int qp = 0; + int cpu_used = 0; + for (int i = 0; i < stream->config.arg_ctrl_cnt; i++) { + int ctrl = stream->config.arg_ctrls[i][0]; + + if (ctrl == AOME_SET_QP) { + qp = stream->config.arg_ctrls[i][1]; + } + if (ctrl == AOME_SET_CPUUSED) { + cpu_used = stream->config.arg_ctrls[i][1]; + } + } + fprintf(stdout, "QP : %d", qp); + if (cfg->use_fixed_qp_offsets) { + fprintf(stdout, " [ "); + for (int level = 0; level < FIXED_QP_OFFSET_COUNT; level++) { + fprintf(stdout, "%d ", cfg->fixed_qp_offsets[level]); + } + fprintf(stdout, "]"); + } + fprintf(stdout, "\nEncoder speed setting : %d (cpu-used)\n", + cpu_used); + fprintf(stdout, "Trellis quantization : %d\n", + !encoder_cfg->disable_trellis_quant); + fprintf(stdout, "Reduced reference frame set : %d\n", + encoder_cfg->enable_reduced_reference_set); + fprintf(stdout, "Reduced transform set : %d\n", + encoder_cfg->reduced_tx_type_set); + + fprintf( + stdout, "Tool setting (Partition) : T-Type (%d), 4:1/1:4 (%d)\n", + encoder_cfg->enable_ab_partitions, encoder_cfg->enable_1to4_partitions); + + fprintf(stdout, + "Tool setting (Intra) : SmoothIntra (%d), CfL (%d), " + "FilterIntra (%d)\n", + encoder_cfg->enable_smooth_intra, encoder_cfg->enable_cfl_intra, + encoder_cfg->enable_filter_intra); + fprintf(stdout, + " : DualFilter (%d), IntraDeltaAngle " + "(%d)\n", + encoder_cfg->enable_dual_filter, encoder_cfg->enable_angle_delta); + fprintf(stdout, + " : " + "EdgeFilter (%d), PaethPredictor (%d)\n", + encoder_cfg->enable_intra_edge_filter, + encoder_cfg->enable_paeth_intra); + + fprintf(stdout, + "Tool setting (Inter) : OBMC (%d), WarpMotion (%d), " + "GlobalMotion (%d)\n", + encoder_cfg->enable_obmc, encoder_cfg->enable_warped_motion, + encoder_cfg->enable_global_motion); + + fprintf(stdout, + " : DistCompound (%d), DiCompound " + "(%d), InterIntra (%d)\n", + encoder_cfg->enable_dist_wtd_comp, encoder_cfg->enable_diff_wtd_comp, + encoder_cfg->enable_interintra_comp); + + fprintf(stdout, + " : MaskCompound: (%d), " + "OneSideCompound (%d), SmoothInterIntra (%d)\n", + encoder_cfg->enable_masked_comp, encoder_cfg->enable_onesided_comp, + encoder_cfg->enable_smooth_interintra); + + fprintf(stdout, + " : InterInterWedge (%d), " + "InterIntraWedge (%d), RefFrameMv (%d)\n", + encoder_cfg->enable_interinter_wedge, + encoder_cfg->enable_interintra_wedge, + encoder_cfg->enable_ref_frame_mvs); + + fprintf(stdout, + "Tool setting (Transform) : Flip & IDT (%d), TX_64 (%d)\n", + encoder_cfg->enable_flip_idtx, encoder_cfg->enable_tx64); + + fprintf(stdout, + "Tool setting (Loop filter) : CDEF (%d), LoopRestortion (%d)\n", + encoder_cfg->enable_cdef, encoder_cfg->enable_restoration); + + fprintf(stdout, + "Tool setting (Others) : Palette (%d), IntraBC (%d)\n", + encoder_cfg->enable_palette, encoder_cfg->enable_intrabc); + + fprintf(stdout, "\n\n"); } static void open_output_file(struct stream_state *stream, @@ -1884,6 +2064,11 @@ static void setup_pass(struct stream_state *stream, struct AvxEncoderConfig *global, int pass) { +#if CONFIG_SINGLEPASS + (void)global; + (void)pass; + assert(pass == 0); +#else if (stream->config.stats_fn) { if (!stats_open_file(&stream->stats, stream->config.stats_fn, pass)) fatal("Failed to open statistics store"); @@ -1891,13 +2076,18 @@ if (!stats_open_mem(&stream->stats, pass)) fatal("Failed to open statistics store"); } +#endif // CONFIG_SINGLEPASS +#if CONFIG_SINGLEPASS + stream->config.cfg.g_pass = AOM_RC_ONE_PASS; +#else stream->config.cfg.g_pass = global->passes == 2 ? pass ? AOM_RC_LAST_PASS : AOM_RC_FIRST_PASS : AOM_RC_ONE_PASS; if (pass) { stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats); } +#endif // CONFIG_SINGLEPASS stream->cx_time = 0; stream->nbytes = 0; @@ -1911,6 +2101,7 @@ flags |= global->show_psnr ? AOM_CODEC_USE_PSNR : 0; flags |= stream->config.use_16bit_internal ? AOM_CODEC_USE_HIGHBITDEPTH : 0; + flags |= global->quiet ? 0 : AOM_CODEC_USE_PER_FRAME_STATS; /* Construct Encoder Context */ aom_codec_enc_init(&stream->encoder, global->codec, &stream->config.cfg, @@ -1938,6 +2129,14 @@ stream->config.film_grain_filename); } + if (stream->config.subgop_config_str) { + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_SUBGOP_CONFIG_STR, + stream->config.subgop_config_str); + } + if (stream->config.subgop_config_path) { + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_SUBGOP_CONFIG_PATH, + stream->config.subgop_config_path); + } #if CONFIG_AV1_DECODER if (global->test_decode != TEST_DECODE_OFF) { aom_codec_iface_t *decoder = get_aom_decoder_by_short_name( @@ -2058,7 +2257,7 @@ if (stream->config.cfg.g_pass != AOM_RC_FIRST_PASS) { int q; - AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AOME_GET_LAST_QUANTIZER_64, + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AOME_GET_LAST_QUANTIZER, &q); ctx_exit_on_error(&stream->encoder, "Failed to read quantizer"); stream->counts[q]++; @@ -2079,9 +2278,6 @@ switch (pkt->kind) { case AOM_CODEC_CX_FRAME_PKT: ++stream->frames_out; - if (!global->quiet) - fprintf(stderr, " %6luF", (unsigned long)pkt->data.frame.sz); - update_rate_histogram(stream->rate_hist, cfg, pkt); #if CONFIG_WEBM_IO if (stream->config.write_webm) { @@ -2127,12 +2323,14 @@ } #endif break; +#if !CONFIG_SINGLEPASS case AOM_CODEC_STATS_PKT: stream->frames_out++; stats_write(&stream->stats, pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz); stream->nbytes += pkt->data.raw.sz; break; +#endif // !CONFIG_SINGLEPASS case AOM_CODEC_PSNR_PKT: if (global->show_psnr) { @@ -2141,8 +2339,6 @@ stream->psnr_sse_total += pkt->data.psnr.sse[0]; stream->psnr_samples_total += pkt->data.psnr.samples[0]; for (i = 0; i < 4; i++) { - if (!global->quiet) - fprintf(stderr, "%.3f ", pkt->data.psnr.psnr[i]); stream->psnr_totals[i] += pkt->data.psnr.psnr[i]; } stream->psnr_count++; @@ -2154,31 +2350,25 @@ } } -static void show_psnr(struct stream_state *stream, double peak, int64_t bps) { - int i; - double ovpsnr; - - if (!stream->psnr_count) return; - - fprintf(stderr, "Stream %d PSNR (Overall/Avg/Y/U/V)", stream->index); - ovpsnr = sse_to_psnr((double)stream->psnr_samples_total, peak, - (double)stream->psnr_sse_total); - fprintf(stderr, " %.3f", ovpsnr); - - for (i = 0; i < 4; i++) { - fprintf(stderr, " %.3f", stream->psnr_totals[i] / stream->psnr_count); - } - if (bps > 0) { - fprintf(stderr, " %7" PRId64 " bps", bps); - } - fprintf(stderr, " %7" PRId64 " ms", stream->cx_time / 1000); - fprintf(stderr, "\n"); -} - static float usec_to_fps(uint64_t usec, unsigned int frames) { return (float)(usec > 0 ? frames * 1000000.0 / (float)usec : 0); } +static void write_recon_file(struct stream_state *stream, FILE *file) { + aom_image_t enc_img; + + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1_GET_NEW_FRAME_IMAGE, + &enc_img); + + ctx_exit_on_error(&stream->encoder, + "Failed to get encoder reconstructed frame"); + + int num_planes = enc_img.monochrome ? 1 : 3; + const int PLANES_YUV[] = { AOM_PLANE_Y, AOM_PLANE_U, AOM_PLANE_V }; + const int *planes = PLANES_YUV; + raw_write_image_file(&enc_img, planes, num_planes, file); +} + static void test_decode(struct stream_state *stream, enum TestDecodeFatality fatal) { aom_image_t enc_img, dec_img; @@ -2234,25 +2424,6 @@ aom_img_free(&dec_img); } -static void print_time(const char *label, int64_t etl) { - int64_t hours; - int64_t mins; - int64_t secs; - - if (etl >= 0) { - hours = etl / 3600; - etl -= hours * 3600; - mins = etl / 60; - etl -= mins * 60; - secs = etl; - - fprintf(stderr, "[%3s %2" PRId64 ":%02" PRId64 ":%02" PRId64 "] ", label, - hours, mins, secs); - } else { - fprintf(stderr, "[%3s unknown] ", label); - } -} - int main(int argc, const char **argv_) { int pass; aom_image_t raw; @@ -2260,7 +2431,6 @@ int allocated_raw_shift = 0; int do_16bit_internal = 0; int input_shift = 0; - int frame_avail, got_data; struct AvxInputContext input; struct AvxEncoderConfig global; @@ -2280,6 +2450,8 @@ input.only_i420 = 1; input.bit_depth = 0; + FILE *recon_file = NULL; + /* First parse the global configuration values, because we want to apply * other parameters on top of the default configuration provided by the * codec. @@ -2327,6 +2499,13 @@ /* Handle non-option arguments */ input.filename = argv[0]; + FOREACH_STREAM(stream, streams) { + if (stream->config.recon_fn != NULL) { + recon_file = fopen(stream->config.recon_fn, "wb"); + if (!recon_file) fatal("Failed to open recon file"); + } + } + if (!input.filename) { fprintf(stderr, "No input file specified!\n"); usage_exit(); @@ -2337,11 +2516,6 @@ input.only_i420 = 0; for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) { - int frames_in = 0, seen_frames = 0; - int64_t estimated_time_left = -1; - int64_t average_rate = -1; - int64_t lagged_count = 0; - open_input_file(&input, global.csp); /* If the input file doesn't specify its w/h (raw files), try to get @@ -2491,6 +2665,7 @@ } FOREACH_STREAM(stream, streams) { validate_stream_config(stream, &global); } +#if !CONFIG_SINGLEPASS /* Ensure that --passes and --pass are consistent. If --pass is set and * --passes=2, ensure --fpf was set. */ @@ -2502,6 +2677,7 @@ stream->index, global.pass); } } +#endif // !CONFIG_SINGLEPASS #if !CONFIG_WEBM_IO FOREACH_STREAM(stream, streams) { @@ -2524,14 +2700,8 @@ stream->config.cfg.g_timebase.den = global.framerate.num; stream->config.cfg.g_timebase.num = global.framerate.den; } - /* Show configuration */ - if (global.verbose && pass == 0) { - FOREACH_STREAM(stream, streams) { - show_stream_config(stream, &global, &input); - } - } - if (pass == (global.pass ? global.pass - 1 : 0)) { + if (CONFIG_SINGLEPASS || pass == (global.pass ? global.pass - 1 : 0)) { if (input.file_type == FILE_TYPE_Y4M) /*The Y4M reader does its own allocation. Just initialize this here to avoid problems if we never read any @@ -2548,6 +2718,17 @@ FOREACH_STREAM(stream, streams) { setup_pass(stream, &global, pass); } FOREACH_STREAM(stream, streams) { initialize_encoder(stream, &global); } + +#if CONFIG_SINGLEPASS + if (global.verbose) { +#else + if (global.verbose && pass == 0) { +#endif // CONFIG_SINGLEPASS + FOREACH_STREAM(stream, streams) { + show_stream_config(stream, &global, &input); + } + } + FOREACH_STREAM(stream, streams) { char *encoder_settings = NULL; #if CONFIG_WEBM_IO @@ -2586,155 +2767,135 @@ }; } - frame_avail = 1; - got_data = 0; + // Keep track of the total number of frames passed to the encoder. + int seen_frames = 0; + // Does the encoder have queued data that needs retrieval? + int got_data = 0; + // Is there a frame available for processing? + int frame_avail = 1; + // Wrap the original stream of frames in an "object" that returns the + // same set of streams. + StreamIter orig_stream; + copy_stream_iter_init(&orig_stream, &input); + + // The skip iterator will skip the first N frames. Wrap the original + // stream in the skip iterator. + StreamIter skip_stream; + skip_stream_iter_init(&skip_stream, &orig_stream, global.skip_frames); + + // The step iterator will only return every N-th frame. + StreamIter step_stream; + step_stream_iter_init(&step_stream, &skip_stream, global.step_frames); + + // The limit iterator will stop returning frames after the N-th. + StreamIter limit_stream; + limit_stream_iter_init(&limit_stream, &step_stream, global.limit); while (frame_avail || got_data) { - struct aom_usec_timer timer; - - if (!global.limit || frames_in < global.limit) { - frame_avail = read_frame(&input, &raw); - - if (frame_avail) frames_in++; - seen_frames = - frames_in > global.skip_frames ? frames_in - global.skip_frames : 0; - - if (!global.quiet) { - float fps = usec_to_fps(cx_time, seen_frames); - fprintf(stderr, "\rPass %d/%d ", pass + 1, global.passes); - - if (stream_cnt == 1) - fprintf(stderr, "frame %4d/%-4d %7" PRId64 "B ", frames_in, - streams->frames_out, (int64_t)streams->nbytes); - else - fprintf(stderr, "frame %4d ", frames_in); - - fprintf(stderr, "%7" PRId64 " %s %.2f %s ", - cx_time > 9999999 ? cx_time / 1000 : cx_time, - cx_time > 9999999 ? "ms" : "us", fps >= 1.0 ? fps : fps * 60, - fps >= 1.0 ? "fps" : "fpm"); - print_time("ETA", estimated_time_left); - } - - } else { - frame_avail = 0; + frame_avail = read_stream_iter(&limit_stream, &raw); + if (frame_avail) { + seen_frames++; } - - if (frames_in > global.skip_frames) { - aom_image_t *frame_to_encode; - if (input_shift || (do_16bit_internal && input.bit_depth == 8)) { - assert(do_16bit_internal); - // Input bit depth and stream bit depth do not match, so up - // shift frame to stream bit depth - if (!allocated_raw_shift) { - aom_img_alloc(&raw_shift, raw.fmt | AOM_IMG_FMT_HIGHBITDEPTH, - input.width, input.height, 32); - allocated_raw_shift = 1; - } - aom_img_upshift(&raw_shift, &raw, input_shift); - frame_to_encode = &raw_shift; - } else { - frame_to_encode = &raw; - } - aom_usec_timer_start(&timer); - if (do_16bit_internal) { - assert(frame_to_encode->fmt & AOM_IMG_FMT_HIGHBITDEPTH); - FOREACH_STREAM(stream, streams) { - if (stream->config.use_16bit_internal) - encode_frame(stream, &global, - frame_avail ? frame_to_encode : NULL, frames_in); - else - assert(0); - }; - } else { - assert((frame_to_encode->fmt & AOM_IMG_FMT_HIGHBITDEPTH) == 0); - FOREACH_STREAM(stream, streams) { - encode_frame(stream, &global, frame_avail ? frame_to_encode : NULL, - frames_in); - } - } - aom_usec_timer_mark(&timer); - cx_time += aom_usec_timer_elapsed(&timer); - - FOREACH_STREAM(stream, streams) { update_quantizer_histogram(stream); } - - got_data = 0; - FOREACH_STREAM(stream, streams) { - get_cx_data(stream, &global, &got_data); - } - - if (!got_data && input.length && streams != NULL && - !streams->frames_out) { - lagged_count = global.limit ? seen_frames : ftello(input.file); - } else if (input.length) { - int64_t remaining; - int64_t rate; - - if (global.limit) { - const int64_t frame_in_lagged = (seen_frames - lagged_count) * 1000; - - rate = cx_time ? frame_in_lagged * (int64_t)1000000 / cx_time : 0; - remaining = 1000 * (global.limit - global.skip_frames - - seen_frames + lagged_count); - } else { - const int64_t input_pos = ftello(input.file); - const int64_t input_pos_lagged = input_pos - lagged_count; - const int64_t input_limit = input.length; - - rate = cx_time ? input_pos_lagged * (int64_t)1000000 / cx_time : 0; - remaining = input_limit - input_pos + lagged_count; - } - - average_rate = - (average_rate <= 0) ? rate : (average_rate * 7 + rate) / 8; - estimated_time_left = average_rate ? remaining / average_rate : -1; - } - - if (got_data && global.test_decode != TEST_DECODE_OFF) { - FOREACH_STREAM(stream, streams) { - test_decode(stream, global.test_decode); - } - } - } - fflush(stdout); - if (!global.quiet) fprintf(stderr, "\033[K"); + + aom_image_t *frame_to_encode; + if (input_shift || (do_16bit_internal && input.bit_depth == 8)) { + assert(do_16bit_internal); + // Input bit depth and stream bit depth do not match, so up + // shift frame to stream bit depth + if (!allocated_raw_shift) { + aom_img_alloc(&raw_shift, raw.fmt | AOM_IMG_FMT_HIGHBITDEPTH, + input.width, input.height, 32); + allocated_raw_shift = 1; + } + aom_img_upshift(&raw_shift, &raw, input_shift); + frame_to_encode = &raw_shift; + } else { + frame_to_encode = &raw; + } + struct aom_usec_timer timer; + aom_usec_timer_start(&timer); + if (do_16bit_internal) { + assert(frame_to_encode->fmt & AOM_IMG_FMT_HIGHBITDEPTH); + FOREACH_STREAM(stream, streams) { + if (stream->config.use_16bit_internal) + encode_frame(stream, &global, frame_avail ? frame_to_encode : NULL, + seen_frames); + else + assert(0); + }; + } else { + assert((frame_to_encode->fmt & AOM_IMG_FMT_HIGHBITDEPTH) == 0); + FOREACH_STREAM(stream, streams) { + encode_frame(stream, &global, frame_avail ? frame_to_encode : NULL, + seen_frames); + } + } + aom_usec_timer_mark(&timer); + cx_time += aom_usec_timer_elapsed(&timer); + + FOREACH_STREAM(stream, streams) { update_quantizer_histogram(stream); } + + got_data = 0; + FOREACH_STREAM(stream, streams) { + get_cx_data(stream, &global, &got_data); + } + if (got_data && recon_file != NULL) { + FOREACH_STREAM(stream, streams) { + write_recon_file(stream, recon_file); + } + } + if (got_data && global.test_decode != TEST_DECODE_OFF) { + FOREACH_STREAM(stream, streams) { + test_decode(stream, global.test_decode); + } + } + fflush(stdout); } if (stream_cnt > 1) fprintf(stderr, "\n"); - if (!global.quiet) { + if (!global.quiet && (pass + 1) == global.passes) { FOREACH_STREAM(stream, streams) { - const int64_t bpf = - seen_frames ? (int64_t)(stream->nbytes * 8 / seen_frames) : 0; - const int64_t bps = bpf * global.framerate.num / global.framerate.den; - fprintf(stderr, - "\rPass %d/%d frame %4d/%-4d %7" PRId64 "B %7" PRId64 - "b/f %7" PRId64 - "b/s" - " %7" PRId64 " %s (%.2f fps)\033[K\n", - pass + 1, global.passes, frames_in, stream->frames_out, - (int64_t)stream->nbytes, bpf, bps, - stream->cx_time > 9999999 ? stream->cx_time / 1000 - : stream->cx_time, - stream->cx_time > 9999999 ? "ms" : "us", - usec_to_fps(stream->cx_time, seen_frames)); - } - } - - if (global.show_psnr) { - if (get_fourcc_by_aom_encoder(global.codec) == AV1_FOURCC) { - FOREACH_STREAM(stream, streams) { - int64_t bps = 0; - if (stream->psnr_count && seen_frames && global.framerate.den) { - bps = (int64_t)stream->nbytes * 8 * (int64_t)global.framerate.num / - global.framerate.den / seen_frames; + const double bpf = + seen_frames ? ((double)stream->nbytes * 8.0 / (double)seen_frames) + : 0.0; + const double kbps = (bpf * (double)global.framerate.num / + (double)global.framerate.den) / + 1000.0; + const double peak = (1 << stream->config.cfg.g_input_bit_depth) - 1; + const double ovpsnr = sse_to_psnr((double)stream->psnr_samples_total, + peak, (double)stream->psnr_sse_total); + double psnr[4] = { 0.0 }; + if (global.show_psnr) { + for (int i = 0; i < 4; i++) { + psnr[i] = stream->psnr_totals[i] / stream->psnr_count; } - show_psnr(stream, (1 << stream->config.cfg.g_input_bit_depth) - 1, - bps); + fprintf(stdout, + "\n Bitrate(kbps) | PSNR(Y) | PSNR(U) " + "| PSNR(V) | PSNR(Avg) | PSNR(Overall) " + "| Encoding time (FPS)\n"); + fprintf(stdout, + "-----------------------------------------" + "---------------------------------------" + "----------------------------\n"); + + fprintf(stdout, + "Summary: %10.4f | %2.4f | %2.4f | %2.4f" + " | %2.4f | %2.4f | %6.1fs (%3.1f fps)\n", + kbps, psnr[1], psnr[2], psnr[3], psnr[0], ovpsnr, + stream->cx_time / 1000000.0, + usec_to_fps(stream->cx_time, seen_frames)); + } else { + fprintf(stdout, "\n Bitrate(kbps) | Encoding time (FPS)\n"); + fprintf(stdout, + "-----------------------------------------" + "---------------------------------------" + "----------------------------\n"); + fprintf(stdout, "Summary: %10.4f | %6.1fs (%3.1f fps)\n", kbps, + stream->cx_time / 1000000.0, + usec_to_fps(stream->cx_time, seen_frames)); } - } else { - FOREACH_STREAM(stream, streams) { show_psnr(stream, 255.0, 0); } } } @@ -2753,9 +2914,11 @@ close_output_file(stream, get_fourcc_by_aom_encoder(global.codec)); } +#if !CONFIG_SINGLEPASS FOREACH_STREAM(stream, streams) { stats_close(&stream->stats, global.passes - 1); } +#endif // !CONFIG_SINGLEPASS if (global.pass) break; } @@ -2792,6 +2955,8 @@ } #endif + if (recon_file != NULL) fclose(recon_file); + if (allocated_raw_shift) aom_img_free(&raw_shift); aom_img_free(&raw); free(argv);
diff --git a/apps/aomenc.h b/apps/aomenc.h index 8d4c25c..b0982db 100644 --- a/apps/aomenc.h +++ b/apps/aomenc.h
@@ -11,6 +11,7 @@ #ifndef AOM_APPS_AOMENC_H_ #define AOM_APPS_AOMENC_H_ +#include "config/aom_config.h" #include "aom/aom_codec.h" #include "aom/aom_encoder.h" @@ -42,6 +43,7 @@ int verbose; int limit; int skip_frames; + int step_frames; int show_psnr; enum TestDecodeFatality test_decode; int have_framerate;
diff --git a/av1/av1.cmake b/av1/av1.cmake index 4015801..070443a 100644 --- a/av1/av1.cmake +++ b/av1/av1.cmake
@@ -223,6 +223,8 @@ "${AOM_ROOT}/av1/encoder/segmentation.h" "${AOM_ROOT}/av1/encoder/speed_features.c" "${AOM_ROOT}/av1/encoder/speed_features.h" + "${AOM_ROOT}/av1/encoder/subgop.c" + "${AOM_ROOT}/av1/encoder/subgop.h" "${AOM_ROOT}/av1/encoder/superres_scale.c" "${AOM_ROOT}/av1/encoder/superres_scale.h" "${AOM_ROOT}/av1/encoder/svc_layercontext.c"
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index fe3178a..fb4c556 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -27,6 +27,9 @@ #include "av1/encoder/ethread.h" #include "av1/encoder/firstpass.h" +#include "aom_dsp/psnr.h" +#include "aom_ports/aom_timer.h" + #define MAG_SIZE (4) struct av1_extracfg { @@ -49,7 +52,9 @@ unsigned int gf_max_pyr_height; aom_tune_metric tuning; const char *vmaf_model_path; - unsigned int cq_level; // constrained quality level + const char *subgop_config_str; + const char *subgop_config_path; + unsigned int qp; // constant/constrained quality level unsigned int rc_max_intra_bitrate_pct; unsigned int rc_max_inter_bitrate_pct; unsigned int gf_cbr_boost_pct; @@ -153,6 +158,56 @@ unsigned int sb_multipass_unit_test; }; +// Example subgop configs. Currently not used by default. +// Default config +const char subgop_config_str_16_def[] = + "16:2:16F1P1/8F2P1^-1/" + "4U3P-2^1^-1/2U4P1^-3^-2^-1/" + "1V5P1^-2^-4^-3^-1/2S/3V5P4^5^1^-3^-2^-1/4S/6U4P3^5^5^1^-2^4^-1/" + "5V5P3^5^4^1^-4^-2^-1/6S/7V5P4^5^5^1^-2^3^-1/8R2P5^4^3^1^2^5^-1/" + "12U3P2^5^3^1^5^4^-1/10U4P2^5^5^1^-3^4^-1/9V5P2^5^4^1^-4^-3^-1/10S/" + "11V5P4^5^5^1^-3^2^-1/12S/14U4P3^5^2^1^5^4^-1/13V5P3^5^5^1^-4^4^-1/" + "14S/15V5P4^5^4^1^5^3^-1/16R1P5^4^5^1^3^5^1," + + "16:0:16F1P5^4^3^1^1^1^5/8F2P5^4^3^1^1^5^-1/" + "4U3P5^4^5^1^-2^1^-1/2U4P5^4^1^1^-3^-2^-1/" + "1V5P5^4^1^1^-4^-3^-1/2S/3V5P4^5^1^1^-3^-2^-1/4S/6U4P3^5^4^1^-2^1^-1/" + "5V5P3^5^1^1^-4^-2^-1/6S/7V5P4^5^3^1^-2^1^-1/8R2P5^4^5^1^2^1^-1/" + "12U3P2^5^5^1^1^4^-1/10U4P2^5^4^1^-3^1^-1/9V5P2^5^1^1^-4^-3^-1/10S/" + "11V5P4^5^2^1^-3^1^-1/12S/14U4P3^5^5^1^1^4^-1/13V5P3^5^4^1^-4^1^-1/" + "14S/15V5P4^5^5^1^1^3^-1/16R1P5^4^5^1^3^5^1,"; + +// A config that honors temporally scalable prediction structure, i.e. +// no frame is coded with references at higher pyramid depths. +const char subgop_config_str_16_ts[] = + "16:0:16F1P1^1/8F2P1^1^2^-1/4U3P1^1^2^-2^-1/2U4P1^1^-3^-2^-1/" + "1V5P1^1^-4^-3^-2^-1/2S/3V5P1^5^4^-3^-2^-1/4S/6U4P1^3^4^-2^-1/" + "5V5P1^4^5^3^-4^-2^-1/6S/7V5P1^3^5^4^-2^-1/8R2P1^2^-1/12U3P1^3^2^-1/" + "10U4P1^3^4^2^-3^-1/9V5P1^3^4^2^-4^-3^-1/10S/11V5P1^2^4^5^-3^-1/12S/" + "14U4P1^2^4^3^-1/13V5P1^2^4^5^3^-4^-1/14S/15V5P1^2^3^4^5^-1/16R1P1^1," + + "16:1:14F1P1^1/7F2P1^1^2^-1/4U3P1^1^2^-2^-1/2U4P1^1^-3^-2^-1/" + "1V5P1^1^-4^-3^-2^-1/2S/3V5P1^5^4^-3^-2^-1/4S/6U4P1^3^4^-2^-1/" + "5V5P1^4^5^3^-4^-2^-1/6S/7R2P1^2^-1/11U3P1^3^2^-1/9U4P1^3^4^2^-3^-1/" + "8V5P1^3^4^2^-4^-3^-1/9S/10V5P1^2^4^5^-3^-1/11S/13U4P1^2^4^3^-1/" + "12V5P1^2^4^5^3^-4^-1/13S/14R1P1^1/16U4P1^1^2^3^4/15V5P1^1^2^3^4^-4^5/16S"; + +// An asymmetrical config where the hierarchical frames are not exactly +// dyadic, but slightly skewed. +const char subgop_config_str_16_asym[] = + "16:0:16F1P1^1/11F2P1^1^2^-1/6U3P1^1^2^-2^-1/3U4P1^1^-3^-2^-1/" + "1V5P1^1^-4^-3^-2^-1/2V5P1^1^-4^-3^-2^-1^5/3S/4V5P1^5^5^4^-3^-2^-1/" + "5V5P1^5^5^4^-3^-2^-1/6S/9U3P^1^3^-1^-2/7V4P1^-1^-2^3^-3^4/" + "8V5P1^-1^-2^-3^3^4^5/9S/10V4P1^-1^-2^3^3^4/11R2P1^2^-1/" + "14U3P1^-1^2^3^3/13U4P1^-1^2^3^-3^4^4/12V5P1^-1^2^3^-3^4^-4/" + "13S/14S/15V5P1^-1^2^3^4^4^5/16R1P1^1," + + "16:1:14F1P1^1/8F2P1^1^2^-1/4U3P1^1^2^-2^-1/2U4P1^1^-3^-2^-1/" + "1V5P1^1^-4^-3^-2^-1/2S/3V5P1^5^4^-3^-2^-1/4S/6U4P1^3^4^-2^-1/" + "5V5P1^4^5^3^-4^-2^-1/6S/7V5P1^3^5^4^-2^-1/8R2P1^2^-1/11U3P1^3^2^-1/" + "9V4P1^-1^2^3^-3^4/10V5P1^-1^2^-3^4^4^5/11S/12V4P1^-1^2^3^4/" + "13V5P1^-1^2^3^4^4^5/14R1P1^1/16U4P1^1^2^3^4/15V5P1^1^2^3^4^-4^5/16S"; + static struct av1_extracfg default_extra_cfg = { 0, // cpu_used 1, // enable_auto_alt_ref @@ -173,7 +228,9 @@ 5, // gf_max_pyr_height AOM_TUNE_PSNR, // tuning "/usr/local/share/model/vmaf_v0.6.1.pkl", // VMAF model path - 10, // cq_level + NULL, // subgop_config_str + NULL, // subgop_config_path + 40, // qp 0, // rc_max_intra_bitrate_pct 0, // rc_max_inter_bitrate_pct 0, // gf_cbr_boost_pct @@ -369,7 +426,7 @@ RANGE_CHECK(cfg, g_timebase.num, 1, cfg->g_timebase.den); RANGE_CHECK_HI(cfg, g_profile, MAX_PROFILES - 1); - RANGE_CHECK_HI(cfg, rc_max_quantizer, 63); + RANGE_CHECK_HI(cfg, rc_max_quantizer, 255); RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer); RANGE_CHECK_BOOL(extra_cfg, lossless); RANGE_CHECK_HI(extra_cfg, aq_mode, AQ_MODE_COUNT - 1); @@ -381,15 +438,22 @@ RANGE_CHECK(cfg, rc_end_usage, AOM_VBR, AOM_Q); RANGE_CHECK_HI(cfg, rc_undershoot_pct, 100); RANGE_CHECK_HI(cfg, rc_overshoot_pct, 100); +#if !CONFIG_SINGLEPASS RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100); +#endif // !!CONFIG_SINGLEPASS RANGE_CHECK(cfg, kf_mode, AOM_KF_DISABLED, AOM_KF_AUTO); RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100); +#if CONFIG_SINGLEPASS + RANGE_CHECK(cfg, g_pass, AOM_RC_ONE_PASS, AOM_RC_ONE_PASS); + RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_TOTAL_BUFFERS); +#else RANGE_CHECK(cfg, g_pass, AOM_RC_ONE_PASS, AOM_RC_LAST_PASS); if (cfg->g_pass == AOM_RC_ONE_PASS) { RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_TOTAL_BUFFERS); } else { RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS); } +#endif // CONFIG_SINGLEPASS RANGE_CHECK_HI(extra_cfg, min_gf_interval, MAX_LAG_BUFFERS - 1); RANGE_CHECK_HI(extra_cfg, max_gf_interval, MAX_LAG_BUFFERS - 1); if (extra_cfg->max_gf_interval > 0) { @@ -414,8 +478,8 @@ SCALE_NUMERATOR << 1); RANGE_CHECK(cfg, rc_superres_kf_denominator, SCALE_NUMERATOR, SCALE_NUMERATOR << 1); - RANGE_CHECK(cfg, rc_superres_qthresh, 1, 63); - RANGE_CHECK(cfg, rc_superres_kf_qthresh, 1, 63); + RANGE_CHECK(cfg, rc_superres_qthresh, 1, 255); + RANGE_CHECK(cfg, rc_superres_kf_qthresh, 1, 255); RANGE_CHECK_HI(extra_cfg, cdf_update_mode, 2); RANGE_CHECK_HI(extra_cfg, motion_vector_unit_test, 2); @@ -445,11 +509,12 @@ RANGE_CHECK_HI(extra_cfg, sharpness, 7); RANGE_CHECK_HI(extra_cfg, arnr_max_frames, 15); RANGE_CHECK_HI(extra_cfg, arnr_strength, 6); - RANGE_CHECK_HI(extra_cfg, cq_level, 63); + RANGE_CHECK_HI(extra_cfg, qp, 255); RANGE_CHECK(cfg, g_bit_depth, AOM_BITS_8, AOM_BITS_12); RANGE_CHECK(cfg, g_input_bit_depth, 8, 12); RANGE_CHECK(extra_cfg, content, AOM_CONTENT_DEFAULT, AOM_CONTENT_INVALID - 1); +#if !CONFIG_SINGLEPASS if (cfg->g_pass == AOM_RC_LAST_PASS) { const size_t packet_sz = sizeof(FIRSTPASS_STATS); const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz); @@ -470,6 +535,7 @@ if ((int)(stats->count + 0.5) != n_packets - 1) ERROR("rc_twopass_stats_in missing EOS stats packet"); } +#endif // !CONFIG_SINGLEPASS if (cfg->g_profile <= (unsigned int)PROFILE_1 && cfg->g_bit_depth > AOM_BITS_10) { @@ -483,7 +549,7 @@ if (cfg->rc_end_usage == AOM_Q) { RANGE_CHECK_HI(cfg, use_fixed_qp_offsets, 1); for (int i = 0; i < FIXED_QP_OFFSET_COUNT; ++i) { - RANGE_CHECK_HI(cfg, fixed_qp_offsets[i], 63); + RANGE_CHECK_HI(cfg, fixed_qp_offsets[i], 255); } } else { if (cfg->use_fixed_qp_offsets > 0) { @@ -507,7 +573,11 @@ /* Average corpus complexity is supported only in the case of single pass * VBR*/ +#if CONFIG_SINGLEPASS + if (cfg->rc_end_usage == AOM_VBR) +#else if (cfg->g_pass == AOM_RC_ONE_PASS && cfg->rc_end_usage == AOM_VBR) +#endif // CONFIG_SINGLEPASS RANGE_CHECK_HI(extra_cfg, vbr_corpus_complexity_lap, MAX_VBR_CORPUS_COMPLEXITY); else if (extra_cfg->vbr_corpus_complexity_lap != 0) @@ -624,70 +694,116 @@ superres_cfg->superres_kf_qthresh = 255; } +static void update_encoder_config(cfg_options_t *cfg, + struct av1_extracfg *extra_cfg) { + cfg->enable_cdef = extra_cfg->enable_cdef; + cfg->enable_restoration = extra_cfg->enable_restoration; + cfg->superblock_size = + (extra_cfg->superblock_size == AOM_SUPERBLOCK_SIZE_64X64) + ? 64 + : (extra_cfg->superblock_size == AOM_SUPERBLOCK_SIZE_128X128) ? 128 + : 0; + cfg->enable_warped_motion = extra_cfg->enable_warped_motion; + cfg->enable_dist_wtd_comp = extra_cfg->enable_dist_wtd_comp; + cfg->enable_diff_wtd_comp = extra_cfg->enable_diff_wtd_comp; + cfg->enable_dual_filter = extra_cfg->enable_dual_filter; + cfg->enable_angle_delta = extra_cfg->enable_angle_delta; + cfg->enable_rect_partitions = extra_cfg->enable_rect_partitions; + cfg->enable_ab_partitions = extra_cfg->enable_ab_partitions; + cfg->enable_1to4_partitions = extra_cfg->enable_1to4_partitions; + cfg->max_partition_size = extra_cfg->max_partition_size; + cfg->min_partition_size = extra_cfg->min_partition_size; + cfg->enable_intra_edge_filter = extra_cfg->enable_intra_edge_filter; + cfg->enable_tx64 = extra_cfg->enable_tx64; + cfg->enable_flip_idtx = extra_cfg->enable_flip_idtx; + cfg->enable_masked_comp = extra_cfg->enable_masked_comp; + cfg->enable_interintra_comp = extra_cfg->enable_interintra_comp; + cfg->enable_smooth_interintra = extra_cfg->enable_smooth_interintra; + cfg->enable_interinter_wedge = extra_cfg->enable_interinter_wedge; + cfg->enable_interintra_wedge = extra_cfg->enable_interintra_wedge; + cfg->enable_global_motion = extra_cfg->enable_global_motion; + cfg->enable_filter_intra = extra_cfg->enable_filter_intra; + cfg->enable_smooth_intra = extra_cfg->enable_smooth_intra; + cfg->enable_paeth_intra = extra_cfg->enable_paeth_intra; + cfg->enable_cfl_intra = extra_cfg->enable_cfl_intra; + cfg->enable_obmc = extra_cfg->enable_obmc; + cfg->enable_palette = extra_cfg->enable_palette; + cfg->enable_intrabc = extra_cfg->enable_intrabc; + cfg->disable_trellis_quant = extra_cfg->disable_trellis_quant; + cfg->enable_ref_frame_mvs = + (extra_cfg->allow_ref_frame_mvs || extra_cfg->enable_ref_frame_mvs); + cfg->enable_onesided_comp = extra_cfg->enable_onesided_comp; + cfg->enable_reduced_reference_set = extra_cfg->enable_reduced_reference_set; + cfg->reduced_tx_type_set = extra_cfg->reduced_tx_type_set; +} + static void update_default_encoder_config(const cfg_options_t *cfg, struct av1_extracfg *extra_cfg) { - extra_cfg->enable_cdef = (cfg->disable_cdef == 0); - extra_cfg->enable_restoration = (cfg->disable_lr == 0); - extra_cfg->superblock_size = (cfg->super_block_size == 64) + extra_cfg->enable_cdef = cfg->enable_cdef; + extra_cfg->enable_restoration = cfg->enable_restoration; + extra_cfg->superblock_size = (cfg->superblock_size == 64) ? AOM_SUPERBLOCK_SIZE_64X64 - : (cfg->super_block_size == 128) + : (cfg->superblock_size == 128) ? AOM_SUPERBLOCK_SIZE_128X128 : AOM_SUPERBLOCK_SIZE_DYNAMIC; - extra_cfg->enable_warped_motion = (cfg->disable_warp_motion == 0); - extra_cfg->enable_dist_wtd_comp = (cfg->disable_dist_wtd_comp == 0); - extra_cfg->enable_diff_wtd_comp = (cfg->disable_diff_wtd_comp == 0); - extra_cfg->enable_dual_filter = (cfg->disable_dual_filter == 0); - extra_cfg->enable_angle_delta = (cfg->disable_intra_angle_delta == 0); - extra_cfg->enable_rect_partitions = (cfg->disable_rect_partition_type == 0); - extra_cfg->enable_ab_partitions = (cfg->disable_ab_partition_type == 0); - extra_cfg->enable_1to4_partitions = (cfg->disable_1to4_partition_type == 0); + extra_cfg->enable_warped_motion = cfg->enable_warped_motion; + extra_cfg->enable_dist_wtd_comp = cfg->enable_dist_wtd_comp; + extra_cfg->enable_diff_wtd_comp = cfg->enable_diff_wtd_comp; + extra_cfg->enable_dual_filter = cfg->enable_dual_filter; + extra_cfg->enable_angle_delta = cfg->enable_angle_delta; + extra_cfg->enable_rect_partitions = cfg->enable_rect_partitions; + extra_cfg->enable_ab_partitions = cfg->enable_ab_partitions; + extra_cfg->enable_1to4_partitions = cfg->enable_1to4_partitions; extra_cfg->max_partition_size = cfg->max_partition_size; extra_cfg->min_partition_size = cfg->min_partition_size; - extra_cfg->enable_intra_edge_filter = (cfg->disable_intra_edge_filter == 0); - extra_cfg->enable_tx64 = (cfg->disable_tx_64x64 == 0); - extra_cfg->enable_flip_idtx = (cfg->disable_flip_idtx == 0); - extra_cfg->enable_masked_comp = (cfg->disable_masked_comp == 0); - extra_cfg->enable_interintra_comp = (cfg->disable_inter_intra_comp == 0); - extra_cfg->enable_smooth_interintra = (cfg->disable_smooth_inter_intra == 0); - extra_cfg->enable_interinter_wedge = (cfg->disable_inter_inter_wedge == 0); - extra_cfg->enable_interintra_wedge = (cfg->disable_inter_intra_wedge == 0); - extra_cfg->enable_global_motion = (cfg->disable_global_motion == 0); - extra_cfg->enable_filter_intra = (cfg->disable_filter_intra == 0); - extra_cfg->enable_smooth_intra = (cfg->disable_smooth_intra == 0); - extra_cfg->enable_paeth_intra = (cfg->disable_paeth_intra == 0); - extra_cfg->enable_cfl_intra = (cfg->disable_cfl == 0); - extra_cfg->enable_obmc = (cfg->disable_obmc == 0); - extra_cfg->enable_palette = (cfg->disable_palette == 0); - extra_cfg->enable_intrabc = (cfg->disable_intrabc == 0); + extra_cfg->enable_intra_edge_filter = cfg->enable_intra_edge_filter; + extra_cfg->enable_tx64 = cfg->enable_tx64; + extra_cfg->enable_flip_idtx = cfg->enable_flip_idtx; + extra_cfg->enable_masked_comp = cfg->enable_masked_comp; + extra_cfg->enable_interintra_comp = cfg->enable_interintra_comp; + extra_cfg->enable_smooth_interintra = cfg->enable_smooth_interintra; + extra_cfg->enable_interinter_wedge = cfg->enable_interinter_wedge; + extra_cfg->enable_interintra_wedge = cfg->enable_interintra_wedge; + extra_cfg->enable_global_motion = cfg->enable_global_motion; + extra_cfg->enable_filter_intra = cfg->enable_filter_intra; + extra_cfg->enable_smooth_intra = cfg->enable_smooth_intra; + extra_cfg->enable_paeth_intra = cfg->enable_paeth_intra; + extra_cfg->enable_cfl_intra = cfg->enable_cfl_intra; + extra_cfg->enable_obmc = cfg->enable_obmc; + extra_cfg->enable_palette = cfg->enable_palette; + extra_cfg->enable_intrabc = cfg->enable_intrabc; extra_cfg->disable_trellis_quant = cfg->disable_trellis_quant; - extra_cfg->allow_ref_frame_mvs = (cfg->disable_ref_frame_mv == 0); - extra_cfg->enable_ref_frame_mvs = (cfg->disable_ref_frame_mv == 0); - extra_cfg->enable_onesided_comp = (cfg->disable_one_sided_comp == 0); - extra_cfg->enable_reduced_reference_set = cfg->reduced_reference_set; + extra_cfg->enable_ref_frame_mvs = cfg->enable_ref_frame_mvs; + extra_cfg->enable_onesided_comp = cfg->enable_onesided_comp; + extra_cfg->enable_reduced_reference_set = cfg->enable_reduced_reference_set; extra_cfg->reduced_tx_type_set = cfg->reduced_tx_type_set; } -static double convert_qp_offset(int cq_level, int q_offset, int bit_depth) { - const double base_q_val = av1_convert_qindex_to_q(cq_level, bit_depth); - const int new_q_index_offset = av1_quantizer_to_qindex(q_offset); - const int new_q_index = AOMMAX(cq_level - new_q_index_offset, 0); - const double new_q_val = av1_convert_qindex_to_q(new_q_index, bit_depth); +static double convert_qp_offset(int qp, int qp_offset, int bit_depth) { + const double base_q_val = av1_convert_qindex_to_q(qp, bit_depth); + const int new_qp = AOMMAX(qp - qp_offset, 0); + const double new_q_val = av1_convert_qindex_to_q(new_qp, bit_depth); return (base_q_val - new_q_val); } -static double get_modeled_qp_offset(int cq_level, int level, int bit_depth) { +static double get_modeled_qp_offset(int qp, int level, int bit_depth) { // 80% for keyframe was derived empirically. // 40% similar to rc_pick_q_and_bounds_one_pass_vbr() for Q mode ARF. // Rest derived similar to rc_pick_q_and_bounds_two_pass() static const int percents[FIXED_QP_OFFSET_COUNT] = { 76, 60, 30, 15, 8 }; - const double q_val = av1_convert_qindex_to_q(cq_level, bit_depth); + const double q_val = av1_convert_qindex_to_q(qp, bit_depth); return q_val * percents[level] / 100; } +// update_config parameter is used to indicate whether extra command line +// parameters are read. If extra command line parameters are read, then +// parameters in the configure file will not overwrite the parameters in +// extra_cfg. static aom_codec_err_t set_encoder_config(AV1EncoderConfig *oxcf, - const aom_codec_enc_cfg_t *cfg, - struct av1_extracfg *extra_cfg) { - if (cfg->encoder_cfg.init_by_cfg_file) { + aom_codec_enc_cfg_t *cfg, + struct av1_extracfg *extra_cfg, + int update_config) { + if (cfg->encoder_cfg.init_by_cfg_file && !update_config) { update_default_encoder_config(&cfg->encoder_cfg, extra_cfg); } @@ -744,6 +860,9 @@ input_cfg->input_bit_depth = cfg->g_input_bit_depth; // guess a frame rate if out of whack, use 30 input_cfg->init_framerate = (double)cfg->g_timebase.den / cfg->g_timebase.num; +#if CONFIG_SINGLEPASS + input_cfg->limit = cfg->g_limit; +#else if (cfg->g_pass == AOM_RC_LAST_PASS) { const size_t packet_sz = sizeof(FIRSTPASS_STATS); const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz); @@ -751,6 +870,7 @@ } else { input_cfg->limit = cfg->g_limit; } +#endif // CONFIG_SINGLEPASS input_cfg->chroma_subsampling_x = extra_cfg->chroma_subsampling_x; input_cfg->chroma_subsampling_y = extra_cfg->chroma_subsampling_y; if (input_cfg->init_framerate > 180) { @@ -791,8 +911,12 @@ switch (cfg->g_pass) { case AOM_RC_ONE_PASS: oxcf->pass = 0; break; +#if CONFIG_SINGLEPASS + default: oxcf->pass = 0; break; +#else case AOM_RC_FIRST_PASS: oxcf->pass = 1; break; case AOM_RC_LAST_PASS: oxcf->pass = 2; break; +#endif // !CONFIG_SINGLEPASS } // Set Rate Control configuration. @@ -801,11 +925,10 @@ rc_cfg->gf_cbr_boost_pct = extra_cfg->gf_cbr_boost_pct; rc_cfg->mode = cfg->rc_end_usage; rc_cfg->min_cr = extra_cfg->min_cr; - rc_cfg->best_allowed_q = - extra_cfg->lossless ? 0 : av1_quantizer_to_qindex(cfg->rc_min_quantizer); - rc_cfg->worst_allowed_q = - extra_cfg->lossless ? 0 : av1_quantizer_to_qindex(cfg->rc_max_quantizer); - rc_cfg->cq_level = av1_quantizer_to_qindex(extra_cfg->cq_level); + rc_cfg->best_allowed_q = extra_cfg->lossless ? 0 : cfg->rc_min_quantizer; + rc_cfg->worst_allowed_q = extra_cfg->lossless ? 0 : cfg->rc_max_quantizer; + rc_cfg->qp = extra_cfg->qp; + rc_cfg->under_shoot_pct = cfg->rc_undershoot_pct; rc_cfg->over_shoot_pct = cfg->rc_overshoot_pct; rc_cfg->maximum_buffer_size_ms = is_vbr ? 240000 : cfg->rc_buf_sz; @@ -815,7 +938,9 @@ rc_cfg->target_bandwidth = 1000 * cfg->rc_target_bitrate; rc_cfg->drop_frames_water_mark = cfg->rc_dropframe_thresh; rc_cfg->vbr_corpus_complexity_lap = extra_cfg->vbr_corpus_complexity_lap; +#if !CONFIG_SINGLEPASS rc_cfg->vbrbias = cfg->rc_2pass_vbr_bias_pct; +#endif // !CONFIG_SINGLEPASS rc_cfg->vbrmin_section = cfg->rc_2pass_vbr_minsection_pct; rc_cfg->vbrmax_section = cfg->rc_2pass_vbr_maxsection_pct; @@ -860,10 +985,10 @@ if (q_cfg->use_fixed_qp_offsets) { if (cfg->fixed_qp_offsets[i] >= 0) { // user-provided qp offset q_cfg->fixed_qp_offsets[i] = convert_qp_offset( - rc_cfg->cq_level, cfg->fixed_qp_offsets[i], tool_cfg->bit_depth); + rc_cfg->qp, cfg->fixed_qp_offsets[i], tool_cfg->bit_depth); } else { // auto-selected qp offset q_cfg->fixed_qp_offsets[i] = - get_modeled_qp_offset(rc_cfg->cq_level, i, tool_cfg->bit_depth); + get_modeled_qp_offset(rc_cfg->qp, i, tool_cfg->bit_depth); } } else { q_cfg->fixed_qp_offsets[i] = -1.0; @@ -899,8 +1024,10 @@ algo_cfg->enable_tpl_model = resize_cfg->resize_mode ? 0 : extra_cfg->enable_tpl_model; - // Set two-pass stats configuration. +// Set two-pass stats configuration. +#if !CONFIG_SINGLEPASS oxcf->twopass_stats_in = cfg->rc_twopass_stats_in; +#endif // !CONFIG_SINGLEPASS // Set Key frame configuration. kf_cfg->fwd_kf_enabled = cfg->fwd_kf_enabled; @@ -932,10 +1059,14 @@ gf_cfg->gf_min_pyr_height = extra_cfg->gf_min_pyr_height; gf_cfg->gf_max_pyr_height = extra_cfg->gf_max_pyr_height; + oxcf->subgop_config_str = extra_cfg->subgop_config_str; + oxcf->subgop_config_path = extra_cfg->subgop_config_path; + // Set tune related configuration. tune_cfg->tuning = extra_cfg->tuning; tune_cfg->vmaf_model_path = extra_cfg->vmaf_model_path; tune_cfg->content = extra_cfg->content; + if (cfg->large_scale_tile) { tune_cfg->film_grain_test_vector = 0; tune_cfg->film_grain_table_filename = NULL; @@ -1040,10 +1171,8 @@ (uint8_t)cfg->rc_superres_denominator; superres_cfg->superres_kf_scale_denominator = (uint8_t)cfg->rc_superres_kf_denominator; - superres_cfg->superres_qthresh = - av1_quantizer_to_qindex(cfg->rc_superres_qthresh); - superres_cfg->superres_kf_qthresh = - av1_quantizer_to_qindex(cfg->rc_superres_kf_qthresh); + superres_cfg->superres_qthresh = cfg->rc_superres_qthresh; + superres_cfg->superres_kf_qthresh = cfg->rc_superres_kf_qthresh; if (superres_cfg->superres_mode == AOM_SUPERRES_FIXED && superres_cfg->superres_scale_denominator == SCALE_NUMERATOR && superres_cfg->superres_kf_scale_denominator == SCALE_NUMERATOR) { @@ -1085,6 +1214,9 @@ sizeof(oxcf->target_seq_level_idx)); oxcf->tier_mask = extra_cfg->tier_mask; + if (update_config) { + update_encoder_config(&cfg->encoder_cfg, extra_cfg); + } return AOM_CODEC_OK; } @@ -1095,8 +1227,13 @@ int force_key = 0; if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) { +#if CONFIG_SINGLEPASS + if (cfg->g_lag_in_frames > 1) + ERROR("Cannot change width or height after initialization"); +#else if (cfg->g_lag_in_frames > 1 || cfg->g_pass != AOM_RC_ONE_PASS) ERROR("Cannot change width or height after initialization"); +#endif // CONFIG_SINGLEPASS if (!valid_ref_frame_size(ctx->cfg.g_w, ctx->cfg.g_h, cfg->g_w, cfg->g_h) || (initial_dimensions->width && (int)cfg->g_w > initial_dimensions->width) || @@ -1120,7 +1257,7 @@ if (res == AOM_CODEC_OK) { ctx->cfg = *cfg; - set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg); + set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg, 0); // On profile change, request a key frame force_key |= ctx->cpi->common.seq_params.profile != ctx->oxcf.profile; av1_change_config(ctx->cpi, &ctx->oxcf); @@ -1146,14 +1283,6 @@ return AOM_CODEC_OK; } -static aom_codec_err_t ctrl_get_quantizer64(aom_codec_alg_priv_t *ctx, - va_list args) { - int *const arg = va_arg(args, int *); - if (arg == NULL) return AOM_CODEC_INVALID_PARAM; - *arg = av1_qindex_to_quantizer(av1_get_quantizer(ctx->cpi)); - return AOM_CODEC_OK; -} - static aom_codec_err_t ctrl_get_baseline_gf_interval(aom_codec_alg_priv_t *ctx, va_list args) { int *const arg = va_arg(args, int *); @@ -1167,7 +1296,7 @@ const aom_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg); if (res == AOM_CODEC_OK) { ctx->extra_cfg = *extra_cfg; - set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg); + set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg, 1); av1_change_config(ctx->cpi, &ctx->oxcf); if (ctx->cpi_lap != NULL) { av1_change_config(ctx->cpi_lap, &ctx->oxcf); @@ -1275,10 +1404,9 @@ return update_extra_cfg(ctx, &extra_cfg); } -static aom_codec_err_t ctrl_set_cq_level(aom_codec_alg_priv_t *ctx, - va_list args) { +static aom_codec_err_t ctrl_set_qp(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; - extra_cfg.cq_level = CAST(AOME_SET_CQ_LEVEL, args); + extra_cfg.qp = CAST(AOME_SET_QP, args); return update_extra_cfg(ctx, &extra_cfg); } @@ -1761,6 +1889,20 @@ return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_subgop_config_str(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.subgop_config_str = CAST(AV1E_SET_SUBGOP_CONFIG_STR, args); + return update_extra_cfg(ctx, &extra_cfg); +} + +static aom_codec_err_t ctrl_set_subgop_config_path(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.subgop_config_path = CAST(AV1E_SET_SUBGOP_CONFIG_PATH, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static aom_codec_err_t ctrl_set_film_grain_test_vector( aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1983,9 +2125,11 @@ priv->timestamp_ratio.num = (int64_t)priv->cfg.g_timebase.num * TICKS_PER_SEC; reduce_ratio(&priv->timestamp_ratio); - - set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg); - if (priv->oxcf.rc_cfg.mode != AOM_CBR && priv->oxcf.pass == 0 && + set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg, 0); + if (priv->oxcf.rc_cfg.mode != AOM_CBR && +#if !CONFIG_SINGLEPASS + priv->oxcf.pass == 0 && +#endif // !CONFIG_SINGLEPASS priv->oxcf.mode == GOOD) { // Enable look ahead - enabled for AOM_Q, AOM_CQ, AOM_VBR *num_lap_buffers = priv->cfg.g_lag_in_frames; @@ -2077,6 +2221,77 @@ return flags; } +static void calculate_psnr(AV1_COMP *cpi, PSNR_STATS *psnr) { + int i; + PSNR_STATS stats; +#if CONFIG_AV1_HIGHBITDEPTH + const uint32_t in_bit_depth = cpi->oxcf.input_cfg.input_bit_depth; + const uint32_t bit_depth = cpi->td.mb.e_mbd.bd; + aom_calc_highbd_psnr(cpi->unfiltered_source, &cpi->common.cur_frame->buf, + &stats, bit_depth, in_bit_depth); +#else + aom_calc_psnr(cpi->unfiltered_source, &cpi->common.cur_frame->buf, psnr); +#endif + + for (i = 0; i < 4; ++i) { + psnr->psnr[i] = stats.psnr[i]; + } +} + +static void report_stats(AV1_COMP *cpi, size_t frame_size, uint64_t cx_time) { + const AV1_COMMON *const cm = &cpi->common; + const int base_qindex = cm->quant_params.base_qindex; + const char frameType[5][20] = { + " KEY ", "INTER", "INTRA", " S ", " UNK ", + }; + + PSNR_STATS psnr; + + for (int i = 0; i < 4; ++i) { + psnr.psnr[i] = 0; + } + + if (cpi->b_calculate_psnr) { + calculate_psnr(cpi, &psnr); + } + + if (!cm->show_existing_frame) { + // Get reference frame information + int ref_poc[INTER_REFS_PER_FRAME]; + for (int ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { + const int ref_idx = ref_frame - LAST_FRAME; + const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame); + ref_poc[ref_idx] = buf ? (int)buf->absolute_poc : -1; + } + if (cpi->b_calculate_psnr) { + fprintf(stdout, + "POC:%6d [%s][Q:%3d]: %10" PRIu64 + " Bytes, " + "%6.1fms, %2.4f dB(Y), %2.4f dB(U), " + "%2.4f dB(V), " + "%2.4f dB(Avg)", + cm->cur_frame->absolute_poc, + frameType[cm->current_frame.frame_type], base_qindex, + (uint64_t)frame_size, cx_time / 1000.0, psnr.psnr[1], + psnr.psnr[2], psnr.psnr[3], psnr.psnr[0]); + } else { + fprintf(stdout, + "POC:%6d [%s][Q:%3d]: %10" PRIu64 + " Bytes, " + "%6.1fms", + cm->cur_frame->absolute_poc, + frameType[cm->current_frame.frame_type], base_qindex, + (uint64_t)frame_size, cx_time / 1000.0); + } + + fprintf(stdout, " ["); + for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ++ref_idx) { + fprintf(stdout, "%3d,", ref_poc[ref_idx]); + } + fprintf(stdout, "]\n"); + } +} + // TODO(Mufaddal): Check feasibility of abstracting functions related to LAP // into a separate function. static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, @@ -2094,7 +2309,11 @@ if (cpi == NULL) return AOM_CODEC_INVALID_PARAM; +#if CONFIG_SINGLEPASS + if (cpi->lap_enabled && cpi_lap == NULL) +#else if (cpi->lap_enabled && cpi_lap == NULL && cpi->oxcf.pass == 0) +#endif // CONFIG_SINGLEPASS return AOM_CODEC_INVALID_PARAM; if (img != NULL) { @@ -2166,7 +2385,12 @@ if (res == AOM_CODEC_OK) { // Set up internal flags - if (ctx->base.init_flags & AOM_CODEC_USE_PSNR) cpi->b_calculate_psnr = 1; + if (ctx->base.init_flags & AOM_CODEC_USE_PSNR) { + cpi->b_calculate_psnr = 1; + } + if (ctx->base.init_flags & AOM_CODEC_USE_PER_FRAME_STATS) { + cpi->print_per_frame_stats = 1; + } if (img != NULL) { if (!ctx->pts_offset_initialized) { @@ -2249,6 +2473,9 @@ int has_no_show_keyframe = 0; int num_workers = 0; +#if CONFIG_SINGLEPASS + num_workers = av1_compute_num_enc_workers(cpi, cpi->oxcf.max_threads); +#else if (cpi->oxcf.pass == 1) { #if !CONFIG_REALTIME_ONLY num_workers = av1_fp_compute_num_enc_workers(cpi); @@ -2256,6 +2483,7 @@ } else { num_workers = av1_compute_num_enc_workers(cpi, cpi->oxcf.max_threads); } +#endif // CONFIG_SINGLEPASS if ((num_workers > 1) && (cpi->mt_info.num_workers == 0)) av1_create_workers(cpi, num_workers); @@ -2285,11 +2513,17 @@ // visible frame. int64_t dst_time_stamp; int64_t dst_end_time_stamp; + struct aom_usec_timer timer; while (cx_data_sz - index_size >= ctx->cx_data_sz / 2 && !is_frame_visible) { + uint64_t cx_time = 0; + aom_usec_timer_start(&timer); + const int status = av1_get_compressed_data( cpi, &lib_flags, &frame_size, cx_data, &dst_time_stamp, &dst_end_time_stamp, !img, timestamp_ratio); + aom_usec_timer_mark(&timer); + cx_time += aom_usec_timer_elapsed(&timer); if (status == -1) break; if (status != AOM_CODEC_OK) { aom_internal_error(&cpi->common.error, AOM_CODEC_ERROR, NULL); @@ -2361,6 +2595,10 @@ has_no_show_keyframe |= (!is_frame_visible && cpi->common.current_frame.frame_type == KEY_FRAME); + + if (cpi->print_per_frame_stats) { + report_stats(cpi, frame_size, cx_time); + } } } if (is_frame_visible) { @@ -2619,8 +2857,8 @@ for (tl = 0; tl < cm->number_temporal_layers; ++tl) { const int layer = LAYER_IDS_TO_IDX(sl, tl, cm->number_temporal_layers); LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer]; - lc->max_q = params->max_quantizers[layer]; - lc->min_q = params->min_quantizers[layer]; + lc->max_qp = params->max_quantizers[layer]; + lc->min_qp = params->min_quantizers[layer]; lc->scaling_factor_num = params->scaling_factor_num[sl]; lc->scaling_factor_den = params->scaling_factor_den[sl]; lc->layer_target_bitrate = 1000 * params->layer_target_bitrate[layer]; @@ -2770,7 +3008,7 @@ { AOME_SET_ARNR_MAXFRAMES, ctrl_set_arnr_max_frames }, { AOME_SET_ARNR_STRENGTH, ctrl_set_arnr_strength }, { AOME_SET_TUNING, ctrl_set_tuning }, - { AOME_SET_CQ_LEVEL, ctrl_set_cq_level }, + { AOME_SET_QP, ctrl_set_qp }, { AOME_SET_MAX_INTRA_BITRATE_PCT, ctrl_set_rc_max_intra_bitrate_pct }, { AOME_SET_NUMBER_SPATIAL_LAYERS, ctrl_set_number_spatial_layers }, { AV1E_SET_MAX_INTER_BITRATE_PCT, ctrl_set_rc_max_inter_bitrate_pct }, @@ -2856,6 +3094,8 @@ { AV1E_SET_SUPERBLOCK_SIZE, ctrl_set_superblock_size }, { AV1E_SET_SINGLE_TILE_DECODING, ctrl_set_single_tile_decoding }, { AV1E_SET_VMAF_MODEL_PATH, ctrl_set_vmaf_model_path }, + { AV1E_SET_SUBGOP_CONFIG_STR, ctrl_set_subgop_config_str }, + { AV1E_SET_SUBGOP_CONFIG_PATH, ctrl_set_subgop_config_path }, { AV1E_SET_FILM_GRAIN_TEST_VECTOR, ctrl_set_film_grain_test_vector }, { AV1E_SET_FILM_GRAIN_TABLE, ctrl_set_film_grain_table }, { AV1E_SET_DENOISE_NOISE_LEVEL, ctrl_set_denoise_noise_level }, @@ -2873,7 +3113,6 @@ // Getters { AOME_GET_LAST_QUANTIZER, ctrl_get_quantizer }, - { AOME_GET_LAST_QUANTIZER_64, ctrl_get_quantizer64 }, { AV1_GET_REFERENCE, ctrl_get_reference }, { AV1E_GET_ACTIVEMAP, ctrl_get_active_map }, { AV1_GET_NEW_FRAME_IMAGE, ctrl_get_new_frame_image }, @@ -2917,15 +3156,17 @@ AOM_SUPERRES_NONE, // rc_superres_mode SCALE_NUMERATOR, // rc_superres_denominator SCALE_NUMERATOR, // rc_superres_kf_denominator - 63, // rc_superres_qthresh - 32, // rc_superres_kf_qthresh + 255, // rc_superres_qthresh + 128, // rc_superres_kf_qthresh - AOM_VBR, // rc_end_usage + AOM_VBR, // rc_end_usage +#if !CONFIG_SINGLEPASS { NULL, 0 }, // rc_twopass_stats_in +#endif // !CONFIG_SINGLEPASS { NULL, 0 }, // rc_firstpass_mb_stats_in 256, // rc_target_bandwidth 0, // rc_min_quantizer - 63, // rc_max_quantizer + 255, // rc_max_quantizer 25, // rc_undershoot_pct 25, // rc_overshoot_pct @@ -2933,7 +3174,9 @@ 4000, // rc_buffer_initial_size 5000, // rc_buffer_optimal_size +#if !CONFIG_SINGLEPASS 50, // rc_two_pass_vbrbias +#endif // !CONFIG_SINGLEPASS 0, // rc_two_pass_vbrmin_section 2000, // rc_two_pass_vbrmax_section @@ -2954,8 +3197,8 @@ { 0 }, // tile_heights 0, // use_fixed_qp_offsets { -1, -1, -1, -1, -1 }, // fixed_qp_offsets - { 0, 128, 128, 4, 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 }, // cfg + { 0, 128, 128, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, // cfg }, { // NOLINT @@ -2987,15 +3230,17 @@ AOM_SUPERRES_NONE, // rc_superres_mode SCALE_NUMERATOR, // rc_superres_denominator SCALE_NUMERATOR, // rc_superres_kf_denominator - 63, // rc_superres_qthresh - 32, // rc_superres_kf_qthresh + 255, // rc_superres_qthresh + 128, // rc_superres_kf_qthresh - AOM_CBR, // rc_end_usage + AOM_CBR, // rc_end_usage +#if !CONFIG_SINGLEPASS { NULL, 0 }, // rc_twopass_stats_in +#endif // !CONFIG_SINGLEPASS { NULL, 0 }, // rc_firstpass_mb_stats_in 256, // rc_target_bandwidth 0, // rc_min_quantizer - 63, // rc_max_quantizer + 255, // rc_max_quantizer 25, // rc_undershoot_pct 25, // rc_overshoot_pct @@ -3003,7 +3248,9 @@ 4000, // rc_buffer_initial_size 5000, // rc_buffer_optimal_size +#if !CONFIG_SINGLEPASS 50, // rc_two_pass_vbrbias +#endif // !CONFIG_SINGLEPASS 0, // rc_two_pass_vbrmin_section 2000, // rc_two_pass_vbrmax_section @@ -3024,8 +3271,8 @@ { 0 }, // tile_heights 0, // use_fixed_qp_offsets { -1, -1, -1, -1, -1 }, // fixed_qp_offsets - { 0, 128, 128, 4, 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 }, // cfg + { 0, 128, 128, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, // cfg }, };
diff --git a/av1/common/av1_common_int.h b/av1/common/av1_common_int.h index eb5cd75..ad4b079 100644 --- a/av1/common/av1_common_int.h +++ b/av1/common/av1_common_int.h
@@ -134,7 +134,10 @@ // the limitation of get_relative_dist() which returns incorrect // distance when a very old frame is used as a reference. unsigned int display_order_hint; + unsigned int absolute_poc; unsigned int ref_display_order_hint[INTER_REFS_PER_FRAME]; + // Frame's level within the hierarchical structure + unsigned int pyramid_level; MV_REF *mvs; uint8_t *seg_map; @@ -320,6 +323,10 @@ unsigned int order_hint; unsigned int display_order_hint; + // Frame's level within the hierarchical structure + unsigned int pyramid_level; + unsigned int absolute_poc; + unsigned int key_frame_number; unsigned int frame_number; SkipModeInfo skip_mode_info; int refresh_frame_flags; // Which ref frames are overwritten by this frame
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c index 56fab62..1fcf3cf 100644 --- a/av1/common/mvref_common.c +++ b/av1/common/mvref_common.c
@@ -838,6 +838,8 @@ void av1_setup_frame_buf_refs(AV1_COMMON *cm) { cm->cur_frame->order_hint = cm->current_frame.order_hint; cm->cur_frame->display_order_hint = cm->current_frame.display_order_hint; + cm->cur_frame->absolute_poc = cm->current_frame.absolute_poc; + cm->cur_frame->pyramid_level = cm->current_frame.pyramid_level; MV_REFERENCE_FRAME ref_frame; for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
diff --git a/av1/encoder/aq_complexity.c b/av1/encoder/aq_complexity.c index 3ea5f63..b5f1efc 100644 --- a/av1/encoder/aq_complexity.c +++ b/av1/encoder/aq_complexity.c
@@ -158,10 +158,14 @@ cm->seq_params.bit_depth); aom_clear_system_state(); +#if CONFIG_SINGLEPASS + low_var_thresh = DEFAULT_LV_THRESH; +#else low_var_thresh = (is_stat_consumption_stage_twopass(cpi)) ? AOMMAX(exp(cpi->twopass.mb_av_energy), MIN_DEFAULT_LV_THRESH) : DEFAULT_LV_THRESH; +#endif // CONFIG_SINGLEPASS av1_setup_src_planes(mb, cpi->source, mi_row, mi_col, num_planes, bs); logvar = av1_log_block_var(cpi, mb, bs);
diff --git a/av1/encoder/aq_variance.c b/av1/encoder/aq_variance.c index 92d7ad1..86a6995 100644 --- a/av1/encoder/aq_variance.c +++ b/av1/encoder/aq_variance.c
@@ -177,9 +177,14 @@ BLOCK_SIZE bs) { double energy, energy_midpoint; aom_clear_system_state(); +#if CONFIG_SINGLEPASS + (void)cpi; + energy_midpoint = DEFAULT_E_MIDPOINT; +#else energy_midpoint = (is_stat_consumption_stage_twopass(cpi)) ? cpi->twopass.frame_avg_haar_energy : DEFAULT_E_MIDPOINT; +#endif // CONFIG_SINGLEPASS energy = av1_log_block_wavelet_energy(x, bs) - energy_midpoint; return clamp((int)round(energy), ENERGY_MIN, ENERGY_MAX); }
diff --git a/av1/encoder/av1_quantize.c b/av1/encoder/av1_quantize.c index 45eba9a..2669c9d 100644 --- a/av1/encoder/av1_quantize.c +++ b/av1/encoder/av1_quantize.c
@@ -774,26 +774,3 @@ aom_get_qmlevel(quant_params->base_qindex + quant_params->v_ac_delta_q, min_qmlevel, max_qmlevel); } - -// Table that converts 0-63 Q-range values passed in outside to the Qindex -// range used internally. -static const int quantizer_to_qindex[] = { - 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, - 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, - 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, - 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, - 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 249, 255, -}; - -int av1_quantizer_to_qindex(int quantizer) { - return quantizer_to_qindex[quantizer]; -} - -int av1_qindex_to_quantizer(int qindex) { - int quantizer; - - for (quantizer = 0; quantizer < 64; ++quantizer) - if (quantizer_to_qindex[quantizer] >= qindex) return quantizer; - - return 63; -}
diff --git a/av1/encoder/av1_quantize.h b/av1/encoder/av1_quantize.h index ad96197..f1d0c91 100644 --- a/av1/encoder/av1_quantize.h +++ b/av1/encoder/av1_quantize.h
@@ -111,10 +111,6 @@ void av1_set_quantizer(struct AV1Common *const cm, int min_qmlevel, int max_qmlevel, int q, int enable_chroma_deltaq); -int av1_quantizer_to_qindex(int quantizer); - -int av1_qindex_to_quantizer(int qindex); - void av1_quantize_skip(intptr_t n_coeffs, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr);
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c index 647ce9f..f407a3e 100644 --- a/av1/encoder/encode_strategy.c +++ b/av1/encoder/encode_strategy.c
@@ -44,6 +44,15 @@ refresh_frame_flags->alt_ref_frame = refresh_arf; } +// Get the subgop config corresponding to the current frame within the +// gf group +const SubGOPStepCfg *get_subgop_step(const GF_GROUP *const gf_group, + int index) { + const SubGOPCfg *subgop_cfg = gf_group->subgop_cfg; + if (subgop_cfg == NULL) return NULL; + return index == 0 ? gf_group->last_step_prev : &subgop_cfg->step[index - 1]; +} + void av1_configure_buffer_updates( AV1_COMP *const cpi, RefreshFrameFlagsInfo *const refresh_frame_flags, const FRAME_UPDATE_TYPE type, const FRAME_TYPE frame_type, @@ -262,6 +271,109 @@ return primary_ref_frame; } +// Map the subgop cfg reference list to actual reference buffers. Disable +// any reference frames that are not listed in the sub gop. +static void get_gop_cfg_enabled_refs(AV1_COMP *const cpi, int *ref_frame_flags, + int order_offset) { + GF_GROUP gf_group = cpi->gf_group; + // The current display index stored has not yet been updated. We must add + // The order offset to get the correct value here. + const int cur_frame_disp = + cpi->common.current_frame.frame_number + order_offset; + + const SubGOPStepCfg *step_gop_cfg = + get_subgop_step(&gf_group, gf_group.index); + assert(step_gop_cfg != NULL); + // No references specified + if (step_gop_cfg->num_references < 0) return; + + // Mask to indicate whether or not each ref is allowed by the GOP config + int ref_frame_used[REF_FRAMES] = { 0 }; + // Structures to hash each reference frame based on its pyramid level. This + // will allow us to match the pyramid levels specified in the cfg to the best + // reference frame index. + int n_references[MAX_ARF_LAYERS + 1] = { 0 }; + int references[MAX_ARF_LAYERS + 1][REF_FRAMES] = { { 0 } }; + int disp_orders[MAX_ARF_LAYERS + 1][REF_FRAMES] = { { 0 } }; + + int frame_level = -1; + // Loop over each reference frame and hash it based on its pyramid level + for (int frame = LAST_FRAME; frame <= ALTREF_FRAME; frame++) { + // Get reference frame buffer + const RefCntBuffer *const buf = get_ref_frame_buf(&cpi->common, frame); + if (buf == NULL) continue; + const int frame_order = (int)buf->display_order_hint; + frame_level = buf->pyramid_level; + + // Handle special cases where the pyramid level computed in the gf group + // won't match the assumptions made in the subgop cfg. + if (frame_order == 0) { + // Keyframe case + frame_level = 1; + } else if (frame_level == MAX_ARF_LAYERS) { + // Leaves + frame_level = gf_group.max_layer_depth; + } else if (frame_level == (MAX_ARF_LAYERS + 1)) { + // Altrefs + frame_level = 1; + } + + // Sometimes a frame index is in multiple reference buffers. + // Do not add a frame to the pyramid list multiple times. + int found = 0; + for (int r = 0; r < n_references[frame_level]; r++) { + if (frame_order == disp_orders[frame_level][r]) { + found = 1; + break; + } + } + // If this is an unseen frame, map its display order and ref buffer + // index to its level in the pyramid + if (!found) { + int n_refs = n_references[frame_level]++; + disp_orders[frame_level][n_refs] = frame_order; + references[frame_level][n_refs] = frame; + } + } + + // For each reference specified in the step_gop_cfg, map it to a reference + // buffer based on pyramid level if possible. + for (int i = 0; i < step_gop_cfg->num_references; i++) { + const int level = step_gop_cfg->references[i]; + const int abs_level = abs(level); + int best_frame = -1; + int best_frame_index = -1; + int best_disp_order = INT_MAX; + for (int ref = 0; ref < n_references[abs_level]; ref++) { + const int disp_order = disp_orders[abs_level][ref]; + const int cur_order_diff = cur_frame_disp - disp_order; + // This frame has already been used + if (disp_order < 0) continue; + // This frame is in the wrong direction + if ((cur_order_diff < 0) != (level < 0)) continue; + // Store this frame if it is the closest in display order to the current + // frame so far + if (abs(cur_order_diff) < abs(best_disp_order - cur_frame_disp)) { + best_frame = references[abs_level][ref]; + best_frame_index = ref; + best_disp_order = disp_order; + } + } + if (best_frame == -1) { + fprintf(stderr, "GOP CFG REF FRAME WARNING\n"); + } else { + ref_frame_used[best_frame] = 1; + disp_orders[abs_level][best_frame_index] = -1; + } + } + + // Avoid using references that were not specified by the cfg + for (int frame = LAST_FRAME; frame <= ALTREF_FRAME; frame++) { + if (!ref_frame_used[frame]) + *ref_frame_flags &= ~(1 << (frame - LAST_FRAME)); + } +} + static void update_fb_of_context_type( const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params, int *const fb_of_context_type) { @@ -588,13 +700,87 @@ } } +// Update reference frame stack info according to the subgop cfg +static void update_ref_frame_map_gopcfg(AV1_COMP *cpi, int gf_index, + int show_existing_frame, + int ref_map_index, + RefBufferStack *ref_buffer_stack) { + GF_GROUP gf_group = cpi->gf_group; + AV1_COMMON *const cm = &cpi->common; + + if (is_frame_droppable(&cpi->svc, &cpi->ext_flags.refresh_frame)) return; + if (cm->current_frame.frame_type == KEY_FRAME || frame_is_sframe(cm)) { + if (show_existing_frame) + ref_map_index = stack_pop(ref_buffer_stack->arf_stack, + &ref_buffer_stack->arf_stack_size); + stack_reset(ref_buffer_stack->lst_stack, &ref_buffer_stack->lst_stack_size); + stack_reset(ref_buffer_stack->gld_stack, &ref_buffer_stack->gld_stack_size); + stack_reset(ref_buffer_stack->arf_stack, &ref_buffer_stack->arf_stack_size); + stack_push(ref_buffer_stack->gld_stack, &ref_buffer_stack->gld_stack_size, + ref_map_index); + } else { + const SubGOPStepCfg *step_gop_cfg = get_subgop_step(&gf_group, gf_index); + + const int pyr_level = step_gop_cfg->pyr_level; + const FRAME_TYPE_CODE type_code = step_gop_cfg->type_code; + switch (type_code) { + case FRAME_TYPE_INO_REPEAT: + if (pyr_level == 1) { + ref_map_index = stack_pop(ref_buffer_stack->arf_stack, + &ref_buffer_stack->arf_stack_size); + stack_push(ref_buffer_stack->gld_stack, + &ref_buffer_stack->gld_stack_size, ref_map_index); + } else { + ref_map_index = stack_pop(ref_buffer_stack->arf_stack, + &ref_buffer_stack->arf_stack_size); + stack_push(ref_buffer_stack->lst_stack, + &ref_buffer_stack->lst_stack_size, ref_map_index); + } + break; + case FRAME_TYPE_INO_VISIBLE: + update_arf_stack(ref_map_index, ref_buffer_stack); + stack_push(ref_buffer_stack->lst_stack, + &ref_buffer_stack->lst_stack_size, ref_map_index); + break; + case FRAME_TYPE_INO_SHOWEXISTING: + ref_map_index = stack_pop(ref_buffer_stack->arf_stack, + &ref_buffer_stack->arf_stack_size); + stack_push(ref_buffer_stack->lst_stack, + &ref_buffer_stack->lst_stack_size, ref_map_index); + break; + case FRAME_TYPE_OOO_FILTERED: + case FRAME_TYPE_OOO_UNFILTERED: + update_arf_stack(ref_map_index, ref_buffer_stack); + stack_push(ref_buffer_stack->arf_stack, + &ref_buffer_stack->arf_stack_size, ref_map_index); + break; + default: assert(0 && "unknown type"); + } + } + return; +} + +int use_subgop_cfg(const GF_GROUP *const gf_group, int gf_index) { + if (gf_index < 0) return 0; + if (gf_group->subgop_cfg == NULL) return 0; + if (gf_index == 0) return gf_group->last_step_prev != NULL; + return 1; +} + // Update reference frame stack info. void av1_update_ref_frame_map(AV1_COMP *cpi, FRAME_UPDATE_TYPE frame_update_type, - FRAME_TYPE frame_type, int show_existing_frame, - int ref_map_index, + FRAME_TYPE frame_type, int gf_index, + int show_existing_frame, int ref_map_index, RefBufferStack *ref_buffer_stack) { AV1_COMMON *const cm = &cpi->common; + if (use_subgop_cfg(&cpi->gf_group, gf_index)) { + // Use the subgop cfg to update the ref frame map + update_ref_frame_map_gopcfg(cpi, gf_index, show_existing_frame, + ref_map_index, ref_buffer_stack); + return; + } + // TODO(jingning): Consider the S-frame same as key frame for the // reference frame tracking purpose. The logic might be better // expressed than converting the frame update type. @@ -691,9 +877,70 @@ return INVALID_IDX; } +static int get_refresh_frame_flags_subgop_cfg( + const AV1_COMP *const cpi, const RefBufferStack *const ref_buffer_stack, + int gf_index, int refresh_mask, int free_fb_index) { + const SubGOPStepCfg *step_gop_cfg = get_subgop_step(&cpi->gf_group, gf_index); + assert(step_gop_cfg != NULL); + const int pyr_level = step_gop_cfg->pyr_level; + const FRAME_TYPE_CODE type_code = step_gop_cfg->type_code; + // No refresh necessary for these frame types + if (type_code == FRAME_TYPE_INO_REPEAT || + type_code == FRAME_TYPE_INO_SHOWEXISTING) + return refresh_mask; + // If there is an open slot, refresh that one instead of replacing a reference + if (free_fb_index != INVALID_IDX) { + refresh_mask = 1 << free_fb_index; + return refresh_mask; + } + + switch (type_code) { + case FRAME_TYPE_INO_VISIBLE: + if (ref_buffer_stack->lst_stack_size >= 2) + refresh_mask = + 1 << ref_buffer_stack + ->lst_stack[ref_buffer_stack->lst_stack_size - 1]; + else if (ref_buffer_stack->gld_stack_size >= 2) + refresh_mask = + 1 << ref_buffer_stack + ->gld_stack[ref_buffer_stack->gld_stack_size - 1]; + else + assert(0 && "No ref map index found"); + break; + case FRAME_TYPE_OOO_FILTERED: + if (pyr_level == 1) { + if (ref_buffer_stack->gld_stack_size >= 3) + refresh_mask = + 1 << ref_buffer_stack + ->gld_stack[ref_buffer_stack->gld_stack_size - 1]; + else if (ref_buffer_stack->lst_stack_size >= 2) + refresh_mask = + 1 << ref_buffer_stack + ->lst_stack[ref_buffer_stack->lst_stack_size - 1]; + else + assert(0 && "No ref map index found"); + + } else { + refresh_mask = + 1 << ref_buffer_stack + ->lst_stack[ref_buffer_stack->lst_stack_size - 1]; + } + break; + case FRAME_TYPE_OOO_UNFILTERED: + refresh_mask = 1 << ref_buffer_stack + ->lst_stack[ref_buffer_stack->lst_stack_size - 1]; + break; + case FRAME_TYPE_INO_REPEAT: + case FRAME_TYPE_INO_SHOWEXISTING: + default: assert(0); break; + } + return refresh_mask; +} + int av1_get_refresh_frame_flags(const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params, FRAME_UPDATE_TYPE frame_update_type, + int gf_index, const RefBufferStack *const ref_buffer_stack) { const AV1_COMMON *const cm = &cpi->common; const ExtRefreshFrameFlagsInfo *const ext_refresh_frame_flags = @@ -763,6 +1010,11 @@ // Search for the open slot to store the current frame. int free_fb_index = get_free_ref_map_index(ref_buffer_stack); + + if (use_subgop_cfg(&cpi->gf_group, gf_index)) { + return get_refresh_frame_flags_subgop_cfg(cpi, ref_buffer_stack, gf_index, + refresh_mask, free_fb_index); + } switch (frame_update_type) { case KF_UPDATE: case GF_UPDATE: @@ -905,6 +1157,9 @@ get_frame_update_type(&cpi->gf_group) == INTNL_ARF_UPDATE) { // ARF apply_filtering = oxcf->algo_cfg.arnr_max_frames > 0; + if (gf_group->is_user_specified) { + apply_filtering &= gf_group->is_filtered[gf_group->index]; + } if (apply_filtering) { arf_src_index = gf_group->arf_src_offset[gf_group->index]; } @@ -1176,7 +1431,11 @@ if (use_one_pass_rt_params) { av1_get_one_pass_rt_params(cpi, &frame_params, *frame_flags); } else if (!is_stat_generation_stage(cpi)) { - av1_get_second_pass_params(cpi, &frame_params, &frame_input, *frame_flags); + av1_get_second_pass_params(cpi, &frame_params, +#if !CONFIG_SINGLEPASS + &frame_input, +#endif // !CONFIG_SINGLEPASS + *frame_flags); } #endif FRAME_UPDATE_TYPE frame_update_type = get_frame_update_type(gf_group); @@ -1267,8 +1526,15 @@ choose_primary_ref_frame(cpi, &frame_params); frame_params.order_offset = gf_group->arf_src_offset[gf_group->index]; + if (!is_stat_generation_stage(cpi) && + use_subgop_cfg(&cpi->gf_group, cpi->gf_group.index)) { + get_gop_cfg_enabled_refs(cpi, &frame_params.ref_frame_flags, + frame_params.order_offset); + } + frame_params.refresh_frame_flags = av1_get_refresh_frame_flags( - cpi, &frame_params, frame_update_type, &cpi->ref_buffer_stack); + cpi, &frame_params, frame_update_type, cpi->gf_group.index, + &cpi->ref_buffer_stack); frame_params.existing_fb_idx_to_show = frame_params.show_existing_frame @@ -1320,8 +1586,8 @@ int ref_map_index = av1_get_refresh_ref_frame_map(cm->current_frame.refresh_frame_flags); av1_update_ref_frame_map(cpi, frame_update_type, frame_params.frame_type, - cm->show_existing_frame, ref_map_index, - &cpi->ref_buffer_stack); + cpi->gf_group.index, cm->show_existing_frame, + ref_map_index, &cpi->ref_buffer_stack); } }
diff --git a/av1/encoder/encode_strategy.h b/av1/encoder/encode_strategy.h index 4bafb0a..e17ac2f 100644 --- a/av1/encoder/encode_strategy.h +++ b/av1/encoder/encode_strategy.h
@@ -69,14 +69,15 @@ int av1_get_refresh_frame_flags(const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params, FRAME_UPDATE_TYPE frame_update_type, + int gf_index, const RefBufferStack *const ref_buffer_stack); int av1_get_refresh_ref_frame_map(int refresh_frame_flags); void av1_update_ref_frame_map(AV1_COMP *cpi, FRAME_UPDATE_TYPE frame_update_type, - FRAME_TYPE frame_type, int show_existing_frame, - int ref_map_index, + FRAME_TYPE frame_type, int gf_index, + int show_existing_frame, int ref_map_index, RefBufferStack *ref_buffer_stack); void av1_get_ref_frames(AV1_COMP *const cpi, RefBufferStack *ref_buffer_stack);
diff --git a/av1/encoder/encodeframe_utils.c b/av1/encoder/encodeframe_utils.c index 695084f..cbeb58b 100644 --- a/av1/encoder/encodeframe_utils.c +++ b/av1/encoder/encodeframe_utils.c
@@ -729,6 +729,7 @@ int bottom_edge = cpi->common.mi_params.mi_rows; int is_active_h_edge = 0; +#if !CONFIG_SINGLEPASS // For two pass account for any formatting bars detected. if (is_stat_consumption_stage_twopass(cpi)) { const AV1_COMMON *const cm = &cpi->common; @@ -743,6 +744,7 @@ bottom_edge -= (int)(this_frame_stats->inactive_zone_rows * 4); bottom_edge = AOMMAX(top_edge, bottom_edge); } +#endif // !CONFIG_SINGLEPASS if (((top_edge >= mi_row) && (top_edge < (mi_row + mi_step))) || ((bottom_edge >= mi_row) && (bottom_edge < (mi_row + mi_step)))) { @@ -759,6 +761,7 @@ int right_edge = cpi->common.mi_params.mi_cols; int is_active_v_edge = 0; +#if !CONFIG_SINGLEPASS // For two pass account for any formatting bars detected. if (is_stat_consumption_stage_twopass(cpi)) { const AV1_COMMON *const cm = &cpi->common; @@ -773,6 +776,7 @@ right_edge -= (int)(this_frame_stats->inactive_zone_cols * 4); right_edge = AOMMAX(left_edge, right_edge); } +#endif // !CONFIG_SINGLEPASS if (((left_edge >= mi_col) && (left_edge < (mi_col + mi_step))) || ((right_edge >= mi_col) && (right_edge < (mi_col + mi_step)))) {
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index b829e55..f763b16 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -13,6 +13,7 @@ #include <float.h> #include <math.h> #include <stdio.h> +#include <string.h> #include "config/aom_config.h" @@ -67,11 +68,12 @@ #include "av1/encoder/rc_utils.h" #include "av1/encoder/rd.h" #include "av1/encoder/rdopt.h" +#include "av1/encoder/reconinter_enc.h" #include "av1/encoder/segmentation.h" #include "av1/encoder/speed_features.h" +#include "av1/encoder/subgop.h" #include "av1/encoder/superres_scale.h" #include "av1/encoder/tpl_model.h" -#include "av1/encoder/reconinter_enc.h" #include "av1/encoder/var_based_part.h" #if CONFIG_TUNE_VMAF @@ -578,6 +580,13 @@ av1_noise_estimate_init(&cpi->noise_estimate, cm->width, cm->height); } +int aom_strcmp(const char *a, const char *b) { + if (a == NULL && b == NULL) return 0; + if (a == NULL && b != NULL) return -1; + if (a != NULL && b == NULL) return 1; + return strcmp(a, b); +} + void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { AV1_COMMON *const cm = &cpi->common; SequenceHeader *const seq_params = &cm->seq_params; @@ -793,6 +802,42 @@ if (lap_lag_in_frames != -1) { cpi->oxcf.gf_cfg.lag_in_frames = lap_lag_in_frames; } + + bool subgop_config_changed = false; + if (aom_strcmp(cpi->subgop_config_path, oxcf->subgop_config_path)) { + aom_free(cpi->subgop_config_path); + if (oxcf->subgop_config_path != NULL) { + cpi->subgop_config_path = + (char *)aom_malloc((strlen(oxcf->subgop_config_path) + 1) * + sizeof(*oxcf->subgop_config_path)); + strcpy(cpi->subgop_config_path, oxcf->subgop_config_path); + } + subgop_config_changed = true; + } + if (aom_strcmp(cpi->subgop_config_str, oxcf->subgop_config_str)) { + aom_free(cpi->subgop_config_str); + if (oxcf->subgop_config_str != NULL) { + cpi->subgop_config_str = + (char *)aom_malloc((strlen(oxcf->subgop_config_str) + 1) * + sizeof(*oxcf->subgop_config_str)); + strcpy(cpi->subgop_config_str, oxcf->subgop_config_str); + } + subgop_config_changed = true; + } + if (subgop_config_changed && cpi->compressor_stage == ENCODE_STAGE) { + av1_init_subgop_config_set(&cpi->subgop_config_set); + // Parse config file first + av1_process_subgop_config_set_fromfile(cpi->subgop_config_path, + &cpi->subgop_config_set); + // Parse config string next, which may override config file configs + // or append to it. + av1_process_subgop_config_set(cpi->subgop_config_str, + &cpi->subgop_config_set); + printf("Successfully processed %d subgop configs.\n", + cpi->subgop_config_set.num_configs); + // Uncomment to print out the configuration + // av1_print_subgop_config_set(&cpi->subgop_config_set); + } } static INLINE void init_frame_info(FRAME_INFO *frame_info, @@ -839,9 +884,15 @@ CommonModeInfoParams *const mi_params = &cm->mi_params; mi_params->free_mi = enc_free_mi; mi_params->setup_mi = enc_setup_mi; +#if CONFIG_SINGLEPASS + mi_params->set_mb_mi = (cpi->compressor_stage == LAP_STAGE) + ? stat_stage_set_mb_mi + : enc_set_mb_mi; +#else mi_params->set_mb_mi = (oxcf->pass == 1 || cpi->compressor_stage == LAP_STAGE) ? stat_stage_set_mb_mi : enc_set_mb_mi; +#endif // CONFIG_SINGLEPASS mi_params->mi_alloc_bsize = BLOCK_4X4; @@ -862,7 +913,11 @@ cpi->frames_left = cpi->oxcf.input_cfg.limit; +#if CONFIG_SINGLEPASS + av1_rc_init(&cpi->oxcf, 0, &cpi->rc); +#else av1_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc); +#endif // CONFIG_SINGLEPASS // For two pass and lag_in_frames > 33 in LAP. cpi->rc.enable_scenecut_detection = ENABLE_SCENECUT_MODE_2; @@ -883,6 +938,7 @@ init_frame_info(&cpi->frame_info, cm); cm->current_frame.frame_number = 0; + cm->current_frame.key_frame_number = 0; cm->current_frame_id = -1; cpi->seq_params_locked = 0; cpi->partition_search_skippable_frame = 0; @@ -950,6 +1006,9 @@ #if !CONFIG_REALTIME_ONLY if (is_stat_consumption_stage(cpi)) { +#if CONFIG_SINGLEPASS + av1_init_single_pass_lap(cpi); +#else const size_t packet_sz = sizeof(FIRSTPASS_STATS); const int packets = (int)(oxcf->twopass_stats_in.sz / packet_sz); @@ -960,13 +1019,13 @@ cpi->twopass.stats_in = cpi->twopass.stats_buf_ctx->stats_in_start; cpi->twopass.stats_buf_ctx->stats_in_end = &cpi->twopass.stats_buf_ctx->stats_in_start[packets - 1]; - av1_init_second_pass(cpi); } else { av1_init_single_pass_lap(cpi); } +#endif // CONFIG_SINGLEPASS } -#endif +#endif // !CONFIG_REALTIME_ONLY int sb_mi_size = av1_get_sb_mi_size(cm); @@ -1469,6 +1528,8 @@ av1_remove_common(cm); av1_free_ref_frame_buffers(cm->buffer_pool); + aom_free(cpi->subgop_config_str); + aom_free(cpi->subgop_config_path); aom_free(cpi); #ifdef OUTPUT_YUV_REC @@ -2234,10 +2295,12 @@ assert(IMPLIES(oxcf->rc_cfg.min_cr > 0, allow_recode)); set_size_independent_vars(cpi); +#if !CONFIG_SINGLEPASS if (is_stat_consumption_stage_twopass(cpi) && cpi->sf.interp_sf.adaptive_interp_filter_search) cpi->interp_search_flags.interp_filter_search_mask = av1_setup_interp_filter_search_mask(cpi); +#endif // !CONFIG_SINGLEPASS cpi->source->buf_8bit_valid = 0; av1_setup_frame_size(cpi); @@ -3104,15 +3167,34 @@ memcpy(&cpi->refresh_frame, &frame_params->refresh_frame, sizeof(cpi->refresh_frame)); - if (current_frame->frame_type == KEY_FRAME && !cpi->no_show_fwd_kf) + if (current_frame->frame_type == KEY_FRAME && !cpi->no_show_fwd_kf) { + current_frame->key_frame_number += current_frame->frame_number; current_frame->frame_number = 0; + } current_frame->order_hint = current_frame->frame_number + frame_params->order_offset; current_frame->display_order_hint = current_frame->order_hint; + current_frame->pyramid_level = cpi->gf_group.layer_depth[cpi->gf_group.index]; + + current_frame->absolute_poc = + current_frame->key_frame_number + current_frame->display_order_hint; + current_frame->order_hint %= (1 << (cm->seq_params.order_hint_info.order_hint_bits_minus_1 + 1)); +#if CONFIG_SINGLEPASS + if (is_stat_generation_stage(cpi)) { +#if !CONFIG_REALTIME_ONLY + av1_first_pass(cpi, frame_input->ts_duration); +#endif + } else { + if (encode_frame_to_data_rate(cpi, &frame_results->size, dest) != + AOM_CODEC_OK) { + return AOM_CODEC_ERROR; + } + } +#else // CONFIG_SINGLEPASS if (is_stat_generation_stage(cpi)) { #if !CONFIG_REALTIME_ONLY av1_first_pass(cpi, frame_input->ts_duration); @@ -3125,6 +3207,7 @@ } else { return AOM_CODEC_ERROR; } +#endif // CONFIG_SINGLEPASS return AOM_CODEC_OK; }
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index 43279ec..4f937ba 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -489,12 +489,13 @@ /*! * Indicates the Constant/Constrained Quality level. */ - int cq_level; + int qp; /*! * Indicates if the encoding mode is vbr, cbr, constrained quality or * constant quality. */ enum aom_rc_mode mode; +#if !CONFIG_SINGLEPASS /*! * Indicates the bias (expressed on a scale of 0 to 100) for determining * target size for the current frame. The value 0 indicates the optimal CBR @@ -502,6 +503,7 @@ * should be used. */ int vbrbias; +#endif // !CONFIG_SINGLEPASS /*! * Indicates the minimum bitrate to be used for a single frame as a percentage * of the target bitrate. @@ -669,11 +671,10 @@ typedef struct { // List of QP offsets for: keyframe, ALTREF, and 3 levels of internal ARFs. // If any of these values are negative, fixed offsets are disabled. - // Uses internal q range. double fixed_qp_offsets[FIXED_QP_OFFSET_COUNT]; // If true, encoder will use fixed QP offsets, that are either: // - Given by the user, and stored in 'fixed_qp_offsets' array, OR - // - Picked automatically from cq_level. + // - Picked automatically from qp. int use_fixed_qp_offsets; // Indicates the minimum flatness of the quantization matrix. int qm_minlevel; @@ -779,6 +780,77 @@ bool enable_palette; } ToolCfg; +#define MAX_SUBGOP_CONFIGS 64 +#define MAX_SUBGOP_STEPS 64 +#define MAX_SUBGOP_LENGTH 32 + +typedef enum { + FRAME_TYPE_INO_VISIBLE = 'V', + FRAME_TYPE_INO_REPEAT = 'R', + FRAME_TYPE_INO_SHOWEXISTING = 'S', + FRAME_TYPE_OOO_FILTERED = 'F', + FRAME_TYPE_OOO_UNFILTERED = 'U', +} FRAME_TYPE_CODE; + +typedef enum { + SUBGOP_IN_GOP_GENERIC = 0, + SUBGOP_IN_GOP_LAST, + SUBGOP_IN_GOP_FIRST, + SUBGOP_IN_GOP_CODES +} SUBGOP_IN_GOP_CODE; + +typedef struct { + int8_t disp_frame_idx; + FRAME_TYPE_CODE type_code; + int8_t pyr_level; + int8_t num_references; // value of -1 indicates unspecified references + int8_t references[INTER_REFS_PER_FRAME]; +} SubGOPStepCfg; + +typedef struct { + int8_t num_frames; + SUBGOP_IN_GOP_CODE subgop_in_gop_code; + int8_t num_steps; + SubGOPStepCfg step[MAX_SUBGOP_STEPS]; +} SubGOPCfg; + +/*!\endcond */ +/*! + * \brief Data relating to the current GF/ARF group and the + * individual frames within the group + */ +typedef struct { + /*!\cond */ + unsigned char is_user_specified; + unsigned char index; + FRAME_UPDATE_TYPE update_type[MAX_STATIC_GF_GROUP_LENGTH]; + unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH]; + // The number of frames displayed so far within the GOP at a given coding + // frame. + unsigned char cur_frame_idx[MAX_STATIC_GF_GROUP_LENGTH]; + unsigned char is_filtered[MAX_STATIC_GF_GROUP_LENGTH]; + int layer_depth[MAX_STATIC_GF_GROUP_LENGTH]; + int arf_boost[MAX_STATIC_GF_GROUP_LENGTH]; + int max_layer_depth; + int max_layer_depth_allowed; + // This is currently only populated for AOM_Q mode + unsigned char q_val[MAX_STATIC_GF_GROUP_LENGTH]; + int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH]; + int arf_index; // the index in the gf group of ARF, if no arf, then -1 + int size; + // Current subgop cfg being used, NULL if cfg not specified + const SubGOPCfg *subgop_cfg; + // The cfg step specified for the last frame in the previous gf group. + const SubGOPStepCfg *last_step_prev; + /*!\endcond */ +} GF_GROUP; +/*!\cond */ + +typedef struct { + int8_t num_configs; + SubGOPCfg config[MAX_SUBGOP_CONFIGS]; +} SubGOPSetCfg; + /*!\endcond */ /*! * \brief Main encoder configuration data structure. @@ -817,6 +889,7 @@ // Frame Super-Resolution size scaling. SuperResCfg superres_cfg; +#if !CONFIG_SINGLEPASS /*!\endcond */ /*! * stats_in buffer contains all of the stats packets produced in the first @@ -824,6 +897,13 @@ */ aom_fixed_buf_t twopass_stats_in; /*!\cond */ +#endif // !CONFIG_SINGLEPASS + + // SubGOP config. + const char *subgop_config_str; + + // SubGOP config. + const char *subgop_config_path; // Configuration related to encoder toolsets. ToolCfg tool_cfg; @@ -2206,6 +2286,21 @@ TWO_PASS twopass; /*! + * SubGOP configuration string + */ + char *subgop_config_str; + + /*! + * SubGOP configuration file path + */ + char *subgop_config_path; + + /*! + * Information related to subGOP configuration if specified. + */ + SubGOPSetCfg subgop_config_set; + + /*! * Information related to a gf group. */ GF_GROUP gf_group; @@ -2265,6 +2360,11 @@ */ int b_calculate_psnr; + /*! + * Prints stats for each frame when set to 1. + */ + int print_per_frame_stats; + #if CONFIG_SPEED_STATS /*! * For debugging: number of transform searches we have performed. @@ -2840,18 +2940,29 @@ static INLINE int is_stat_generation_stage(const AV1_COMP *const cpi) { assert(IMPLIES(cpi->compressor_stage == LAP_STAGE, cpi->oxcf.pass == 0 && cpi->lap_enabled)); +#if CONFIG_SINGLEPASS + return (cpi->compressor_stage == LAP_STAGE); +#else return (cpi->oxcf.pass == 1 || (cpi->compressor_stage == LAP_STAGE)); +#endif // CONFIG_SINGLEPASS } + +#if !CONFIG_SINGLEPASS // Check if statistics consumption stage static INLINE int is_stat_consumption_stage_twopass(const AV1_COMP *const cpi) { return (cpi->oxcf.pass == 2); } +#endif // !CONFIG_SINGLEPASS // Check if statistics consumption stage static INLINE int is_stat_consumption_stage(const AV1_COMP *const cpi) { +#if CONFIG_SINGLEPASS + return (cpi->compressor_stage == ENCODE_STAGE && cpi->lap_enabled); +#else return (is_stat_consumption_stage_twopass(cpi) || (cpi->oxcf.pass == 0 && (cpi->compressor_stage == ENCODE_STAGE) && cpi->lap_enabled)); +#endif // CONFIG_SINGLEPASS } /*!\endcond */ @@ -2865,7 +2976,11 @@ */ static INLINE int has_no_stats_stage(const AV1_COMP *const cpi) { assert(IMPLIES(!cpi->lap_enabled, cpi->compressor_stage == ENCODE_STAGE)); +#if CONFIG_SINGLEPASS + return (!cpi->lap_enabled); +#else return (cpi->oxcf.pass == 0 && !cpi->lap_enabled); +#endif // CONFIG_SINGLEPASS } /*!\cond */
diff --git a/av1/encoder/encoder_utils.c b/av1/encoder/encoder_utils.c index 9baea60..35d10a8 100644 --- a/av1/encoder/encoder_utils.c +++ b/av1/encoder/encoder_utils.c
@@ -300,6 +300,7 @@ { 512, 512, 512 } } }; +#if !CONFIG_SINGLEPASS static void configure_static_seg_features(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; @@ -428,6 +429,7 @@ } } } +#endif // !CONFIG_SINGLEPASS void av1_apply_active_map(AV1_COMP *cpi) { struct segmentation *const seg = &cpi->common.seg; @@ -567,6 +569,7 @@ *q = av1_rc_pick_q_and_bounds(cpi, &cpi->rc, cm->width, cm->height, cpi->gf_group.index, bottom_index, top_index); +#if !CONFIG_SINGLEPASS // Configure experimental use of segmentation for enhanced coding of // static regions if indicated. // Only allowed in the second pass of a two pass encode, as it requires @@ -574,6 +577,7 @@ if (is_stat_consumption_stage_twopass(cpi) && cpi->sf.hl_sf.static_segmentation) configure_static_seg_features(cpi); +#endif // !CONFIG_SINGLEPASS } static void reset_film_grain_chroma_params(aom_film_grain_t *pars) {
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h index e37926c..e4908f8 100644 --- a/av1/encoder/firstpass.h +++ b/av1/encoder/firstpass.h
@@ -167,32 +167,6 @@ FRAME_CONTENT_TYPES = 2 } UENUM1BYTE(FRAME_CONTENT_TYPE); -/*!\endcond */ -/*! - * \brief Data relating to the current GF/ARF group and the - * individual frames within the group - */ -typedef struct { - /*!\cond */ - unsigned char index; - FRAME_UPDATE_TYPE update_type[MAX_STATIC_GF_GROUP_LENGTH]; - unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH]; - // The number of frames displayed so far within the GOP at a given coding - // frame. - unsigned char cur_frame_idx[MAX_STATIC_GF_GROUP_LENGTH]; - int layer_depth[MAX_STATIC_GF_GROUP_LENGTH]; - int arf_boost[MAX_STATIC_GF_GROUP_LENGTH]; - int max_layer_depth; - int max_layer_depth_allowed; - // This is currently only populated for AOM_Q mode - unsigned char q_val[MAX_STATIC_GF_GROUP_LENGTH]; - int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH]; - int arf_index; // the index in the gf group of ARF, if no arf, then -1 - int size; - /*!\endcond */ -} GF_GROUP; -/*!\cond */ - typedef struct { FIRSTPASS_STATS *stats_in_start; FIRSTPASS_STATS *stats_in_end;
diff --git a/av1/encoder/gop_structure.c b/av1/encoder/gop_structure.c index bd03de2..47b51ba 100644 --- a/av1/encoder/gop_structure.c +++ b/av1/encoder/gop_structure.c
@@ -24,6 +24,7 @@ #include "av1/encoder/encoder.h" #include "av1/encoder/firstpass.h" #include "av1/encoder/gop_structure.h" +#include "av1/encoder/subgop.h" // Set parameters for frames between 'start' and 'end' (excluding both). static void set_multi_layer_params(const TWO_PASS *twopass, @@ -85,6 +86,104 @@ } } +static int find_backward_alt_ref(const SubGOPCfg *subgop_cfg, int cur_idx) { + int cur_disp_idx = subgop_cfg->step[cur_idx].disp_frame_idx; + int cur_pyr_level = subgop_cfg->step[cur_idx].pyr_level; + int bwd_alt_ref_disp_idx = 0; + + for (int i = 0; i < cur_idx; ++i) { + int disp_idx = subgop_cfg->step[i].disp_frame_idx; + int pyr_level = subgop_cfg->step[i].pyr_level; + if (pyr_level < cur_pyr_level && disp_idx < cur_disp_idx) { + if (disp_idx > bwd_alt_ref_disp_idx) bwd_alt_ref_disp_idx = disp_idx; + } + } + + return bwd_alt_ref_disp_idx; +} + +static int find_forward_alt_ref(const SubGOPCfg *subgop_cfg, int cur_idx) { + int cur_disp_idx = subgop_cfg->step[cur_idx].disp_frame_idx; + int cur_pyr_level = subgop_cfg->step[cur_idx].pyr_level; + int fwd_alt_ref_disp_idx = subgop_cfg->num_frames; + + for (int i = 0; i < cur_idx; ++i) { + int disp_idx = subgop_cfg->step[i].disp_frame_idx; + int pyr_level = subgop_cfg->step[i].pyr_level; + if (pyr_level < cur_pyr_level && disp_idx > cur_disp_idx) { + if (disp_idx < fwd_alt_ref_disp_idx) fwd_alt_ref_disp_idx = disp_idx; + } + } + + return fwd_alt_ref_disp_idx; +} + +static void set_multi_layer_params_from_subgop_cfg( + const TWO_PASS *twopass, GF_GROUP *const gf_group, + const SubGOPCfg *subgop_cfg, RATE_CONTROL *rc, FRAME_INFO *frame_info, + int *cur_frame_idx, int *frame_index) { + int use_altref = 0; + int last_shown_frame = 0; + + for (int idx = 0; idx < subgop_cfg->num_steps; ++idx) { + const SubGOPStepCfg *frame = &subgop_cfg->step[idx]; + FRAME_TYPE_CODE type = frame->type_code; + int pyr_level = frame->pyr_level; + int disp_idx = frame->disp_frame_idx; + + if (type == FRAME_TYPE_OOO_FILTERED || + type == FRAME_TYPE_OOO_UNFILTERED) { // ARF + use_altref = 1; + gf_group->update_type[*frame_index] = + pyr_level == 1 ? ARF_UPDATE : INTNL_ARF_UPDATE; + if (pyr_level == 1) { + gf_group->arf_index = *frame_index; + gf_group->arf_boost[*frame_index] = rc->gfu_boost; + } else { + int fwd_arf_disp_idx = find_forward_alt_ref(subgop_cfg, idx); + int bwd_arf_disp_idx = find_backward_alt_ref(subgop_cfg, idx); + gf_group->arf_boost[*frame_index] = av1_calc_arf_boost( + twopass, rc, frame_info, disp_idx, fwd_arf_disp_idx - disp_idx, + disp_idx - bwd_arf_disp_idx, NULL, NULL); + } + gf_group->arf_src_offset[*frame_index] = disp_idx - last_shown_frame - 1; + } else if (type == FRAME_TYPE_INO_VISIBLE) { // Leaf + gf_group->update_type[*frame_index] = LF_UPDATE; + + int fwd_arf_disp_idx = find_forward_alt_ref(subgop_cfg, idx); + gf_group->arf_boost[*frame_index] = + av1_calc_arf_boost(twopass, rc, frame_info, disp_idx, + fwd_arf_disp_idx - disp_idx, 0, NULL, NULL); + gf_group->arf_src_offset[*frame_index] = 0; + last_shown_frame = disp_idx; + + (*cur_frame_idx)++; + } else if (type == FRAME_TYPE_INO_REPEAT || + type == FRAME_TYPE_INO_SHOWEXISTING) { // Overlay + gf_group->update_type[*frame_index] = + pyr_level == 1 ? OVERLAY_UPDATE : INTNL_OVERLAY_UPDATE; + gf_group->arf_boost[*frame_index] = 0; + gf_group->arf_src_offset[*frame_index] = 0; + last_shown_frame = disp_idx; + (*cur_frame_idx)++; + } + gf_group->is_filtered[*frame_index] = (type == FRAME_TYPE_OOO_FILTERED); + gf_group->cur_frame_idx[*frame_index] = *cur_frame_idx; + gf_group->layer_depth[*frame_index] = pyr_level; + gf_group->max_layer_depth = AOMMAX(gf_group->max_layer_depth, pyr_level); + + if (idx == (subgop_cfg->num_steps - 1)) { + if (!use_altref) gf_group->update_type[*frame_index] = GF_UPDATE; + } else { + (*frame_index)++; + } + } + for (int idx = 1; idx <= *frame_index; idx++) { + if (gf_group->layer_depth[idx] == gf_group->max_layer_depth) + gf_group->layer_depth[idx] = MAX_ARF_LAYERS; + } +} + static int construct_multi_layer_gf_structure( AV1_COMP *cpi, TWO_PASS *twopass, GF_GROUP *const gf_group, RATE_CONTROL *rc, FRAME_INFO *const frame_info, int gf_interval, @@ -125,29 +224,59 @@ ++cur_frame_index; } - // ALTREF. - const int use_altref = gf_group->max_layer_depth_allowed > 0; - if (use_altref) { - gf_group->update_type[frame_index] = ARF_UPDATE; - gf_group->arf_src_offset[frame_index] = gf_interval - 1; - gf_group->cur_frame_idx[frame_index] = cur_frame_index; - gf_group->layer_depth[frame_index] = 1; - gf_group->arf_boost[frame_index] = cpi->rc.gfu_boost; - gf_group->max_layer_depth = 1; - gf_group->arf_index = frame_index; - ++frame_index; + // Rest of the frames. + SubGOPSetCfg *subgop_cfg_set = &cpi->subgop_config_set; + const SubGOPCfg *subgop_cfg0; + if (first_frame_update_type == KF_UPDATE) { + const SubGOPCfg *subgop_cfg_first = + av1_find_subgop_config(subgop_cfg_set, gf_interval, 0, 1); + if (subgop_cfg_first == NULL) + subgop_cfg0 = av1_find_subgop_config(subgop_cfg_set, gf_interval, 0, 0); + else + subgop_cfg0 = subgop_cfg_first; } else { - gf_group->arf_index = -1; + subgop_cfg0 = av1_find_subgop_config(subgop_cfg_set, gf_interval, 0, 0); + } + gf_group->subgop_cfg = NULL; + if (subgop_cfg0) { + const SubGOPCfg *subgop_cfg = subgop_cfg0; + // Check if it is the last GOP + if ((rc->frames_to_key - 1) == gf_interval) { + const SubGOPCfg *subgop_cfg1 = + av1_find_subgop_config(subgop_cfg_set, gf_interval, 1, 0); + if (subgop_cfg1) subgop_cfg = subgop_cfg1; + } + + gf_group->subgop_cfg = subgop_cfg; + gf_group->is_user_specified = 1; + set_multi_layer_params_from_subgop_cfg(twopass, gf_group, subgop_cfg, rc, + frame_info, &cur_frame_index, + &frame_index); + } else { + // ALTREF. + const int use_altref = gf_group->max_layer_depth_allowed > 0; + + if (use_altref) { + gf_group->update_type[frame_index] = ARF_UPDATE; + gf_group->arf_src_offset[frame_index] = gf_interval - 1; + gf_group->cur_frame_idx[frame_index] = cur_frame_index; + gf_group->layer_depth[frame_index] = 1; + gf_group->arf_boost[frame_index] = cpi->rc.gfu_boost; + gf_group->max_layer_depth = 1; + gf_group->arf_index = frame_index; + ++frame_index; + } else { + gf_group->arf_index = -1; + } + set_multi_layer_params(twopass, gf_group, rc, frame_info, 0, gf_interval, + &cur_frame_index, &frame_index, use_altref + 1); + // The end frame will be Overlay frame for an ARF GOP; otherwise set it to + // be GF, for consistency, which will be updated in the next GOP. + gf_group->update_type[frame_index] = + use_altref ? OVERLAY_UPDATE : GF_UPDATE; + gf_group->arf_src_offset[frame_index] = 0; } - // Rest of the frames. - set_multi_layer_params(twopass, gf_group, rc, frame_info, 0, gf_interval, - &cur_frame_index, &frame_index, use_altref + 1); - - // The end frame will be Overlay frame for an ARF GOP; otherwise set it to - // be GF, for consistency, which will be updated in the next GOP. - gf_group->update_type[frame_index] = use_altref ? OVERLAY_UPDATE : GF_UPDATE; - gf_group->arf_src_offset[frame_index] = 0; return frame_index; } @@ -188,6 +317,7 @@ const FRAME_UPDATE_TYPE first_frame_update_type = key_frame ? KF_UPDATE : rc->source_alt_ref_active ? OVERLAY_UPDATE : GF_UPDATE; + gf_group->is_user_specified = 0; gf_group->size = construct_multi_layer_gf_structure( cpi, twopass, gf_group, rc, frame_info, rc->baseline_gf_interval, first_frame_update_type);
diff --git a/av1/encoder/partition_strategy.c b/av1/encoder/partition_strategy.c index 8cc6b76..f2f8952 100644 --- a/av1/encoder/partition_strategy.c +++ b/av1/encoder/partition_strategy.c
@@ -391,12 +391,22 @@ const int w_mi = mi_size_wide[bsize]; const int h_mi = mi_size_high[bsize]; assert(mi_size_wide[bsize] == mi_size_high[bsize]); - assert(cpi->ref_frame_flags & av1_ref_frame_flag_list[LAST_FRAME] || - cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME]); - // Setting up motion search - const int ref_list[] = { cpi->rc.is_src_frame_alt_ref ? ALTREF_FRAME - : LAST_FRAME }; + int ref_list[1]; + ref_list[0] = LAST_FRAME; + if (!(cpi->ref_frame_flags & av1_ref_frame_flag_list[LAST_FRAME]) && + !(cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME])) { + for (int i = LAST_FRAME; i <= ALTREF_FRAME; i++) { + if (cpi->ref_frame_flags & av1_ref_frame_flag_list[i]) { + ref_list[0] = i; + break; + } + } + } else { + // Setting up motion search + ref_list[0] = cpi->rc.is_src_frame_alt_ref ? ALTREF_FRAME : LAST_FRAME; + } + const int num_refs = 1; const int use_subpixel = 1;
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c index c118a44..11fb729 100644 --- a/av1/encoder/pass2_strategy.c +++ b/av1/encoder/pass2_strategy.c
@@ -60,14 +60,14 @@ // Calculate a modified Error used in distributing bits between easier and // harder frames. #define ACT_AREA_CORRECTION 0.5 +#if !CONFIG_SINGLEPASS static double calculate_modified_err(const FRAME_INFO *frame_info, const TWO_PASS *twopass, const AV1EncoderConfig *oxcf, const FIRSTPASS_STATS *this_frame) { const FIRSTPASS_STATS *const stats = twopass->stats_buf_ctx->total_stats; - if (stats == NULL) { - return 0; - } + if (stats == NULL) return 0; + assert(stats->count); const double av_weight = stats->weight / stats->count; const double av_err = (stats->coded_error * av_weight) / stats->count; double modified_error = @@ -86,6 +86,7 @@ return fclamp(modified_error, twopass->modified_error_min, twopass->modified_error_max); } +#endif // !CONFIG_SINGLEPASS // Resets the first pass file to the given position using a relative seek from // the current position. @@ -274,7 +275,7 @@ rc->worst_quality); // Restriction on active max q for constrained quality mode. - if (rc_cfg->mode == AOM_CQ) q = AOMMAX(q, rc_cfg->cq_level); + if (rc_cfg->mode == AOM_CQ) q = AOMMAX(q, rc_cfg->qp); return q; } } @@ -1482,8 +1483,12 @@ static INLINE void set_baseline_gf_interval(AV1_COMP *cpi, int arf_position, int active_max_gf_interval, - int use_alt_ref, - int is_final_pass) { + int use_alt_ref +#if !CONFIG_SINGLEPASS + , + int is_final_pass +#endif // !CONFIG_SINGLEPASS +) { RATE_CONTROL *const rc = &cpi->rc; TWO_PASS *const twopass = &cpi->twopass; // Set the interval until the next gf. @@ -1504,12 +1509,18 @@ // if possible, merge the last two gf groups if (rc->frames_to_key <= active_max_gf_interval) { rc->baseline_gf_interval = rc->frames_to_key; - if (is_final_pass) rc->intervals_till_gf_calculate_due = 0; +#if !CONFIG_SINGLEPASS + if (is_final_pass) +#endif // !CONFIG_SINGLEPASS + rc->intervals_till_gf_calculate_due = 0; // if merging the last two gf groups creates a group that is too long, // split them and force the last gf group to be the MIN_FWD_KF_INTERVAL } else { rc->baseline_gf_interval = rc->frames_to_key - MIN_FWD_KF_INTERVAL; - if (is_final_pass) rc->intervals_till_gf_calculate_due = 0; +#if !CONFIG_SINGLEPASS + if (is_final_pass) +#endif // !CONFIG_SINGLEPASS + rc->intervals_till_gf_calculate_due = 0; } } else { rc->baseline_gf_interval = arf_position - rc->source_alt_ref_pending; @@ -1565,7 +1576,12 @@ */ static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, const EncodeFrameParams *const frame_params, - int max_gop_length, int is_final_pass) { + int max_gop_length +#if !CONFIG_SINGLEPASS + , + int is_final_pass +#endif // !CONFIG_SINGLEPASS +) { AV1_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; const AV1EncoderConfig *const oxcf = &cpi->oxcf; @@ -1589,7 +1605,12 @@ // Reset the GF group data structures unless this is a key // frame in which case it will already have been done. if (!is_intra_only) { + const SubGOPCfg *subgop_cfg = cpi->gf_group.subgop_cfg; + const SubGOPStepCfg *last_step_prev = + subgop_cfg != NULL ? &subgop_cfg->step[subgop_cfg->num_steps - 1] + : NULL; av1_zero(cpi->gf_group); + gf_group->last_step_prev = last_step_prev; } aom_clear_system_state(); @@ -1613,7 +1634,11 @@ // Load stats for the current frame. double mod_frame_err = +#if CONFIG_SINGLEPASS + 0.0; +#else calculate_modified_err(frame_info, twopass, oxcf, this_frame); +#endif // CONFIG_SINGLEPASS // Note the error of the frame at the start of the group. This will be // the GF frame error if we code a normal gf. @@ -1644,7 +1669,11 @@ ++i; // Accumulate error score of frames in this gf group. mod_frame_err = +#if CONFIG_SINGLEPASS + 0.0; +#else calculate_modified_err(frame_info, twopass, oxcf, this_frame); +#endif // CONFIG_SINGLEPASS // accumulate stats for this frame accumulate_this_frame_stats(this_frame, mod_frame_err, &gf_stats); @@ -1666,10 +1695,15 @@ last_frame_stats.frame_sr_coded_error = next_frame.sr_coded_error; last_frame_stats.frame_tr_coded_error = next_frame.tr_coded_error; +#if CONFIG_SINGLEPASS + rc->intervals_till_gf_calculate_due--; + rc->cur_gf_index++; +#else if (is_final_pass) { rc->intervals_till_gf_calculate_due--; rc->cur_gf_index++; } +#endif // CONFIG_SINGLEPASS // Was the group length constrained by the requirement for a new KF? rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0; @@ -1703,7 +1737,7 @@ (i >= MIN_GF_INTERVAL); // TODO(urvang): Improve and use model for VBR, CQ etc as well. - if (use_alt_ref && rc_cfg->mode == AOM_Q && rc_cfg->cq_level <= 200) { + if (use_alt_ref && rc_cfg->mode == AOM_Q && rc_cfg->qp <= 200) { aom_clear_system_state(); float features[21]; get_features_from_gf_stats( @@ -1726,7 +1760,7 @@ // The length reduction strategy is tweaked for certain cases, and doesn't // work well for certain other cases. const int allow_gf_length_reduction = - ((rc_cfg->mode == AOM_Q && rc_cfg->cq_level <= 128) || + ((rc_cfg->mode == AOM_Q && rc_cfg->qp <= 128) || !cpi->internal_altref_allowed) && !is_lossless_requested(rc_cfg); @@ -1752,7 +1786,10 @@ if (i - roll_back >= active_min_gf_interval + 1) { alt_offset = -roll_back; i -= roll_back; - if (is_final_pass) rc->intervals_till_gf_calculate_due = 0; +#if !CONFIG_SINGLEPASS + if (is_final_pass) +#endif // !CONFIG_SINGLEPASS + rc->intervals_till_gf_calculate_due = 0; } } } @@ -1761,8 +1798,12 @@ if (use_alt_ref) { rc->source_alt_ref_pending = 1; gf_group->max_layer_depth_allowed = gf_cfg->gf_max_pyr_height; +#if CONFIG_SINGLEPASS + set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref); +#else set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref, is_final_pass); +#endif // CONFIG_SINGLEPASS const int forward_frames = (rc->frames_to_key - i >= i - 1) ? i - 1 @@ -1777,8 +1818,12 @@ reset_fpf_position(twopass, start_pos); rc->source_alt_ref_pending = 0; gf_group->max_layer_depth_allowed = 0; +#if CONFIG_SINGLEPASS + set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref); +#else set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref, is_final_pass); +#endif // CONFIG_SINGLEPASS rc->gfu_boost = AOMMIN( MAX_GF_BOOST, @@ -1793,10 +1838,17 @@ // the next gf group. // TODO(bohanli): should incorporate the usage of alt_ref into // calculate_gf_length +#if CONFIG_SINGLEPASS + if (rc->source_alt_ref_pending == 0 && + rc->intervals_till_gf_calculate_due > 0) { + rc->gf_intervals[rc->cur_gf_index]--; + } +#else if (is_final_pass && rc->source_alt_ref_pending == 0 && rc->intervals_till_gf_calculate_due > 0) { rc->gf_intervals[rc->cur_gf_index]--; } +#endif // CONFIG_SINGLEPASS #define LAST_ALR_BOOST_FACTOR 0.2f rc->arf_boost_factor = 1.0; @@ -1865,7 +1917,9 @@ #endif // Adjust KF group bits and error remaining. +#if !CONFIG_SINGLEPASS if (is_final_pass) +#endif // !CONFIG_SINGLEPASS twopass->kf_group_error_left -= (int64_t)gf_stats.gf_group_err; // Set up the structure of this Group-Of-Pictures (same as GF_GROUP) @@ -2112,7 +2166,7 @@ const AV1EncoderConfig *const oxcf = &cpi->oxcf; const KeyFrameCfg *const kf_cfg = &oxcf->kf_cfg; double recent_loop_decay[FRAMES_TO_CHECK_DECAY]; - FIRSTPASS_STATS last_frame; + FIRSTPASS_STATS last_frame = { 0 }; double decay_accumulator = 1.0; int i = 0, j; int frames_to_key = 1; @@ -2143,10 +2197,12 @@ // Accumulate total number of stats available till next key frame num_stats_used_for_kf_boost++; +#if !CONFIG_SINGLEPASS // Accumulate kf group error. if (kf_group_err != NULL) *kf_group_err += calculate_modified_err(frame_info, twopass, oxcf, this_frame); +#endif // !CONFIG_SINGLEPASS // Load the next frame's stats. last_frame = *this_frame; @@ -2381,7 +2437,9 @@ RATE_CONTROL *const rc = &cpi->rc; TWO_PASS *const twopass = &cpi->twopass; GF_GROUP *const gf_group = &cpi->gf_group; +#if !CONFIG_SINGLEPASS FRAME_INFO *const frame_info = &cpi->frame_info; +#endif // !CONFIG_SINGLEPASS AV1_COMMON *const cm = &cpi->common; CurrentFrame *const current_frame = &cm->current_frame; const AV1EncoderConfig *const oxcf = &cpi->oxcf; @@ -2441,7 +2499,12 @@ twopass->kf_group_error_left = 0; // Group modified error score. kf_raw_err = this_frame->intra_error; - kf_mod_err = calculate_modified_err(frame_info, twopass, oxcf, this_frame); + kf_mod_err = +#if CONFIG_SINGLEPASS + 0.0; +#else + calculate_modified_err(frame_info, twopass, oxcf, this_frame); +#endif // CONFIG_SINGLEPASS frames_to_key = define_kf_interval(cpi, this_frame, &kf_group_err, kf_cfg->key_freq_max); @@ -2469,15 +2532,23 @@ // Rescan to get the correct error data for the forced kf group. for (i = 0; i < rc->frames_to_key; ++i) { +#if !CONFIG_SINGLEPASS kf_group_err += calculate_modified_err(frame_info, twopass, oxcf, &tmp_frame); +#endif // !CONFIG_SINGLEPASS if (EOF == input_stats(twopass, &tmp_frame)) break; } rc->next_key_frame_forced = 1; + +#if CONFIG_SINGLEPASS + } else if (rc->frames_to_key >= kf_cfg->key_freq_max) { + rc->next_key_frame_forced = 1; +#else } else if ((twopass->stats_in == twopass->stats_buf_ctx->stats_in_end && is_stat_consumption_stage_twopass(cpi)) || rc->frames_to_key >= kf_cfg->key_freq_max) { rc->next_key_frame_forced = 1; +#endif // CONFIG_SINGLEPASS } else { rc->next_key_frame_forced = 0; } @@ -2487,8 +2558,10 @@ // Special case for the last key frame of the file. if (twopass->stats_in >= twopass->stats_buf_ctx->stats_in_end) { // Accumulate kf group error. +#if !CONFIG_SINGLEPASS kf_group_err += calculate_modified_err(frame_info, twopass, oxcf, this_frame); +#endif // !CONFIG_SINGLEPASS } // Calculate the number of bits that should be assigned to the kf group. @@ -2740,7 +2813,9 @@ void av1_get_second_pass_params(AV1_COMP *cpi, EncodeFrameParams *const frame_params, +#if !CONFIG_SINGLEPASS const EncodeFrameInput *const frame_input, +#endif // !CONFIG_SINGLEPASS unsigned int frame_flags) { RATE_CONTROL *const rc = &cpi->rc; TWO_PASS *const twopass = &cpi->twopass; @@ -2777,8 +2852,7 @@ aom_clear_system_state(); - if (oxcf->rc_cfg.mode == AOM_Q) - rc->active_worst_quality = oxcf->rc_cfg.cq_level; + if (oxcf->rc_cfg.mode == AOM_Q) rc->active_worst_quality = oxcf->rc_cfg.qp; FIRSTPASS_STATS this_frame; av1_zero(this_frame); // call above fn @@ -2790,7 +2864,7 @@ process_first_pass_stats(cpi, &this_frame); } } else { - rc->active_worst_quality = oxcf->rc_cfg.cq_level; + rc->active_worst_quality = oxcf->rc_cfg.qp; } // Keyframe and section processing. @@ -2856,16 +2930,25 @@ reset_fpf_position(twopass, start_position); +#if CONFIG_SINGLEPASS + int max_gop_length = MAX_GF_LENGTH_LAP; +#else int max_gop_length = (oxcf->gf_cfg.lag_in_frames >= 32 && is_stat_consumption_stage_twopass(cpi)) ? AOMMIN(MAX_GF_INTERVAL, oxcf->gf_cfg.lag_in_frames - oxcf->algo_cfg.arnr_max_frames / 2) : MAX_GF_LENGTH_LAP; +#endif // CONFIG_SINGLEPASS if (rc->intervals_till_gf_calculate_due == 0) { calculate_gf_length(cpi, max_gop_length, MAX_NUM_GF_INTERVALS); } +#if CONFIG_SINGLEPASS + // Note max_gop_length = MAX_GF_LENGTH_LAP (16) in 1-pass case + assert(max_gop_length == MAX_GF_LENGTH_LAP); + define_gf_group(cpi, &this_frame, frame_params, max_gop_length); +#else if (max_gop_length > 16 && oxcf->algo_cfg.enable_tpl_model && !cpi->sf.tpl_sf.disable_gop_length_decision) { if (rc->gf_intervals[rc->cur_gf_index] - 1 > 16) { @@ -2886,6 +2969,7 @@ } } define_gf_group(cpi, &this_frame, frame_params, max_gop_length, 1); +#endif // CONFIG_SINGLEPASS rc->frames_till_gf_update_due = rc->baseline_gf_interval; assert(gf_group->index == 0); @@ -2914,6 +2998,7 @@ setup_target_rate(cpi); } +#if !CONFIG_SINGLEPASS void av1_init_second_pass(AV1_COMP *cpi) { const AV1EncoderConfig *const oxcf = &cpi->oxcf; TWO_PASS *const twopass = &cpi->twopass; @@ -2977,6 +3062,7 @@ twopass->rolling_arf_group_target_bits = 1; twopass->rolling_arf_group_actual_bits = 1; } +#endif // !CONFIG_SINGLEPASS void av1_init_single_pass_lap(AV1_COMP *cpi) { TWO_PASS *const twopass = &cpi->twopass;
diff --git a/av1/encoder/pass2_strategy.h b/av1/encoder/pass2_strategy.h index a984320..c079c63 100644 --- a/av1/encoder/pass2_strategy.h +++ b/av1/encoder/pass2_strategy.h
@@ -64,7 +64,9 @@ } GF_FRAME_STATS; /*!cond */ +#if !CONFIG_SINGLEPASS void av1_init_second_pass(struct AV1_COMP *cpi); +#endif // !CONFIG_SINGLEPASS void av1_init_single_pass_lap(AV1_COMP *cpi); @@ -91,7 +93,9 @@ */ void av1_get_second_pass_params(struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params, +#if !CONFIG_SINGLEPASS const EncodeFrameInput *const frame_input, +#endif // !CONFIG_SINGLEPASS unsigned int frame_flags); /*!\brief Adjustments to two pass and rate control after each frame.
diff --git a/av1/encoder/picklpf.c b/av1/encoder/picklpf.c index 2fa848e..7593d3e 100644 --- a/av1/encoder/picklpf.c +++ b/av1/encoder/picklpf.c
@@ -38,12 +38,17 @@ } int av1_get_max_filter_level(const AV1_COMP *cpi) { +#if CONFIG_SINGLEPASS + (void)cpi; + return MAX_LOOP_FILTER; +#else if (is_stat_consumption_stage_twopass(cpi)) { return cpi->twopass.section_intra_rating > 8 ? MAX_LOOP_FILTER * 3 / 4 : MAX_LOOP_FILTER; } else { return MAX_LOOP_FILTER; } +#endif // CONFIG_SINGLEPASS } static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd, @@ -145,9 +150,11 @@ // Bias against raising loop filter in favor of lowering it. int64_t bias = (best_err >> (15 - (filt_mid / 8))) * filter_step; +#if !CONFIG_SINGLEPASS if ((is_stat_consumption_stage_twopass(cpi)) && (cpi->twopass.section_intra_rating < 20)) bias = (bias * cpi->twopass.section_intra_rating) / 20; +#endif // !CONFIG_SINGLEPASS // yx, bias less for large block size if (cm->features.tx_mode != ONLY_4X4) bias >>= 1;
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c index 93f5b1c..561f889 100644 --- a/av1/encoder/ratectrl.c +++ b/av1/encoder/ratectrl.c
@@ -952,13 +952,12 @@ return gf_group->layer_depth[gf_index]; } -static int get_active_cq_level(const RATE_CONTROL *rc, - const AV1EncoderConfig *const oxcf, - int intra_only, aom_superres_mode superres_mode, - int superres_denom) { +static int get_active_qp(const RATE_CONTROL *rc, + const AV1EncoderConfig *const oxcf, int intra_only, + aom_superres_mode superres_mode, int superres_denom) { const RateControlCfg *const rc_cfg = &oxcf->rc_cfg; static const double cq_adjust_threshold = 0.1; - int active_cq_level = rc_cfg->cq_level; + int active_qp = rc_cfg->qp; (void)intra_only; if (rc_cfg->mode == AOM_CQ || rc_cfg->mode == AOM_Q) { // printf("Superres %d %d %d = %d\n", superres_denom, intra_only, @@ -974,17 +973,17 @@ } else { mult = SUPERRES_QADJ_PER_DENOM_ARFFRAME; } - active_cq_level = AOMMAX( - active_cq_level - ((superres_denom - SCALE_NUMERATOR) * mult), 0); + active_qp = + AOMMAX(active_qp - ((superres_denom - SCALE_NUMERATOR) * mult), 0); } } if (rc_cfg->mode == AOM_CQ && rc->total_target_bits > 0) { const double x = (double)rc->total_actual_bits / rc->total_target_bits; if (x < cq_adjust_threshold) { - active_cq_level = (int)(active_cq_level * x / cq_adjust_threshold); + active_qp = (int)(active_qp * x / cq_adjust_threshold); } } - return active_cq_level; + return active_qp; } /*! \brief Pick q index for this frame using fixed q index offsets. @@ -998,8 +997,8 @@ * \param[in] rc Top level rate control structure * \param[in] gf_group Configuration of current golden frame group * \param[in] gf_index Index of this frame in the golden frame group - * \param[in] cq_level Upper bound for q index (this may be same as - * \c oxcf->cq_level, or slightly modified for some + * \param[in] qp Upper bound for q index (this may be same as + * \c oxcf->qp, or slightly modified for some * special cases) * \param[in] bit_depth Bit depth of the codec (same as * \c cm->seq_params.bit_depth) @@ -1008,8 +1007,7 @@ static int get_q_using_fixed_offsets(const AV1EncoderConfig *const oxcf, const RATE_CONTROL *const rc, const GF_GROUP *const gf_group, - int gf_index, int cq_level, - int bit_depth) { + int gf_index, int qp, int bit_depth) { assert(oxcf->q_cfg.use_fixed_qp_offsets); assert(oxcf->rc_cfg.mode == AOM_Q); const FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_index]; @@ -1018,7 +1016,7 @@ if (update_type == KF_UPDATE) { if (rc->frames_to_key <= 1) { // Image / intra-only coding: ignore offsets. - return cq_level; + return qp; } offset_idx = 0; } else if (update_type == ARF_UPDATE || update_type == GF_UPDATE) { @@ -1029,18 +1027,18 @@ } else { // Leaf level / overlay frame. assert(update_type == LF_UPDATE || update_type == OVERLAY_UPDATE || update_type == INTNL_OVERLAY_UPDATE); - return cq_level; // Directly Return worst quality allowed. + return qp; // Directly Return worst quality allowed. } assert(offset_idx >= 0 && offset_idx < FIXED_QP_OFFSET_COUNT); assert(oxcf->q_cfg.fixed_qp_offsets[offset_idx] >= 0); // Get qindex offset, by first converting to 'q' and then back. - const double q_val_orig = av1_convert_qindex_to_q(cq_level, bit_depth); + const double q_val_orig = av1_convert_qindex_to_q(qp, bit_depth); const double q_val_target = AOMMAX(q_val_orig - oxcf->q_cfg.fixed_qp_offsets[offset_idx], 0.0); const int delta_qindex = av1_compute_qdelta(rc, q_val_orig, q_val_target, bit_depth); - return AOMMAX(cq_level + delta_qindex, 0); + return AOMMAX(qp + delta_qindex, 0); } /*!\brief Picks q and q bounds given non-CBR rate control params in \c cpi->rc. @@ -1078,13 +1076,13 @@ assert( IMPLIES(rc_mode == AOM_Q, gf_group->update_type[gf_index] == ARF_UPDATE)); - const int cq_level = - get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode, - cm->superres_scale_denominator); + const int qp = + get_active_qp(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode, + cm->superres_scale_denominator); const int bit_depth = cm->seq_params.bit_depth; if (oxcf->q_cfg.use_fixed_qp_offsets) { - return get_q_using_fixed_offsets(oxcf, rc, gf_group, gf_index, cq_level, + return get_q_using_fixed_offsets(oxcf, rc, gf_group, gf_index, qp, bit_depth); } @@ -1096,7 +1094,7 @@ if (frame_is_intra_only(cm)) { if (rc_mode == AOM_Q) { - const int qindex = cq_level; + const int qindex = qp; const double q_val = av1_convert_qindex_to_q(qindex, bit_depth); const int delta_qindex = av1_compute_qdelta(rc, q_val, q_val * 0.25, bit_depth); @@ -1138,12 +1136,12 @@ : rc->avg_frame_qindex[KEY_FRAME]; // For constrained quality dont allow Q less than the cq level if (rc_mode == AOM_CQ) { - if (q < cq_level) q = cq_level; + if (q < qp) q = qp; active_best_quality = get_gf_active_quality(rc, q, bit_depth); // Constrained quality use slightly lower active best. active_best_quality = active_best_quality * 15 / 16; } else if (rc_mode == AOM_Q) { - const int qindex = cq_level; + const int qindex = qp; const double q_val = av1_convert_qindex_to_q(qindex, bit_depth); const int delta_qindex = (refresh_frame_flags->alt_ref_frame) @@ -1155,7 +1153,7 @@ } } else { if (rc_mode == AOM_Q) { - const int qindex = cq_level; + const int qindex = qp; const double q_val = av1_convert_qindex_to_q(qindex, bit_depth); const double delta_rate[FIXED_GF_INTERVAL] = { 0.50, 1.0, 0.85, 1.0, 0.70, 1.0, 0.85, 1.0 }; @@ -1171,8 +1169,8 @@ : inter_minq[rc->avg_frame_qindex[KEY_FRAME]]; // For the constrained quality mode we don't want // q to fall below the cq level. - if ((rc_mode == AOM_CQ) && (active_best_quality < cq_level)) { - active_best_quality = cq_level; + if ((rc_mode == AOM_CQ) && (active_best_quality < qp)) { + active_best_quality = qp; } } } @@ -1258,11 +1256,11 @@ const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; const AV1EncoderConfig *const oxcf = &cpi->oxcf; - const int cq_level = - get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode, - cm->superres_scale_denominator); + const int qp = + get_active_qp(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode, + cm->superres_scale_denominator); const int bit_depth = cm->seq_params.bit_depth; - const int q = (int)av1_convert_qindex_to_q(cq_level, bit_depth); + const int q = (int)av1_convert_qindex_to_q(qp, bit_depth); (void)width; (void)height; assert(has_no_stats_stage(cpi)); @@ -1277,8 +1275,8 @@ #define STATIC_MOTION_THRESH 95 static void get_intra_q_and_bounds(const AV1_COMP *cpi, int width, int height, - int *active_best, int *active_worst, - int cq_level, int is_fwd_kf) { + int *active_best, int *active_worst, int qp, + int is_fwd_kf) { const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; const AV1EncoderConfig *const oxcf = &cpi->oxcf; @@ -1288,10 +1286,9 @@ if (rc->frames_to_key <= 1 && oxcf->rc_cfg.mode == AOM_Q) { // If the next frame is also a key frame or the current frame is the - // only frame in the sequence in AOM_Q mode, just use the cq_level - // as q. - active_best_quality = cq_level; - active_worst_quality = cq_level; + // only frame in the sequence in AOM_Q mode, just use the qp as q. + active_best_quality = qp; + active_worst_quality = qp; } else if (is_fwd_kf) { // Handle the special case for forward reference key frames. // Increase the boost because this keyframe is used as a forward and @@ -1309,6 +1306,7 @@ int delta_qindex; int qindex; +#if !CONFIG_SINGLEPASS if (is_stat_consumption_stage_twopass(cpi) && cpi->twopass.last_kfgroup_zeromotion_pct >= STATIC_MOTION_THRESH) { qindex = AOMMIN(rc->last_kf_qindex, rc->last_boosted_qindex); @@ -1319,12 +1317,15 @@ active_worst_quality = AOMMIN(qindex + delta_qindex, active_worst_quality); } else { +#endif // !CONFIG_SINGLEPASS qindex = rc->last_boosted_qindex; last_boosted_q = av1_convert_qindex_to_q(qindex, bit_depth); delta_qindex = av1_compute_qdelta(rc, last_boosted_q, last_boosted_q * 0.50, bit_depth); active_best_quality = AOMMAX(qindex + delta_qindex, rc->best_quality); +#if !CONFIG_SINGLEPASS } +#endif // !CONFIG_SINGLEPASS } else { // Not forced keyframe. double q_adj_factor = 1.0; @@ -1337,19 +1338,23 @@ active_best_quality /= 2; } +#if !CONFIG_SINGLEPASS if (is_stat_consumption_stage_twopass(cpi) && cpi->twopass.kf_zeromotion_pct >= STATIC_KF_GROUP_THRESH) { active_best_quality /= 3; } +#endif // !CONFIG_SINGLEPASS // Allow somewhat lower kf minq with small image formats. if ((width * height) <= (352 * 288)) { q_adj_factor -= 0.25; } +#if !CONFIG_SINGLEPASS // Make a further adjustment based on the kf zero motion measure. if (is_stat_consumption_stage_twopass(cpi)) q_adj_factor += 0.05 - (0.001 * (double)cpi->twopass.kf_zeromotion_pct); +#endif // !CONFIG_SINGLEPASS // Convert the adjustment factor to a qindex delta // on active_best_quality. @@ -1487,8 +1492,8 @@ // The returning active_best_quality could further be adjusted in // adjust_active_best_and_worst_quality(). static int get_active_best_quality(const AV1_COMP *const cpi, - const int active_worst_quality, - const int cq_level, const int gf_index) { + const int active_worst_quality, const int qp, + const int gf_index) { const AV1_COMMON *const cm = &cpi->common; const int bit_depth = cm->seq_params.bit_depth; const RATE_CONTROL *const rc = &cpi->rc; @@ -1507,13 +1512,13 @@ const int is_overlay_frame = rc->is_src_frame_alt_ref; if (is_leaf_frame || is_overlay_frame) { - if (rc_mode == AOM_Q) return cq_level; + if (rc_mode == AOM_Q) return qp; active_best_quality = inter_minq[active_worst_quality]; // For the constrained quality mode we don't want // q to fall below the cq level. - if ((rc_mode == AOM_CQ) && (active_best_quality < cq_level)) { - active_best_quality = cq_level; + if ((rc_mode == AOM_CQ) && (active_best_quality < qp)) { + active_best_quality = qp; } return active_best_quality; } @@ -1521,7 +1526,7 @@ // TODO(chengchen): can we remove this condition? if (rc_mode == AOM_Q && !refresh_frame_flags->alt_ref_frame && !is_intrl_arf_boost) { - return cq_level; + return qp; } // Determine active_best_quality for frames that are not leaf or overlay. @@ -1533,7 +1538,7 @@ rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) { q = rc->avg_frame_qindex[INTER_FRAME]; } - if (rc_mode == AOM_CQ && q < cq_level) q = cq_level; + if (rc_mode == AOM_CQ && q < qp) q = qp; active_best_quality = get_gf_active_quality(rc, q, bit_depth); // Constrained quality use slightly lower active best. if (rc_mode == AOM_CQ) active_best_quality = active_best_quality * 15 / 16; @@ -1577,14 +1582,14 @@ assert(IMPLIES(has_no_stats_stage(cpi), cpi->oxcf.rc_cfg.mode == AOM_Q && gf_group->update_type[gf_index] != ARF_UPDATE)); - const int cq_level = - get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode, - cm->superres_scale_denominator); + const int qp = + get_active_qp(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode, + cm->superres_scale_denominator); const int bit_depth = cm->seq_params.bit_depth; if (oxcf->q_cfg.use_fixed_qp_offsets) { - return get_q_using_fixed_offsets(oxcf, rc, gf_group, gf_group->index, - cq_level, bit_depth); + return get_q_using_fixed_offsets(oxcf, rc, gf_group, gf_group->index, qp, + bit_depth); } int active_best_quality = 0; @@ -1598,7 +1603,7 @@ const int is_fwd_kf = cm->current_frame.frame_type == KEY_FRAME && cm->show_frame == 0 && cpi->no_show_fwd_kf; get_intra_q_and_bounds(cpi, width, height, &active_best_quality, - &active_worst_quality, cq_level, is_fwd_kf); + &active_worst_quality, qp, is_fwd_kf); #ifdef STRICT_RC active_best_quality = 0; #endif @@ -1608,8 +1613,8 @@ if ((pyramid_level <= 1) || (pyramid_level > MAX_ARF_LAYERS) || (oxcf->rc_cfg.mode == AOM_Q)) { - active_best_quality = get_active_best_quality(cpi, active_worst_quality, - cq_level, gf_index); + active_best_quality = + get_active_best_quality(cpi, active_worst_quality, qp, gf_index); } else { active_best_quality = rc->active_best_quality[pyramid_level - 1] + 1; active_best_quality = AOMMIN(active_best_quality, active_worst_quality);
diff --git a/av1/encoder/rc_utils.h b/av1/encoder/rc_utils.h index b30ef28..d07f349 100644 --- a/av1/encoder/rc_utils.h +++ b/av1/encoder/rc_utils.h
@@ -118,7 +118,7 @@ } else if (cpi->oxcf.rc_cfg.mode == AOM_CQ) { // Deal with frame undershoot and whether or not we are // below the automatically set cq level. - if (q > oxcf->rc_cfg.cq_level && + if (q > oxcf->rc_cfg.qp && rc->projected_frame_size < ((rc->this_frame_target * 7) >> 3)) { force_recode = 1; }
diff --git a/av1/encoder/subgop.c b/av1/encoder/subgop.c new file mode 100644 index 0000000..1f43311 --- /dev/null +++ b/av1/encoder/subgop.c
@@ -0,0 +1,447 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include "av1/encoder/subgop.h" + +static char *my_strtok_r(char *str, const char *delim, char **saveptr) { + if (str == NULL) return NULL; + if (strlen(str) == 0) return NULL; + char *ptr = str; + char *x = strstr(str, delim); + if (x) { + *x = 0; + *saveptr = x + strlen(delim); + } else { + *saveptr = NULL; + return ptr; + } + return ptr; +} + +static char *read_token_after(char *str, const char *delim, char **saveptr) { + if (str == NULL) return NULL; + if (strlen(str) == 0) return NULL; + char *ptr = str; + char *x = strstr(str, delim); + if (x) { + ptr = x + strlen(delim); + while (*x != 0 && !isspace(*x)) x++; + *x = 0; + *saveptr = x + 1; + return ptr; + } else { + *saveptr = NULL; + return NULL; + } +} + +static bool readline(char *buf, int size, FILE *fp) { + buf[0] = '\0'; + buf[size - 1] = '\0'; + char *tmp; + while (1) { + if (fgets(buf, size, fp) == NULL) { + *buf = '\0'; + return false; + } else { + if ((tmp = strrchr(buf, '\n')) != NULL) *tmp = '\0'; + for (int i = 0; i < (int)strlen(buf); ++i) { + if (!isspace(buf[i])) return true; + } + } + } + return true; +} + +void av1_init_subgop_config_set(SubGOPSetCfg *config_set) { + memset(config_set, 0, sizeof(*config_set)); + config_set->num_configs = 0; + for (int i = 0; i < MAX_SUBGOP_CONFIGS; ++i) { + memset(&config_set->config[i], 0, sizeof(config_set->config[i])); + } +} + +static void check_duplicate_and_add(SubGOPSetCfg *config_set) { + int k; + const int n = config_set->num_configs; + for (k = 0; k < n; ++k) { + if (config_set->config[k].num_frames == config_set->config[n].num_frames && + config_set->config[k].subgop_in_gop_code == + config_set->config[n].subgop_in_gop_code) { + memcpy(&config_set->config[k], &config_set->config[n], + sizeof(config_set->config[k])); + return; + } + } + if (k == n) config_set->num_configs++; +} + +static int process_subgop_step(char *str, SubGOPStepCfg *step) { + char *ptr; + step->num_references = 0; + step->disp_frame_idx = (int8_t)strtol(str, &ptr, 10); + // Check if no numeric disp idx exist or is negative + if (ptr == str || step->disp_frame_idx < 0) return 0; + switch (*ptr) { + case 'V': step->type_code = FRAME_TYPE_INO_VISIBLE; break; + case 'R': step->type_code = FRAME_TYPE_INO_REPEAT; break; + case 'S': step->type_code = FRAME_TYPE_INO_SHOWEXISTING; return 1; + case 'F': step->type_code = FRAME_TYPE_OOO_FILTERED; break; + case 'U': step->type_code = FRAME_TYPE_OOO_UNFILTERED; break; + default: return 0; + } + str = ++ptr; + step->pyr_level = (int8_t)strtol(str, &ptr, 10); + // Check if no numeric disp idx exist + if (ptr == str) return 0; + + // Check for unspecified references + if (*ptr == 0) { + step->num_references = -1; + return 1; + } + // Check for character P preceding the references + if (*ptr != 'P') return 0; + str = ++ptr; + char delim[] = "^"; + char *token; + while ((token = my_strtok_r(str, delim, &str)) != NULL) { + if (step->num_references >= INTER_REFS_PER_FRAME) return 0; + step->references[step->num_references] = (int8_t)strtol(token, NULL, 10); + step->num_references++; + } + return 1; +} + +static int process_subgop_steps(char *str, SubGOPCfg *config) { + char delim[] = "/"; + config->num_steps = 0; + char *token; + while ((token = my_strtok_r(str, delim, &str)) != NULL) { + int res = process_subgop_step(token, &config->step[config->num_steps]); + if (!res) return 0; + // Populate pyr level for show existing frame + if (config->step[config->num_steps].type_code == + FRAME_TYPE_INO_SHOWEXISTING) { + int k; + for (k = 0; k < config->num_steps; ++k) { + if (config->step[k].disp_frame_idx == + config->step[config->num_steps].disp_frame_idx) { + config->step[config->num_steps].pyr_level = config->step[k].pyr_level; + break; + } + } + // showexisting for a frame not coded before is invalid + if (k == config->num_steps) return 0; + } + config->num_steps++; + } + return 1; +} + +static int process_subgop_config(char *str, SubGOPCfg *config) { + char delim[] = ":"; + char *token = my_strtok_r(str, delim, &str); + if (!token) return 0; + config->num_frames = atoi(token); + token = my_strtok_r(str, delim, &str); + if (!token) return 0; + int subgop_in_gop_code = atoi(token); + // check for invalid subgop_in_gop_code + if (subgop_in_gop_code < 0 || subgop_in_gop_code >= SUBGOP_IN_GOP_CODES) + return 0; + config->subgop_in_gop_code = (SUBGOP_IN_GOP_CODE)subgop_in_gop_code; + token = my_strtok_r(str, delim, &str); + if (!token) return 0; + return process_subgop_steps(token, config); +} + +static int is_visible(FRAME_TYPE_CODE code) { + switch (code) { + case FRAME_TYPE_INO_VISIBLE: + case FRAME_TYPE_INO_REPEAT: + case FRAME_TYPE_INO_SHOWEXISTING: return 1; + case FRAME_TYPE_OOO_FILTERED: + case FRAME_TYPE_OOO_UNFILTERED: return 0; + default: assert(0 && "Invalid frame type code"); return 0; + } +} + +static int check_subgop_config(SubGOPCfg *config) { + // check for invalid disp_frame_idx + for (int s = 0; s < config->num_steps; ++s) { + if (config->step[s].disp_frame_idx > config->num_frames) return 0; + } + + // Each disp frame index must be shown exactly once + int visible[MAX_SUBGOP_LENGTH]; + memset(visible, 0, config->num_frames * sizeof(*visible)); + for (int s = 0; s < config->num_steps; ++s) { + if (is_visible(config->step[s].type_code)) + visible[config->step[s].disp_frame_idx - 1]++; + } + for (int k = 0; k < config->num_frames; ++k) { + if (visible[k] != 1) return 0; + } + + // Each disp frame index must have at most one invisible frame + int invisible[MAX_SUBGOP_LENGTH]; + memset(invisible, 0, config->num_frames * sizeof(*invisible)); + for (int s = 0; s < config->num_steps; ++s) { + if (!is_visible(config->step[s].type_code)) + invisible[config->step[s].disp_frame_idx - 1]++; + } + for (int k = 0; k < config->num_frames; ++k) { + if (invisible[k] > 1) return 0; + } + + // Check for a single level 1 frame in the subgop + int level[MAX_SUBGOP_LENGTH]; + memset(level, 0, config->num_frames * sizeof(*level)); + for (int s = 0; s < config->num_steps; ++s) { + if (is_visible(config->step[s].type_code)) + level[config->step[s].disp_frame_idx - 1] = config->step[s].pyr_level; + } + int num_level1 = 0; + for (int k = 0; k < config->num_frames; ++k) { + num_level1 += (level[k] == 1); + } + if (num_level1 != 1) return 0; + return 1; +} + +int av1_process_subgop_config_set(const char *param, SubGOPSetCfg *config_set) { + if (!param) return 1; + if (!strlen(param)) return 1; + const int bufsize = (int)((strlen(param) + 1) * sizeof(*param)); + char *buf = (char *)aom_malloc(bufsize); + memcpy(buf, param, bufsize); + char delim[] = ","; + + char *str = buf; + char *token; + while ((token = my_strtok_r(str, delim, &str)) != NULL) { + int res = process_subgop_config( + token, &config_set->config[config_set->num_configs]); + if (res) { + res = check_subgop_config(&config_set->config[config_set->num_configs]); + if (res) { + check_duplicate_and_add(config_set); + } else { + printf( + "Warning: Subgop config validation failed for config #%d, " + "skipping the rest.\n", + config_set->num_configs); + return 0; + } + } else { + printf( + "Warning: Subgop config parsing failed for config #%d, " + "skipping the rest.\n", + config_set->num_configs); + return 0; + } + } + aom_free(buf); + return 1; +} + +static int process_subgop_config_fromfile(FILE *fp, SubGOPCfg *config) { + char line[256]; + int linesize = 256; + int s; + if (!readline(line, linesize, fp)) return 0; + char *token; + char *str = line; + token = read_token_after(str, "num_frames:", &str); + if (!token) return 0; + if (strlen(token) == 0) return 0; + const int num_frames = atoi(token); + if (num_frames <= 0) return 0; + config->num_frames = num_frames; + + token = read_token_after(str, "subgop_in_gop_code:", &str); + if (!token) return 0; + if (strlen(token) == 0) return 0; + const int subgop_in_gop_code = atoi(token); + // check for invalid subgop_in_gop_code + if (subgop_in_gop_code < 0 || subgop_in_gop_code >= SUBGOP_IN_GOP_CODES) + return 0; + config->subgop_in_gop_code = (SUBGOP_IN_GOP_CODE)subgop_in_gop_code; + + token = read_token_after(str, "num_steps:", &str); + if (!token) return 0; + if (strlen(token) == 0) return 0; + config->num_steps = atoi(token); + for (s = 0; s < config->num_steps; ++s) { + SubGOPStepCfg *step = &config->step[s]; + step->num_references = 0; + if (!readline(line, linesize, fp)) return 0; + str = line; + + token = read_token_after(str, "disp_frame_idx:", &str); + if (!token) return 0; + if (strlen(token) == 0) return 0; + const int disp_frame_idx = atoi(token); + if (disp_frame_idx < 0 || disp_frame_idx > config->num_frames) return 0; + step->disp_frame_idx = disp_frame_idx; + token = read_token_after(str, "type_code:", &str); + if (!token) return 0; + if (strlen(token) != 1) return 0; + switch (*token) { + case 'V': step->type_code = FRAME_TYPE_INO_VISIBLE; break; + case 'R': step->type_code = FRAME_TYPE_INO_REPEAT; break; + case 'S': step->type_code = FRAME_TYPE_INO_SHOWEXISTING; break; + case 'F': step->type_code = FRAME_TYPE_OOO_FILTERED; break; + case 'U': step->type_code = FRAME_TYPE_OOO_UNFILTERED; break; + default: return 0; + } + if (step->type_code == FRAME_TYPE_INO_SHOWEXISTING) { + int k; + for (k = 0; k < s; ++k) { + if (config->step[k].disp_frame_idx == step->disp_frame_idx) { + step->pyr_level = config->step[k].pyr_level; + break; + } + } + // showexisting for a frame not coded before is invalid + if (k == s) return 0; + continue; + } + token = read_token_after(str, "pyr_level:", &str); + if (!token) return 0; + if (strlen(token) == 0) return 0; + const int pyr_level = atoi(token); + if (pyr_level <= 0) return 0; + step->pyr_level = pyr_level; + + token = read_token_after(str, "references:", &str); + if (!token) { // no references specified + step->num_references = -1; + continue; + } + if (strlen(token) == 0) continue; // no references + + char delim[] = "^"; + str = token; + while ((token = my_strtok_r(str, delim, &str)) != NULL) { + if (step->num_references >= INTER_REFS_PER_FRAME) return 0; + step->references[step->num_references] = (int8_t)strtol(token, NULL, 10); + step->num_references++; + } + } + return 1; +} + +int av1_process_subgop_config_set_fromfile(const char *paramfile, + SubGOPSetCfg *config_set) { + if (!paramfile) return 1; + if (!strlen(paramfile)) return 1; + FILE *fp = fopen(paramfile, "r"); + if (!fp) return 0; + char line[256]; + int linesize = 256; + char *tok, *str; + if (readline(line, linesize, fp)) { + tok = read_token_after(line, "[num_configs:", &str); + if (!tok) rewind(fp); + } else { + // Blank file + return 1; + } + while (readline(line, linesize, fp)) { + str = line; + tok = read_token_after(str, "config:", &str); + if (tok) { + int res = process_subgop_config_fromfile( + fp, &config_set->config[config_set->num_configs]); + if (res) { + res = check_subgop_config(&config_set->config[config_set->num_configs]); + if (res) { + check_duplicate_and_add(config_set); + } else { + printf( + "Warning: Subgop config validation failed for config #%d, " + "skipping the rest.\n", + config_set->num_configs); + fclose(fp); + return 0; + } + } else { + printf("Warning: config parsing failed, skipping the rest.\n"); + fclose(fp); + return 0; + } + } else { + printf("Warning: config not found, skipping the rest.\n"); + fclose(fp); + return 0; + } + } + fclose(fp); + return 1; +} + +void av1_print_subgop_config_set(SubGOPSetCfg *config_set) { + if (!config_set->num_configs) return; + printf("SUBGOP CONFIG SET\n"); + printf("=================\n"); + printf("[num_configs:%d]\n", config_set->num_configs); + for (int i = 0; i < config_set->num_configs; ++i) { + printf("config:[%d]\n", i); + SubGOPCfg *config = &config_set->config[i]; + printf(" num_frames:%d", config->num_frames); + printf(" subgop_in_gop_code:%d", config->subgop_in_gop_code); + printf(" num_steps:%d\n", config->num_steps); + for (int j = 0; j < config->num_steps; ++j) { + printf(" [step:%d]", j); + printf(" disp_frame_idx:%d", config->step[j].disp_frame_idx); + printf(" type_code:%c", config->step[j].type_code); + printf(" pyr_level:%d", config->step[j].pyr_level); + if (config->step[j].type_code != FRAME_TYPE_INO_SHOWEXISTING && + config->step[j].num_references >= 0) { + printf(" references:"); + for (int r = 0; r < config->step[j].num_references; ++r) { + if (r) printf("^"); + printf("%d", config->step[j].references[r]); + } + } + printf("\n"); + } + } + printf("\n"); +} + +const SubGOPCfg *av1_find_subgop_config(SubGOPSetCfg *config_set, + int num_frames, int is_last_subgop, + int is_first_subgop) { + SubGOPCfg *cfg = NULL; + SUBGOP_IN_GOP_CODE subgop_in_gop_code; + if (is_last_subgop) + subgop_in_gop_code = SUBGOP_IN_GOP_LAST; + else if (is_first_subgop) + subgop_in_gop_code = SUBGOP_IN_GOP_FIRST; + else + subgop_in_gop_code = SUBGOP_IN_GOP_GENERIC; + for (int i = 0; i < config_set->num_configs; ++i) { + if (config_set->config[i].num_frames == num_frames) { + if (config_set->config[i].subgop_in_gop_code == subgop_in_gop_code) + return &config_set->config[i]; + else if (config_set->config[i].subgop_in_gop_code == + SUBGOP_IN_GOP_GENERIC) + cfg = &config_set->config[i]; + } + } + return cfg; +}
diff --git a/av1/encoder/subgop.h b/av1/encoder/subgop.h new file mode 100644 index 0000000..464af04 --- /dev/null +++ b/av1/encoder/subgop.h
@@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#ifndef AOM_AV1_ENCODER_SUBGOP_H_ + +#include "av1/encoder/encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void av1_init_subgop_config_set(SubGOPSetCfg *config_set); +int av1_process_subgop_config_set(const char *param, SubGOPSetCfg *config_set); +void av1_print_subgop_config_set(SubGOPSetCfg *config_set); +int av1_process_subgop_config_set_fromfile(const char *paramfile, + SubGOPSetCfg *config_set); + +// Finds the ptr to the subgop config with the queried number of +// frames and whether it is the last or first subgop in a gop. +// If the right number of frames is found but the right +// subgop_in_gop_code is not found then the generic config with the +// matching length is returned. If the right number of frames +// is not found, Null is returned. +const SubGOPCfg *av1_find_subgop_config(SubGOPSetCfg *config_set, + int num_frames, int is_last_gop, + int is_first_subgop); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_SUBGOP_H_
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c index c43edf9..087d395 100644 --- a/av1/encoder/svc_layercontext.c +++ b/av1/encoder/svc_layercontext.c
@@ -45,8 +45,8 @@ lrc->ni_frames = 0; lrc->decimation_count = 0; lrc->decimation_factor = 0; - lrc->worst_quality = av1_quantizer_to_qindex(lc->max_q); - lrc->best_quality = av1_quantizer_to_qindex(lc->min_q); + lrc->worst_quality = lc->max_qp; + lrc->best_quality = lc->min_qp; for (int i = 0; i < RATE_FACTOR_LEVELS; ++i) { lrc->rate_correction_factors[i] = 1.0; } @@ -121,8 +121,8 @@ lc->framerate = cpi->framerate / lc->framerate_factor; lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate); lrc->max_frame_bandwidth = rc->max_frame_bandwidth; - lrc->worst_quality = av1_quantizer_to_qindex(lc->max_q); - lrc->best_quality = av1_quantizer_to_qindex(lc->min_q); + lrc->worst_quality = lc->max_qp; + lrc->best_quality = lc->min_qp; } } }
diff --git a/av1/encoder/svc_layercontext.h b/av1/encoder/svc_layercontext.h index 3c7ae67..a34843e 100644 --- a/av1/encoder/svc_layercontext.h +++ b/av1/encoder/svc_layercontext.h
@@ -34,8 +34,8 @@ int64_t spatial_layer_target_bandwidth; double framerate; int avg_frame_size; - int max_q; - int min_q; + int max_qp; + int min_qp; int frames_from_key_frame; /*!\endcond */
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c index 751f4e6..2da95a7 100644 --- a/av1/encoder/temporal_filter.c +++ b/av1/encoder/temporal_filter.c
@@ -1073,7 +1073,8 @@ // Filter one more ARF if the lookahead index is leq 7 (w.r.t. 9-th frame). // This frame is ALWAYS a show existing frame. const int is_second_arf = - (update_type == INTNL_ARF_UPDATE) && (filter_frame_lookahead_idx >= 7); + (update_type == INTNL_ARF_UPDATE) && + (filter_frame_lookahead_idx >= (cpi->gf_group.is_user_specified ? 5 : 7)); // TODO(anyone): Currently, we enforce the filtering strength on internal // ARFs except the second ARF to be zero. We should investigate in which case // it is more beneficial to use non-zero strength filtering.
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c index 6a828a8..d5f1f4e 100644 --- a/av1/encoder/tpl_model.c +++ b/av1/encoder/tpl_model.c
@@ -1007,11 +1007,11 @@ av1_get_ref_frames(cpi, &ref_buffer_stack); int refresh_mask = av1_get_refresh_frame_flags( - cpi, &frame_params, frame_update_type, &ref_buffer_stack); + cpi, &frame_params, frame_update_type, gf_index, &ref_buffer_stack); int refresh_frame_map_index = av1_get_refresh_ref_frame_map(refresh_mask); av1_update_ref_frame_map(cpi, frame_update_type, frame_params.frame_type, - frame_params.show_existing_frame, + gf_index, frame_params.show_existing_frame, refresh_frame_map_index, &ref_buffer_stack); for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i) @@ -1067,11 +1067,15 @@ gf_group->q_val[gf_index] = *pframe_qindex; av1_get_ref_frames(cpi, &ref_buffer_stack); + // TODO(sarahparker) av1_get_refresh_frame_flags() and + // av1_update_ref_frame_map() will execute default behavior even when + // subgop cfg is enabled. This should be addressed if we ever remove the + // frame_update_type. int refresh_mask = av1_get_refresh_frame_flags( - cpi, &frame_params, frame_update_type, &ref_buffer_stack); + cpi, &frame_params, frame_update_type, -1, &ref_buffer_stack); int refresh_frame_map_index = av1_get_refresh_ref_frame_map(refresh_mask); av1_update_ref_frame_map(cpi, frame_update_type, frame_params.frame_type, - frame_params.show_existing_frame, + -1, frame_params.show_existing_frame, refresh_frame_map_index, &ref_buffer_stack); for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i)
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake index 2497ff1..decd8bc 100644 --- a/build/cmake/aom_config_defaults.cmake +++ b/build/cmake/aom_config_defaults.cmake
@@ -82,6 +82,7 @@ set_aom_config_var(CONFIG_RUNTIME_CPU_DETECT 1 "Runtime CPU detection support.") set_aom_config_var(CONFIG_SHARED 0 "Build shared libs.") set_aom_config_var(CONFIG_WEBM_IO 1 "Enables WebM support.") +set_aom_config_var(CONFIG_SINGLEPASS 1 "Only allow single pass encoding.") # Debugging flags. set_aom_config_var(CONFIG_DEBUG 0 "Debug build flag.")
diff --git a/build/cmake/tensorflow_lite.cmake b/build/cmake/tensorflow_lite.cmake new file mode 100644 index 0000000..9fca969 --- /dev/null +++ b/build/cmake/tensorflow_lite.cmake
@@ -0,0 +1,97 @@ +# +# Copyright (c) 2020, Alliance for Open Media. All rights reserved +# +# This source code is subject to the terms of the BSD 2 Clause License and the +# Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License was +# not distributed with this source code in the LICENSE file, you can obtain it +# at www.aomedia.org/license/software. If the Alliance for Open Media Patent +# License 1.0 was not distributed with this source code in the PATENTS file, you +# can obtain it at www.aomedia.org/license/patent. +# +if(AOM_BUILD_CMAKE_TENSORFLOW_LITE_CMAKE_) + return() +endif() # AOM_BUILD_CMAKE_TENSORFLOW_LITE_CMAKE_ +set(AOM_BUILD_CMAKE_TENSORFLOW_LITE_CMAKE_ 1) + +include(FindGit) + +# Checks if the dependencies on Tensorflow Lite are already checked out -- if +# not, uses the git submodule command to fetch them. +function(checkout_submodules_) + # As a quick sanity check, see if at least 1 expected file or directory is + # present in each submodule. If so, assume they are all checked out (if they + # are not, then the base directory will be empty). + if( + (EXISTS "${AOM_ROOT}/third_party/tensorflow/tensorflow") + AND (EXISTS + "${AOM_ROOT}/third_party/tensorflow_dependencies/neon_2_sse/ReadMe.md") + AND (EXISTS "${AOM_ROOT}/third_party/tensorflow_aom/absl/absl") + AND (EXISTS "${AOM_ROOT}/third_party/tensorflow_aom/eigen/Eigen") + AND (EXISTS "${AOM_ROOT}/third_party/tensorflow_aom/farmhash/Makefile.am") + AND (EXISTS "${AOM_ROOT}/third_party/tensorflow_aom/flatbuffers/BUILD") + AND (EXISTS "${AOM_ROOT}/third_party/tensorflow_aom/fp16/CMakeLists.txt") + AND (EXISTS "${AOM_ROOT}/third_party/tensorflow_aom/gemmlowp/BUILD") + AND (EXISTS "${AOM_ROOT}/third_party/tensorflow_aom/ruy/BUILD")) + return() + endif() + if(NOT GIT_FOUND) + message( + FATAL_ERROR + "Tensorflow-Lite/dependencies not present; " "git could not be found; " + "please check out submodules with 'git submodule update --init'") + endif() + # Note that "git submodule update --init" must be run from inside the git + # repository; the --git-dir flag does not work. + message("Checking out Tensorflow-Lite submodule") + execute_process(COMMAND "${GIT_EXECUTABLE}" submodule update --init + WORKING_DIRECTORY "${AOM_ROOT}" + OUTPUT_VARIABLE submodule_out + ERROR_VARIABLE submodule_err + RESULT_VARIABLE submodule_result) + if(NOT ${submodule_result} EQUAL 0) + message(FATAL_ERROR "Unable to run 'git submodule update --init': " + "Return code: " ${submodule_result} ", STDOUT: " + ${submodule_out} ", STDERR: " ${submodule_err}) + endif() +endfunction() + +function(add_tensorflow_lite_dependency_) + if(NOT AOM_APP_TARGETS) + message(FATAL_ERROR "AOM_APP_TARGETS variable must not be empty.") + endif() + # Build the library. + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libtensorflow-lite.a" + COMMAND "${AOM_ROOT}/third_party/tensorflow_dependencies/build.pl" + "${AOM_ROOT}" "${CMAKE_CURRENT_BINARY_DIR}/libtensorflow-lite.a" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + add_custom_target(tensorflowlite_a ALL + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libtensorflow-lite.a") + include_directories("${AOM_ROOT}/third_party/tensorflow") + include_directories( + "${AOM_ROOT}/third_party/tensorflow_dependencies/flatbuffers/include/") + # Add tensorflow-lite as a dependency on all AOM applications. + foreach(aom_app ${AOM_APP_TARGETS}) + add_dependencies(${aom_app} tensorflowlite_a) + target_link_libraries( + ${aom_app} + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/libtensorflow-lite.a" + ${AOM_LIB_LINK_TYPE} Threads::Threads + PRIVATE ${CMAKE_DL_LIBS}) + endforeach() +endfunction() + +# If Tensorflow-Lite should be enabled, adds appropriate build rules / targets. +function(setup_tensorflow_lite) + if("${AOM_ROOT}" STREQUAL "") + message(FATAL_ERROR "AOM_ROOT variable must not be empty.") + endif() + # Cross-compile is not currently implemented. + if(CMAKE_TOOLCHAIN_FILE) + message("TOOLCHAIN: ${CMAKE_TOOLCHAIN_FILE}") + message(WARNING "No cross-compile support for TensorFlow Lite; disabling") + set(CONFIG_TENSORFLOW_LITE 0) + endif() + checkout_submodules_() + add_tensorflow_lite_dependency_() +endfunction()
diff --git a/common/args.c b/common/args.c index ec2a863..2766a00 100644 --- a/common/args.c +++ b/common/args.c
@@ -50,11 +50,11 @@ } static const char kSbSizeWarningString[] = - "super_block_size has to be 64 or 128."; + "superblock_size has to be 64 or 128."; static const char kMinpartWarningString[] = "min_partition_size has to be smaller or equal to max_partition_size."; static const char kMaxpartWarningString[] = - "max_partition_size has to be smaller or equal to super_block_size."; + "max_partition_size has to be smaller or equal to superblock_size."; int parse_cfg(const char *file, cfg_options_t *config) { char line[1024 * 10]; @@ -86,46 +86,46 @@ ignore_end_spaces(left); ignore_end_spaces(right); - GET_PARAMS(super_block_size); + GET_PARAMS(superblock_size); GET_PARAMS(max_partition_size); GET_PARAMS(min_partition_size); - GET_PARAMS(disable_ab_partition_type); - GET_PARAMS(disable_rect_partition_type); - GET_PARAMS(disable_1to4_partition_type); - GET_PARAMS(disable_flip_idtx); - GET_PARAMS(disable_cdef); - GET_PARAMS(disable_lr); - GET_PARAMS(disable_obmc); - GET_PARAMS(disable_warp_motion); - GET_PARAMS(disable_global_motion); - GET_PARAMS(disable_dist_wtd_comp); - GET_PARAMS(disable_diff_wtd_comp); - GET_PARAMS(disable_inter_intra_comp); - GET_PARAMS(disable_masked_comp); - GET_PARAMS(disable_one_sided_comp); - GET_PARAMS(disable_palette); - GET_PARAMS(disable_intrabc); - GET_PARAMS(disable_cfl); - GET_PARAMS(disable_smooth_intra); - GET_PARAMS(disable_filter_intra); - GET_PARAMS(disable_dual_filter); - GET_PARAMS(disable_intra_angle_delta); - GET_PARAMS(disable_intra_edge_filter); - GET_PARAMS(disable_tx_64x64); - GET_PARAMS(disable_smooth_inter_intra); - GET_PARAMS(disable_inter_inter_wedge); - GET_PARAMS(disable_inter_intra_wedge); - GET_PARAMS(disable_paeth_intra); + GET_PARAMS(enable_ab_partitions); + GET_PARAMS(enable_rect_partitions); + GET_PARAMS(enable_1to4_partitions); + GET_PARAMS(enable_flip_idtx); + GET_PARAMS(enable_cdef); + GET_PARAMS(enable_restoration); + GET_PARAMS(enable_obmc); + GET_PARAMS(enable_warped_motion); + GET_PARAMS(enable_global_motion); + GET_PARAMS(enable_dist_wtd_comp); + GET_PARAMS(enable_diff_wtd_comp); + GET_PARAMS(enable_interintra_comp); + GET_PARAMS(enable_masked_comp); + GET_PARAMS(enable_onesided_comp); + GET_PARAMS(enable_palette); + GET_PARAMS(enable_intrabc); + GET_PARAMS(enable_cfl_intra); + GET_PARAMS(enable_smooth_intra); + GET_PARAMS(enable_filter_intra); + GET_PARAMS(enable_dual_filter); + GET_PARAMS(enable_angle_delta); + GET_PARAMS(enable_intra_edge_filter); + GET_PARAMS(enable_tx64); + GET_PARAMS(enable_smooth_interintra); + GET_PARAMS(enable_interinter_wedge); + GET_PARAMS(enable_interintra_wedge); + GET_PARAMS(enable_paeth_intra); GET_PARAMS(disable_trellis_quant); - GET_PARAMS(disable_ref_frame_mv); - GET_PARAMS(reduced_reference_set); + GET_PARAMS(enable_ref_frame_mvs); + GET_PARAMS(enable_reduced_reference_set); GET_PARAMS(reduced_tx_type_set); fprintf(stderr, "\nInvalid parameter: %s", left); exit(-1); } - if (config->super_block_size != 128 && config->super_block_size != 64) { + if (config->superblock_size != 128 && config->superblock_size != 64) { fprintf(stderr, "\n%s", kSbSizeWarningString); exit(-1); } @@ -133,7 +133,7 @@ fprintf(stderr, "\n%s", kMinpartWarningString); exit(-1); } - if (config->max_partition_size > config->super_block_size) { + if (config->max_partition_size > config->superblock_size) { fprintf(stderr, "\n%s", kMaxpartWarningString); exit(-1); }
diff --git a/common/stream_iter.c b/common/stream_iter.c new file mode 100644 index 0000000..bf523d8 --- /dev/null +++ b/common/stream_iter.c
@@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> + +#include "common/stream_iter.h" +#include "common/y4minput.h" + +static int copy_reader(StreamIter *iter, aom_image_t *img) { + struct AvxInputContext *input_ctx = iter->input.avx; + FILE *f = input_ctx->file; + y4m_input *y4m = &input_ctx->y4m; + int shortread = 0; + + if (input_ctx->file_type == FILE_TYPE_Y4M) { + if (y4m_input_fetch_frame(y4m, f, img) < 1) return 0; + } else { + shortread = read_yuv_frame(input_ctx, img); + } + return !shortread; +} + +void copy_stream_iter_init(StreamIter *iter, struct AvxInputContext *input) { + iter->input.avx = input; + iter->reader = copy_reader; +} + +static int skip_reader(StreamIter *iter, aom_image_t *raw) { + // While we haven't skipped enough frames, read from the underlying + // stream and throw the result away. If no frame is available, early + // exit. + while (iter->current < iter->n) { + ++iter->current; + int frame_avail = read_stream_iter(iter->input.stream, raw); + if (!frame_avail) { + return frame_avail; + } + } + // If we're past the skip region, copy the remaining output. + return read_stream_iter(iter->input.stream, raw); +} + +void skip_stream_iter_init(StreamIter *iter, StreamIter *input, int num_skip) { + assert(num_skip >= 0); + iter->input.stream = input; + iter->current = 0; + iter->n = num_skip; + iter->reader = skip_reader; +} + +static int step_reader(StreamIter *iter, aom_image_t *raw) { + while (true) { + int frame_avail = read_stream_iter(iter->input.stream, raw); + // If at end of stream, no need to read further. + if (!frame_avail) { + return frame_avail; + } + + bool should_encode = iter->current == 0; + iter->current = (iter->current + 1) % (iter->n); + if (should_encode) { + return frame_avail; + } + } +} + +void step_stream_iter_init(StreamIter *iter, StreamIter *input, int step_size) { + assert(step_size > 0); + iter->input.stream = input; + iter->current = 0; + iter->n = step_size; + iter->reader = step_reader; +} + +static int limit_reader(StreamIter *iter, aom_image_t *raw) { + // limit of 0 is a special case meaning "no limit". + if (iter->n != 0 && iter->current >= iter->n) { + return 0; + } + ++iter->current; + return read_stream_iter(iter->input.stream, raw); +} + +void limit_stream_iter_init(StreamIter *iter, StreamIter *input, int limit) { + assert(limit >= 0); + iter->input.stream = input; + iter->current = 0; + iter->n = limit; + iter->reader = limit_reader; +} + +int read_stream_iter(StreamIter *iter, aom_image_t *raw) { + return iter->reader(iter, raw); +}
diff --git a/common/stream_iter.h b/common/stream_iter.h new file mode 100644 index 0000000..af98a2a --- /dev/null +++ b/common/stream_iter.h
@@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ +#ifndef AOM_COMMON_STREAM_ITER_H_ +#define AOM_COMMON_STREAM_ITER_H_ + +#include "aom/aom_image.h" +#include "common/tools_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct StreamIter; + +// The input to each stream iterator can either be an AvxInputContext (when +// reading from a file or a pipe like STDIN) or another stream iterator. +union StreamInput { + struct AvxInputContext *avx; + struct StreamIter *stream; +}; + +typedef struct StreamIter { + union StreamInput input; + // For simplicity, all streams have two additional numbers associated + // with them, e.g., for counting the number of frames returned and the + // number of frames that should be skipped. Some iterators, like the copy + // iterator, do not use either field. + int current; + int n; + // Pointer to the function that performs the read. Returns whether a frame + // is available. If a frame is returned, it is written into *raw. + int (*reader)(struct StreamIter *iter, aom_image_t *raw); +} StreamIter; + +// Iterator that simply copies the data from the AvxInputContext. +void copy_stream_iter_init(StreamIter *iter, struct AvxInputContext *input); + +// Iterator that skips the first N frames. Takes another stream as input. +void skip_stream_iter_init(StreamIter *iter, StreamIter *input, int num_skip); + +// Iterator that only returns every N-th frame. Takes another stream as input. +void step_stream_iter_init(StreamIter *iter, StreamIter *input, int step_size); + +// Iterator that stops returning frames after the N-th. Takes another stream +// as input. +void limit_stream_iter_init(StreamIter *iter, StreamIter *input, int limit); + +// Invokes the iterator's specialized read function to read data from the +// stream. Returns if a frame was read. If so, writes the data into *raw. +int read_stream_iter(StreamIter *iter, aom_image_t *raw); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_COMMON_STREAM_ITER_H_
diff --git a/common/tf_lite_includes.h b/common/tf_lite_includes.h new file mode 100644 index 0000000..e28adbe --- /dev/null +++ b/common/tf_lite_includes.h
@@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#ifndef AOM_COMMON_TF_LITE_INCLUDES_H_ +#define AOM_COMMON_TF_LITE_INCLUDES_H_ + +// TensorFlow Lite has several unused parameters that are +// exposed as part of the API. In the AOM build process, this +// will cause failures when -Wunused-parameter is set. +// Since TF Lite is external code, instruct the compiler to +// ignore this warning when including it. +// Note that Clang supports this GCC pragma. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + +#include "tensorflow/lite/kernels/builtin_op_kernels.h" +#include "tensorflow/lite/interpreter.h" +#include "tensorflow/lite/model.h" +#include "tensorflow/lite/op_resolver.h" + +#pragma GCC diagnostic pop + +#endif // AOM_COMMON_TF_LITE_INCLUDES_H_
diff --git a/common/warnings.c b/common/warnings.c index 2facee2..efe7ae2 100644 --- a/common/warnings.c +++ b/common/warnings.c
@@ -67,10 +67,10 @@ return c == 'y'; } -static void check_quantizer(int min_q, int max_q, +static void check_quantizer(int min_qp, int max_qp, struct WarningList *warning_list) { - const int lossless = min_q == 0 && max_q == 0; - if (!lossless && (min_q == max_q || abs(max_q - min_q) < 8)) + const int lossless = min_qp == 0 && max_qp == 0; + if (!lossless && (min_qp == max_qp || abs(max_qp - min_qp) < 32)) add_warning(quantizer_warning_string, warning_list); }
diff --git a/doc/dev_guide/av1_encoder.dox b/doc/dev_guide/av1_encoder.dox index 7ddd18d..3f85745 100644 --- a/doc/dev_guide/av1_encoder.dox +++ b/doc/dev_guide/av1_encoder.dox
@@ -131,7 +131,7 @@ - \ref RateControlCfg.target_bandwidth - \ref RateControlCfg.best_allowed_q - \ref RateControlCfg.worst_allowed_q - - \ref RateControlCfg.cq_level + - \ref RateControlCfg.qp - \ref RateControlCfg.under_shoot_pct - \ref RateControlCfg.over_shoot_pct - \ref RateControlCfg.maximum_buffer_size_ms @@ -531,9 +531,9 @@ control configuration data structures. - <b>--target-bitrate</b> (\ref RateControlCfg.target_bandwidth) -- <b>--min-q</b> (\ref RateControlCfg.best_allowed_q) -- <b>--max-q</b> (\ref RateControlCfg.worst_allowed_q) -- <b>--cq-level</b> (\ref RateControlCfg.cq_level) +- <b>--min-qp</b> (\ref RateControlCfg.best_allowed_q) +- <b>--max-qp</b> (\ref RateControlCfg.worst_allowed_q) +- <b>--qp</b> (\ref RateControlCfg.qp) - <b>--undershoot-pct</b> (\ref RateControlCfg.under_shoot_pct) - <b>--overshoot-pct</b> (\ref RateControlCfg.over_shoot_pct)
diff --git a/examples/lightfield_encoder.c b/examples/lightfield_encoder.c index d24aabd..073f97e 100644 --- a/examples/lightfield_encoder.c +++ b/examples/lightfield_encoder.c
@@ -64,6 +64,7 @@ return image_size_bytes; } +#if !CONFIG_SINGLEPASS static int get_frame_stats(aom_codec_ctx_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, unsigned int duration, aom_enc_frame_flags_t flags, @@ -88,6 +89,7 @@ return got_pkts; } +#endif // !CONFIG_SINGLEPASS static int encode_frame(aom_codec_ctx_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, unsigned int duration, @@ -127,6 +129,7 @@ } } +#if !CONFIG_SINGLEPASS static aom_fixed_buf_t pass0(aom_image_t *raw, FILE *infile, aom_codec_iface_t *encoder, const aom_codec_enc_cfg_t *cfg, int lf_width, @@ -229,6 +232,7 @@ return stats; } +#endif // !CONFIG_SINGLEPASS static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name, aom_codec_iface_t *encoder, aom_codec_enc_cfg_t *cfg, @@ -353,7 +357,7 @@ die_codec(&codec, "Failed to configure encoder"); // The fixed q value used in encoding. - if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 36)) + if (aom_codec_control(&codec, AOME_SET_QP, 36)) die_codec(&codec, "Failed to set cq level"); if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 1)) die_codec(&codec, "Failed to set frame parallel decoding"); @@ -435,7 +439,9 @@ aom_image_t raw; aom_image_t raw_shift; aom_codec_err_t res; +#if !CONFIG_SINGLEPASS aom_fixed_buf_t stats; +#endif // !CONFIG_SINGLEPASS int flags = 0; const int fps = 30; @@ -500,6 +506,12 @@ if (!(infile = fopen(infile_arg, "rb"))) die("Failed to open %s for reading", infile_arg); +#if CONFIG_SINGLEPASS + // Pass 1 + cfg.g_pass = AOM_RC_ONE_PASS; + pass1(&raw, infile, outfile_arg, encoder, &cfg, lf_width, lf_height, + lf_blocksize, flags, &raw_shift); +#else // Pass 0 cfg.g_pass = AOM_RC_FIRST_PASS; stats = pass0(&raw, infile, encoder, &cfg, lf_width, lf_height, lf_blocksize, @@ -512,6 +524,7 @@ pass1(&raw, infile, outfile_arg, encoder, &cfg, lf_width, lf_height, lf_blocksize, flags, &raw_shift); free(stats.buf); +#endif // CONFIG_SINGLEPASS if (FORCE_HIGHBITDEPTH_DECODING) aom_img_free(&raw_shift); aom_img_free(&raw);
diff --git a/examples/noise_model.c b/examples/noise_model.c index d07443f..4ad94b4 100644 --- a/examples/noise_model.c +++ b/examples/noise_model.c
@@ -34,7 +34,7 @@ * * # Encode with your favorite settings (including the grain table): * aomenc --limit=100 --cpu-used=4 --input-bit-depth=8 \ - * --i420 -w 854 -h 480 --end-usage=q --cq-level=25 --lag-in-frames=25 \ + * --i420 -w 854 -h 480 --end-usage=q --qp=100 --lag-in-frames=25 \ * --auto-alt-ref=2 --bit-depth=8 --film-grain-table=film_grain.tbl \ * -o denoised_with_grain_params.ivf denoised.854_480.yuv */
diff --git a/examples/scalable_encoder.c b/examples/scalable_encoder.c index 5bfd184..d09cbb7 100644 --- a/examples/scalable_encoder.c +++ b/examples/scalable_encoder.c
@@ -242,7 +242,7 @@ die_codec(&codec, "Failed to set enc cfg for layer 0"); if (aom_codec_control(&codec, AOME_SET_SPATIAL_LAYER_ID, 0)) die_codec(&codec, "Failed to set layer id to 0"); - if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 62)) + if (aom_codec_control(&codec, AOME_SET_QP, 62)) die_codec(&codec, "Failed to set cq level"); encode_frame(&codec, &raw0, frame_count++, flags, outfile); @@ -261,7 +261,7 @@ die_codec(&codec, "Failed to set enc cfg for layer 1"); if (aom_codec_control(&codec, AOME_SET_SPATIAL_LAYER_ID, 1)) die_codec(&codec, "Failed to set layer id to 1"); - if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 10)) + if (aom_codec_control(&codec, AOME_SET_QP, 10)) die_codec(&codec, "Failed to set cq level"); encode_frame(&codec, &raw1, frame_count++, flags, outfile);
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c index 2b883cf..c098464 100644 --- a/examples/svc_encoder_rtc.c +++ b/examples/svc_encoder_rtc.c
@@ -723,8 +723,8 @@ cfg.rc_dropframe_thresh = (unsigned int)strtoul(argv[9], NULL, 0); cfg.rc_end_usage = AOM_CBR; - cfg.rc_min_quantizer = 2; - cfg.rc_max_quantizer = 52; + cfg.rc_min_quantizer = 8; + cfg.rc_max_quantizer = 208; cfg.rc_undershoot_pct = 50; cfg.rc_overshoot_pct = 50; cfg.rc_buf_initial_sz = 600;
diff --git a/examples/tf_lite_model.cc b/examples/tf_lite_model.cc new file mode 100644 index 0000000..8474ed6 --- /dev/null +++ b/examples/tf_lite_model.cc
@@ -0,0 +1,233 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +/*!\file + * \brief This binary demonstrates how to build an executable with TensorFlow + * Lite. A library for aomenc/aomdec is almost identical in structure, + * except that "main" will not be present, and a header file will be added. + */ + +#include <cstdio> +#include <memory> + +#include "common/tf_lite_includes.h" + +namespace { + +/** + * Model data. Steps to create: + * + * 1. Build your model like normal. + * 2. Follow the steps at https://www.tensorflow.org/lite/convert/python_api + * to convert into a TF-lite model. Optionally quantize the model to make + * it smaller (see the Quantization section at + * https://www.tensorflow.org/lite/guide/get_started) + * 3. Run `xxd -i model.tflite > model.cc` to make it a CC file. + * 4. Change the declaration to be const. + * 5. Either include directly or create .h/.cc files that expose the array. + */ +const unsigned char tf_lite_model_data[] = { + 0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x00, 0x00, 0x12, 0x00, 0x1c, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf4, 0x04, 0x00, + 0x00, 0x4c, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xb0, + 0xfb, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, + 0x00, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0xf4, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x5c, + 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0xba, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x00, 0x00, 0x00, 0xb0, 0xfb, 0xff, 0xff, 0xb4, + 0xfb, 0xff, 0xff, 0xb8, 0xfb, 0xff, 0xff, 0xbc, 0xfb, 0xff, 0xff, 0xde, 0xfe, + 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x83, 0xad, 0x05, + 0x3e, 0x0a, 0x72, 0x13, 0x3f, 0x83, 0xfb, 0x88, 0x3f, 0x2a, 0xf1, 0x8b, 0xbe, + 0xfa, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x86, + 0xc7, 0x46, 0x3f, 0x57, 0xb7, 0x35, 0xbf, 0x78, 0x2c, 0xeb, 0x3e, 0x25, 0xab, + 0xae, 0xbe, 0x93, 0xbe, 0x6f, 0x3f, 0x44, 0x91, 0x8d, 0x3e, 0xdc, 0x92, 0xe7, + 0x3e, 0x25, 0x67, 0x83, 0xbf, 0x2a, 0xc0, 0x7a, 0xbf, 0xf8, 0x46, 0x9d, 0x3f, + 0x0b, 0x18, 0x6b, 0xbf, 0x0d, 0xe7, 0xc1, 0x3e, 0xb4, 0xd9, 0x15, 0xbf, 0x8d, + 0x62, 0xa3, 0x3e, 0xb4, 0x5e, 0xab, 0xbb, 0xb8, 0x49, 0x3a, 0x3e, 0x46, 0xff, + 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x5a, 0xdc, 0x3d, + 0x3d, 0xdd, 0x63, 0x17, 0xbe, 0x4a, 0x05, 0x1a, 0xbf, 0x27, 0xde, 0x3d, 0x3e, + 0x74, 0xcd, 0xd7, 0x3e, 0x63, 0xff, 0x0c, 0x3f, 0xf7, 0xcc, 0x0d, 0x3f, 0x10, + 0x30, 0x00, 0xbf, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x76, 0xf6, 0x0a, 0xbf, 0x76, 0xf6, 0x0a, 0x3f, 0x68, 0xfc, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x54, 0x4f, 0x43, 0x4f, 0x20, 0x43, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x00, + 0x00, 0xec, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xa4, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x07, 0x00, + 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x24, 0xfd, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, + 0x00, 0xe4, 0x01, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, + 0xf4, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0xe2, 0xfd, 0xff, 0xff, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd4, 0xfd, 0xff, + 0xff, 0x1e, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x31, 0x2f, 0x4d, 0x61, + 0x74, 0x4d, 0x75, 0x6c, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0xfe, 0xff, 0xff, 0x4c, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x18, 0xfe, 0xff, 0xff, 0x32, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x31, + 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x2f, 0x52, 0x65, 0x61, 0x64, 0x56, + 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x2f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x82, 0xfe, 0xff, 0xff, 0x34, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x74, 0xfe, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, + 0x31, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc6, 0xfe, 0xff, + 0xff, 0x38, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xb8, 0xfe, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x73, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, + 0x73, 0x65, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x5f, 0x62, 0x69, 0x61, + 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0a, 0xff, 0xff, 0xff, 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xfc, 0xfe, 0xff, 0xff, 0x30, 0x00, + 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x2f, + 0x52, 0x65, 0x61, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4f, + 0x70, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x66, 0xff, 0xff, 0xff, 0x34, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x58, 0xff, 0xff, 0xff, 0x1a, + 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x52, + 0x65, 0x6c, 0x75, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, 0x44, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x64, + 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, + 0x00, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x19, 0x0a, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x00, 0x00, 0x00 +}; + +/** + * These lines were generated by building the binary + * tensorflow/lite/tools/generate_op_registrations and running it with + * the TF-Lite model as input. In order to build that binary, follow + * these instructions: + * + * 1.) Check out a clean copy of tensorflow/ in a different directory. Pin to + * commit 18445b0e39b677a21c86b4cf3d2bcb823f27e3e2. Make sure you are + * in the root of the tensorflow/ directory. + * 2.) Apply the following diff to + * tensorflow/lite/tools/gen_op_registration_main.cc: + <pre> +153,155c153,155 +< std::string input_models; +< std::string output_registration; +< std::string tflite_path; +--- +> std::string input_model(argv[1]); +> std::string output_registration(argv[2]); +> std::string tflite_path("tensorflow/lite"); +158,159d157 +< ParseFlagAndInit(&argc, argv, &input_models, &output_registration, +< &tflite_path, &namespace_flag, &for_micro); +163,171c161 +< if (!input_models.empty()) { +< std::vector<std::string> models = absl::StrSplit(input_models, ','); +< for (const std::string& input_model : models) { +< AddOpsFromModel(input_model, &builtin_ops, &custom_ops); +< } +< } +< for (int i = 1; i < argc; i++) { +< AddOpsFromModel(argv[i], &builtin_ops, &custom_ops); +< } +--- +> AddOpsFromModel(input_model, &builtin_ops, &custom_ops); + </pre> + * This diff fixes an issue with the current binary's flag parsing + * library, which is failing silently. + * + * 3. Run "bazel build tensorflow/lite/tools/generate_op_registrations" + * and then run: + <pre> + ./bazel-bin/tensorflow/lite/tools/generate_op_registrations \ + /path/to/model.tflite /path/to/output.cc + </pre> + * For appropriate paths to the input and output files. + */ +void RegisterSpecificOps(tflite::MutableOpResolver *resolver) { + resolver->AddBuiltin(tflite::BuiltinOperator_FULLY_CONNECTED, + tflite::ops::builtin::Register_FULLY_CONNECTED(), 3, 3); + resolver->AddBuiltin(tflite::BuiltinOperator_SOFTMAX, + tflite::ops::builtin::Register_SOFTMAX()); +} + +} // namespace + +int main() { + // Toy model that takes in four floats and returns two classification + // probabilities. + auto model = tflite::GetModel(tf_lite_model_data); + // Build the interpreter. + tflite::MutableOpResolver resolver; + RegisterSpecificOps(&resolver); + tflite::InterpreterBuilder builder(model, resolver); + std::unique_ptr<tflite::Interpreter> interpreter; + builder(&interpreter); + + std::unique_ptr<tflite::ErrorReporter> reporter( + tflite::DefaultErrorReporter()); + + if (interpreter->AllocateTensors() != kTfLiteOk) { + reporter->Report("Failed"); + return EXIT_FAILURE; + } + + // Always uses (0, 1, 2, 3) as inputs. + float *input = interpreter->typed_input_tensor<float>(0); + for (int i = 0; i < 4; ++i) { + input[i] = i; + } + auto status = interpreter->Invoke(); + if (status != kTfLiteOk) { + reporter->Report("Failed"); + return EXIT_FAILURE; + } + float y0 = interpreter->typed_output_tensor<float>(0)[0]; + float y1 = interpreter->typed_output_tensor<float>(0)[1]; + printf("Sample classification probability: %f, %f\n", y0, y1); + return EXIT_SUCCESS; +}
diff --git a/examples/twopass_encoder.c b/examples/twopass_encoder.c index 075eeae..9902938 100644 --- a/examples/twopass_encoder.c +++ b/examples/twopass_encoder.c
@@ -242,7 +242,9 @@ // Pass 1 rewind(infile); cfg.g_pass = AOM_RC_LAST_PASS; +#if !CONFIG_SINGLEPASS cfg.rc_twopass_stats_in = stats; +#endif // !CONFIG_SINGLEPASS pass1(&raw, infile, outfile_arg, encoder, &cfg, limit); free(stats.buf);
diff --git a/libs.doxy_template b/libs.doxy_template index dab0ba0..bf88a1d 100644 --- a/libs.doxy_template +++ b/libs.doxy_template
@@ -2110,10 +2110,12 @@ # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # -# In builds where CONFIG_REALTIME_ONLY is set some functions are #ifdefed out -# which causes reference failures. Hence for doxygen we set it to 0 here. +# In builds where CONFIG_SINGLEPASS and/or CONFIG_REALTIME_ONLY are set some +# functions are #ifdefed out which causes reference failures. Hence for +# doxygen we set those to 0 here. -PREDEFINED = CONFIG_REALTIME_ONLY=0 +PREDEFINED = "CONFIG_SINGLEPASS=0" \ + "CONFIG_REALTIME_ONLY=0" # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The
diff --git a/test/altref_test.cc b/test/altref_test.cc index 742358e..d4d1fca 100644 --- a/test/altref_test.cc +++ b/test/altref_test.cc
@@ -31,12 +31,14 @@ { 0, 60, 12, 20, 25, ::libaom_test::kOnePassGood }, { 60, 60, 16, 28, 30, ::libaom_test::kOnePassGood }, { 0, 100, 16, 32, 35, ::libaom_test::kOnePassGood }, +#if !CONFIG_SINGLEPASS { 0, 10, 4, 8, 10, ::libaom_test::kTwoPassGood }, { 0, 30, 8, 12, 16, ::libaom_test::kTwoPassGood }, { 30, 30, 12, 16, 25, ::libaom_test::kTwoPassGood }, { 0, 60, 16, 24, 25, ::libaom_test::kTwoPassGood }, { 60, 60, 20, 28, 30, ::libaom_test::kTwoPassGood }, { 0, 100, 24, 32, 35, ::libaom_test::kTwoPassGood }, +#endif }; std::ostream &operator<<(std::ostream &os, const AltRefTestParams &test_arg) { @@ -128,15 +130,17 @@ { ::libaom_test::kOnePassGood, 8, 16 }, { ::libaom_test::kOnePassGood, 16, 16 }, +#if !CONFIG_SINGLEPASS // two pass { ::libaom_test::kTwoPassGood, 0, 6 }, { ::libaom_test::kTwoPassGood, 0, 8 }, { ::libaom_test::kTwoPassGood, 5, 10 }, { ::libaom_test::kTwoPassGood, 8, 16 }, { ::libaom_test::kTwoPassGood, 16, 32 }, - // disabled below test case because it causes failure - // TODO(anyone): enable below test case once issue is fixed. - // { ::libaom_test::kTwoPassGood, 20, 32 }, +// disabled below test case because it causes failure +// TODO(anyone): enable below test case once issue is fixed. +// { ::libaom_test::kTwoPassGood, 20, 32 }, +#endif }; // This class is used to test if the gf interval bounds configured by the user
diff --git a/test/aomenc.sh b/test/aomenc.sh index 0c0d1b1..e14b231 100755 --- a/test/aomenc.sh +++ b/test/aomenc.sh
@@ -192,8 +192,8 @@ $(aomenc_encode_test_fast_params) \ --ivf \ --output="${output}" \ - --min-q=0 \ - --max-q=0 || return 1 + --min-qp=0 \ + --max-qp=0 || return 1 if [ ! -e "${output}" ]; then elog "Output file does not exist."
diff --git a/test/aq_segment_test.cc b/test/aq_segment_test.cc index e2715a1..1c0c18b 100644 --- a/test/aq_segment_test.cc +++ b/test/aq_segment_test.cc
@@ -48,8 +48,8 @@ aq_mode_ = aq_mode; deltaq_mode_ = 0; cfg_.kf_max_dist = 12; - cfg_.rc_min_quantizer = 8; - cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 32; + cfg_.rc_max_quantizer = 224; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 6; cfg_.rc_buf_initial_sz = 500;
diff --git a/test/arf_freq_test.cc b/test/arf_freq_test.cc index 0780cd7..bebcafa 100644 --- a/test/arf_freq_test.cc +++ b/test/arf_freq_test.cc
@@ -57,8 +57,11 @@ const TestEncodeParam kEncodeVectors[] = { { ::libaom_test::kOnePassGood, 2 }, { ::libaom_test::kOnePassGood, 5 }, +#if !CONFIG_SINGLEPASS { ::libaom_test::kTwoPassGood, 1 }, { ::libaom_test::kTwoPassGood, 2 }, - { ::libaom_test::kTwoPassGood, 5 }, { ::libaom_test::kRealTime, 5 }, + { ::libaom_test::kTwoPassGood, 5 }, +#endif // !CONFIG_SINGLEPASS + { ::libaom_test::kRealTime, 5 }, }; const int kMinArfVectors[] = {
diff --git a/test/av1_encoder_parms_get_to_decoder.cc b/test/av1_encoder_parms_get_to_decoder.cc index 717584d..6b662f9 100644 --- a/test/av1_encoder_parms_get_to_decoder.cc +++ b/test/av1_encoder_parms_get_to_decoder.cc
@@ -89,7 +89,11 @@ virtual void SetUp() { InitializeConfig(); +#if CONFIG_SINGLEPASS + SetMode(::libaom_test::kOnePassGood); +#else SetMode(::libaom_test::kTwoPassGood); +#endif // CONFIG_SINGLEPASS cfg_.g_lag_in_frames = 25; test_video_ = kAV1ParamPassingTestVector; cfg_.rc_target_bitrate = test_video_.bitrate;
diff --git a/test/av1_ext_tile_test.cc b/test/av1_ext_tile_test.cc index ad45667..d9456f8 100644 --- a/test/av1_ext_tile_test.cc +++ b/test/av1_ext_tile_test.cc
@@ -71,7 +71,7 @@ cfg_.rc_end_usage = AOM_VBR; cfg_.g_error_resilient = 1; - cfg_.rc_max_quantizer = 56; + cfg_.rc_max_quantizer = 224; cfg_.rc_min_quantizer = 0; } @@ -199,17 +199,31 @@ TEST_P(AV1ExtTileTest, DecoderResultTest) { TestRoundTrip(); } +#if CONFIG_SINGLEPASS AV1_INSTANTIATE_TEST_SUITE( - // Now only test 2-pass mode. + // Only test 1-pass mode. + AV1ExtTileTest, ::testing::Values(::libaom_test::kOnePassGood), + ::testing::Range(1, 4)); +#else +AV1_INSTANTIATE_TEST_SUITE( + // Only test 2-pass mode. AV1ExtTileTest, ::testing::Values(::libaom_test::kTwoPassGood), ::testing::Range(1, 4)); +#endif // CONFIG_SINGLEPASS class AV1ExtTileTestLarge : public AV1ExtTileTest {}; TEST_P(AV1ExtTileTestLarge, DecoderResultTest) { TestRoundTrip(); } +#if CONFIG_SINGLEPASS AV1_INSTANTIATE_TEST_SUITE( - // Now only test 2-pass mode. + // Only test 1-pass mode. + AV1ExtTileTestLarge, ::testing::Values(::libaom_test::kOnePassGood), + ::testing::Range(0, 1)); +#else +AV1_INSTANTIATE_TEST_SUITE( + // Only test 2-pass mode. AV1ExtTileTestLarge, ::testing::Values(::libaom_test::kTwoPassGood), ::testing::Range(0, 1)); +#endif // CONFIG_SINGLEPASS } // namespace
diff --git a/test/best_encode.sh b/test/best_encode.sh index fe31a01..a9a72ae 100755 --- a/test/best_encode.sh +++ b/test/best_encode.sh
@@ -40,8 +40,8 @@ --kf-min-dist=0 \ --kf-max-dist=99999 \ --static-thresh=0 \ - --min-q=0 \ - --max-q=63 \ + --min-qp=0 \ + --max-qp=255 \ --drop-frame=0 \ --bias-pct=50 \ --minsection-pct=0 \ @@ -69,8 +69,8 @@ --kf-min-dist=0 \ --kf-max-dist=99999 \ --static-thresh=0 \ - --min-q=0 \ - --max-q=63 \ + --min-qp=0 \ + --max-qp=255 \ --drop-frame=0 aomenc \ @@ -90,8 +90,8 @@ --kf-min-dist=0 \ --kf-max-dist=99999 \ --static-thresh=0 \ - --min-q=0 \ - --max-q=63 \ + --min-qp=0 \ + --max-qp=255 \ --drop-frame=0 \ --bias-pct=50 \ --minsection-pct=0 \
diff --git a/test/block_test.cc b/test/block_test.cc index 510a756..e6d7c98 100644 --- a/test/block_test.cc +++ b/test/block_test.cc
@@ -192,9 +192,7 @@ << "Failed for SB size " << superblock_size_; } -AV1_INSTANTIATE_TEST_SUITE(SuperBlockSizeTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(SuperBlockSizeTestLarge, NONREALTIME_TEST_MODES, ::testing::Values(AOM_SUPERBLOCK_SIZE_64X64, AOM_SUPERBLOCK_SIZE_128X128), ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ));
diff --git a/test/borders_test.cc b/test/borders_test.cc index 841f0d9..09504cc 100644 --- a/test/borders_test.cc +++ b/test/borders_test.cc
@@ -53,10 +53,12 @@ // the encoder to producing lots of big partitions which will likely // extend into the border and test the border condition. cfg_.g_lag_in_frames = 25; +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS cfg_.rc_target_bitrate = 2000; - cfg_.rc_max_quantizer = 10; + cfg_.rc_max_quantizer = 40; ::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0, 10); @@ -69,10 +71,12 @@ // lots of small partitions which might will test the other condition. cfg_.g_lag_in_frames = 25; +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS cfg_.rc_target_bitrate = 200; - cfg_.rc_min_quantizer = 40; + cfg_.rc_min_quantizer = 160; ::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0, 10); @@ -80,6 +84,11 @@ ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); } +#if CONFIG_SINGLEPASS +AV1_INSTANTIATE_TEST_SUITE(BordersTestLarge, + ::testing::Values(::libaom_test::kOnePassGood)); +#else AV1_INSTANTIATE_TEST_SUITE(BordersTestLarge, ::testing::Values(::libaom_test::kTwoPassGood)); +#endif // !CONFIG_SINGLEPASS } // namespace
diff --git a/test/codec_factory.h b/test/codec_factory.h index 5ceb70b..2ea0ea5 100644 --- a/test/codec_factory.h +++ b/test/codec_factory.h
@@ -41,9 +41,14 @@ virtual Decoder *CreateDecoder(aom_codec_dec_cfg_t cfg, const aom_codec_flags_t flags) const = 0; +#if CONFIG_SINGLEPASS + virtual Encoder *CreateEncoder(aom_codec_enc_cfg_t cfg, + const aom_codec_flags_t init_flags) const = 0; +#else virtual Encoder *CreateEncoder(aom_codec_enc_cfg_t cfg, const aom_codec_flags_t init_flags, TwopassStatsStore *stats) const = 0; +#endif // CONFIG_SINGLEPASS virtual aom_codec_err_t DefaultEncoderConfig(aom_codec_enc_cfg_t *cfg, unsigned int usage) const = 0; @@ -101,9 +106,14 @@ class AV1Encoder : public Encoder { public: +#if CONFIG_SINGLEPASS + AV1Encoder(aom_codec_enc_cfg_t cfg, const aom_codec_flags_t init_flags) + : Encoder(cfg, init_flags) {} +#else AV1Encoder(aom_codec_enc_cfg_t cfg, const aom_codec_flags_t init_flags, TwopassStatsStore *stats) : Encoder(cfg, init_flags, stats) {} +#endif // CONFIG_SINGLEPASS protected: virtual aom_codec_iface_t *CodecInterface() const { @@ -134,15 +144,27 @@ #endif } +#if CONFIG_SINGLEPASS + virtual Encoder *CreateEncoder(aom_codec_enc_cfg_t cfg, + const aom_codec_flags_t init_flags) const +#else virtual Encoder *CreateEncoder(aom_codec_enc_cfg_t cfg, const aom_codec_flags_t init_flags, - TwopassStatsStore *stats) const { + TwopassStatsStore *stats) const +#endif // CONFIG_SINGLEPASS + { #if CONFIG_AV1_ENCODER +#if CONFIG_SINGLEPASS + return new AV1Encoder(cfg, init_flags); +#else return new AV1Encoder(cfg, init_flags, stats); +#endif // CONFIG_SINGLEPASS #else (void)cfg; (void)init_flags; +#if !CONFIG_SINGLEPASS (void)stats; +#endif // !CONFIG_SINGLEPASS return NULL; #endif }
diff --git a/test/coding_path_sync.cc b/test/coding_path_sync.cc index 4c613dc..4779120 100644 --- a/test/coding_path_sync.cc +++ b/test/coding_path_sync.cc
@@ -36,9 +36,9 @@ // force the quantizer, to reduce the sensitivity on encoding choices. // e.g, we don't want this test to break when the rate control is modified. { - const int max_q = cfg.rc_max_quantizer; - const int min_q = cfg.rc_min_quantizer; - const int q = rnd_.PseudoUniform(max_q - min_q + 1) + min_q; + const int max_qp = cfg.rc_max_quantizer; + const int min_qp = cfg.rc_min_quantizer; + const int q = rnd_.PseudoUniform(max_qp - min_qp + 1) + min_qp; cfg.rc_end_usage = AOM_Q; cfg.rc_max_quantizer = q;
diff --git a/test/cpu_speed_test.cc b/test/cpu_speed_test.cc index 9ef3a5c..f31cea6 100644 --- a/test/cpu_speed_test.cc +++ b/test/cpu_speed_test.cc
@@ -78,8 +78,10 @@ // without a mismatch when passing in a very low max q. This pushes // the encoder to producing lots of big partitions which will likely // extend into the border and test the border condition. +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS cfg_.rc_target_bitrate = 400; cfg_.rc_max_quantizer = 0; cfg_.rc_min_quantizer = 0; @@ -96,8 +98,10 @@ void CpuSpeedTest::TestScreencastQ0() { ::libaom_test::Y4mVideoSource video("screendata.y4m", 0, 3); cfg_.g_timebase = video.timebase(); +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS cfg_.rc_target_bitrate = 400; cfg_.rc_max_quantizer = 0; cfg_.rc_min_quantizer = 0; @@ -111,10 +115,12 @@ void CpuSpeedTest::TestTuneScreen() { ::libaom_test::Y4mVideoSource video("screendata.y4m", 0, 3); cfg_.g_timebase = video.timebase(); +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_minsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS cfg_.rc_target_bitrate = 2000; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_min_quantizer = 0; tune_content_ = AOM_CONTENT_SCREEN; @@ -128,10 +134,12 @@ // without a mismatch when passing in a very low max q. This pushes // the encoder to producing lots of big partitions which will likely // extend into the border and test the border condition. +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS cfg_.rc_target_bitrate = 12000; - cfg_.rc_max_quantizer = 10; + cfg_.rc_max_quantizer = 40; cfg_.rc_min_quantizer = 0; ::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0, @@ -144,10 +152,12 @@ // Validate that this clip encodes and decodes without a mismatch // when passing in a very high min q. This pushes the encoder to producing // lots of small partitions which might will test the other condition. +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS cfg_.rc_target_bitrate = 200; - cfg_.rc_min_quantizer = 40; + cfg_.rc_min_quantizer = 160; ::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0, 10); @@ -169,12 +179,8 @@ TEST_P(CpuSpeedTestLarge, TestEncodeHighBitrate) { TestEncodeHighBitrate(); } TEST_P(CpuSpeedTestLarge, TestLowBitrate) { TestLowBitrate(); } -AV1_INSTANTIATE_TEST_SUITE(CpuSpeedTest, - ::testing::Values(::libaom_test::kTwoPassGood, - ::libaom_test::kOnePassGood), +AV1_INSTANTIATE_TEST_SUITE(CpuSpeedTest, NONREALTIME_TEST_MODES, ::testing::Range(1, 3)); -AV1_INSTANTIATE_TEST_SUITE(CpuSpeedTestLarge, - ::testing::Values(::libaom_test::kTwoPassGood, - ::libaom_test::kOnePassGood), +AV1_INSTANTIATE_TEST_SUITE(CpuSpeedTestLarge, NONREALTIME_TEST_MODES, ::testing::Range(0, 1)); } // namespace
diff --git a/test/datarate_test.cc b/test/datarate_test.cc index b82c31f..ff64aca 100644 --- a/test/datarate_test.cc +++ b/test/datarate_test.cc
@@ -45,7 +45,7 @@ virtual void BasicRateTargetingVBRTest() { cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.g_error_resilient = 0; cfg_.rc_end_usage = AOM_VBR; cfg_.g_lag_in_frames = 0; @@ -68,7 +68,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 1; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; @@ -92,7 +92,7 @@ cfg_.rc_dropframe_thresh = 0; cfg_.g_error_resilient = 1; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; @@ -113,7 +113,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 1; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; // Periodic keyframe @@ -138,7 +138,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; // Periodic keyframe @@ -162,8 +162,8 @@ cfg_.rc_buf_optimal_sz = 500; cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; - cfg_.rc_min_quantizer = 2; - cfg_.rc_max_quantizer = 63; + cfg_.rc_min_quantizer = 8; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 0; @@ -193,7 +193,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 1; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; const int bitrate_array[2] = { 250, 650 }; @@ -238,7 +238,7 @@ cfg_.rc_undershoot_pct = 20; cfg_.rc_dropframe_thresh = 10; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 50; + cfg_.rc_max_quantizer = 200; cfg_.rc_end_usage = AOM_CBR; cfg_.rc_target_bitrate = 200; cfg_.g_lag_in_frames = 0; @@ -351,7 +351,7 @@ cfg_.rc_undershoot_pct = 20; cfg_.rc_dropframe_thresh = 10; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 50; + cfg_.rc_max_quantizer = 200; cfg_.rc_end_usage = AOM_CBR; cfg_.rc_target_bitrate = 200; cfg_.g_lag_in_frames = 0;
diff --git a/test/decode_multithreaded_test.cc b/test/decode_multithreaded_test.cc index 5224dcc..3b687d0 100644 --- a/test/decode_multithreaded_test.cc +++ b/test/decode_multithreaded_test.cc
@@ -71,7 +71,11 @@ virtual void SetUp() { InitializeConfig(); +#if CONFIG_SINGLEPASS + SetMode(libaom_test::kOnePassGood); +#else SetMode(libaom_test::kTwoPassGood); +#endif // CONFIG_SINGLEPASS } virtual void PreEncodeFrameHook(libaom_test::VideoSource *video,
diff --git a/test/decode_perf_test.cc b/test/decode_perf_test.cc index 9f0de03..416fd9d 100644 --- a/test/decode_perf_test.cc +++ b/test/decode_perf_test.cc
@@ -110,8 +110,8 @@ SetMode(encoding_mode_); cfg_.g_lag_in_frames = 25; - cfg_.rc_min_quantizer = 2; - cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 8; + cfg_.rc_max_quantizer = 224; cfg_.rc_dropframe_thresh = 0; cfg_.rc_undershoot_pct = 50; cfg_.rc_overshoot_pct = 50;
diff --git a/test/encode_perf_test.cc b/test/encode_perf_test.cc index b626acd..bcd0184 100644 --- a/test/encode_perf_test.cc +++ b/test/encode_perf_test.cc
@@ -70,8 +70,8 @@ SetMode(encoding_mode_); cfg_.g_lag_in_frames = 0; - cfg_.rc_min_quantizer = 2; - cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 8; + cfg_.rc_max_quantizer = 224; cfg_.rc_dropframe_thresh = 0; cfg_.rc_undershoot_pct = 50; cfg_.rc_overshoot_pct = 50;
diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc index 0139d1f..89c7aec 100644 --- a/test/encode_test_driver.cc +++ b/test/encode_test_driver.cc
@@ -32,7 +32,9 @@ cfg_.g_w = img->d_w; cfg_.g_h = img->d_h; cfg_.g_timebase = video->timebase(); +#if !CONFIG_SINGLEPASS cfg_.rc_twopass_stats_in = stats_->buf(); +#endif // !CONFIG_SINGLEPASS res = aom_codec_enc_init(&encoder_, CodecInterface(), &cfg_, init_flags_); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); @@ -45,6 +47,7 @@ else Flush(); +#if !CONFIG_SINGLEPASS // Handle twopass stats CxDataIterator iter = GetCxData(); @@ -53,6 +56,7 @@ stats_->Append(*pkt); } +#endif // !CONFIG_SINGLEPASS } void Encoder::EncodeFrameInternal(const VideoSource &video, @@ -90,8 +94,10 @@ void EncoderTest::SetMode(TestMode mode) { switch (mode) { - case kOnePassGood: + case kOnePassGood: break; +#if !CONFIG_SINGLEPASS case kTwoPassGood: break; +#endif // !CONFIG_SINGLEPASS case kRealTime: { cfg_.g_lag_in_frames = 0; cfg_.g_usage = AOM_USAGE_REALTIME; @@ -100,10 +106,14 @@ default: ASSERT_TRUE(false) << "Unexpected mode " << mode; } mode_ = mode; +#if CONFIG_SINGLEPASS + passes_ = 1; +#else if (mode == kTwoPassGood) passes_ = 2; else passes_ = 1; +#endif // CONFIG_SINGLEPASS } static bool compare_plane(const uint8_t *const buf1, int stride1, @@ -183,9 +193,15 @@ aom_codec_dec_cfg_t dec_cfg = aom_codec_dec_cfg_t(); dec_cfg.allow_lowbitdepth = 1; +#if !CONFIG_SINGLEPASS stats_.Reset(); +#endif // !CONFIG_SINGLEPASS +#if CONFIG_SINGLEPASS + ASSERT_EQ(1, (int)passes_); +#else ASSERT_TRUE(passes_ == 1 || passes_ == 2); +#endif // CONFIG_SINGLEPASS for (unsigned int pass = 0; pass < passes_; pass++) { last_pts_ = 0; @@ -197,8 +213,12 @@ cfg_.g_pass = AOM_RC_LAST_PASS; BeginPassHook(pass); +#if CONFIG_SINGLEPASS + std::unique_ptr<Encoder> encoder(codec_->CreateEncoder(cfg_, init_flags_)); +#else std::unique_ptr<Encoder> encoder( codec_->CreateEncoder(cfg_, init_flags_, &stats_)); +#endif // CONFIG_SINGLEPASS ASSERT_TRUE(encoder.get() != NULL); ASSERT_NO_FATAL_FAILURE(video->Begin()); @@ -267,7 +287,9 @@ case AOM_CODEC_PSNR_PKT: PSNRPktHook(pkt); break; +#if !CONFIG_SINGLEPASS case AOM_CODEC_STATS_PKT: StatsPktHook(pkt); break; +#endif // !CONFIG_SINGLEPASS default: break; }
diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h index 9744b11..369615f 100644 --- a/test/encode_test_driver.h +++ b/test/encode_test_driver.h
@@ -28,6 +28,18 @@ class CodecFactory; class VideoSource; +#if CONFIG_SINGLEPASS +enum TestMode { kRealTime, kOnePassGood }; +#define ALL_TEST_MODES \ + ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood) + +#define ONE_PASS_TEST_MODES \ + ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood) + +#define TWO_PASS_TEST_MODES ::testing::Values() + +#define NONREALTIME_TEST_MODES ::testing::Values(::libaom_test::kOnePassGood) +#else enum TestMode { kRealTime, kOnePassGood, kTwoPassGood }; #define ALL_TEST_MODES \ ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood, \ @@ -40,6 +52,7 @@ #define NONREALTIME_TEST_MODES \ ::testing::Values(::libaom_test::kOnePassGood, ::libaom_test::kTwoPassGood) +#endif // CONFIG_SINGLEPASS // Provides an object to handle the libaom get_cx_data() iteration pattern class CxDataIterator { @@ -82,11 +95,18 @@ // level of abstraction will be fleshed out as more tests are written. class Encoder { public: +#if CONFIG_SINGLEPASS + Encoder(aom_codec_enc_cfg_t cfg, const aom_codec_flags_t init_flags) + : cfg_(cfg), init_flags_(init_flags) { + memset(&encoder_, 0, sizeof(encoder_)); + } +#else Encoder(aom_codec_enc_cfg_t cfg, const aom_codec_flags_t init_flags, TwopassStatsStore *stats) : cfg_(cfg), init_flags_(init_flags), stats_(stats) { memset(&encoder_, 0, sizeof(encoder_)); } +#endif // !CONFIG_SINGLEPASS virtual ~Encoder() { aom_codec_destroy(&encoder_); } @@ -165,7 +185,9 @@ aom_codec_ctx_t encoder_; aom_codec_enc_cfg_t cfg_; aom_codec_flags_t init_flags_; +#if !CONFIG_SINGLEPASS TwopassStatsStore *stats_; +#endif // !CONFIG_SINGLEPASS }; // Common test functionality for all Encoder tests. @@ -255,7 +277,9 @@ bool abort_; aom_codec_enc_cfg_t cfg_; unsigned int passes_; +#if !CONFIG_SINGLEPASS TwopassStatsStore stats_; +#endif // !CONFIG_SINGLEPASS aom_codec_flags_t init_flags_; unsigned long frame_flags_; aom_codec_pts_t last_pts_;
diff --git a/test/end_to_end_test.cc b/test/end_to_end_test.cc index 82a4a8c..f1e5ebc 100644 --- a/test/end_to_end_test.cc +++ b/test/end_to_end_test.cc
@@ -77,7 +77,9 @@ // Encoding modes tested const libaom_test::TestMode kEncodingModeVectors[] = { +#if !CONFIG_SINGLEPASS ::libaom_test::kTwoPassGood, +#endif // !CONFIG_SINGLEPASS ::libaom_test::kOnePassGood, ::libaom_test::kRealTime, }; @@ -136,11 +138,15 @@ encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1); encoder->Control(AV1E_SET_TILE_COLUMNS, 4); encoder->Control(AOME_SET_CPUUSED, cpu_used_); +#if CONFIG_SINGLEPASS + encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_DEFAULT); +#else // Test screen coding tools at cpu_used = 1 && encoding mode is two-pass. if (cpu_used_ == 1 && encoding_mode_ == ::libaom_test::kTwoPassGood) encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN); else encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_DEFAULT); +#endif // CONFIG_SINGLEPASS if (encoding_mode_ != ::libaom_test::kRealTime) { encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1); encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
diff --git a/test/error_resilience_test.cc b/test/error_resilience_test.cc index f7e4287..efbb701 100644 --- a/test/error_resilience_test.cc +++ b/test/error_resilience_test.cc
@@ -541,9 +541,7 @@ * Hence this configuration is not added. Add this configuration after the * bug is fixed. */ -AV1_INSTANTIATE_TEST_SUITE(SFramePresenceTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(SFramePresenceTestLarge, NONREALTIME_TEST_MODES, ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ), ::testing::Values(0)); } // namespace
diff --git a/test/ethread_test.cc b/test/ethread_test.cc index 04ee4d7..81b036d 100644 --- a/test/ethread_test.cc +++ b/test/ethread_test.cc
@@ -45,9 +45,11 @@ cfg_.g_lag_in_frames = 35; cfg_.rc_end_usage = AOM_VBR; +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; - cfg_.rc_max_quantizer = 56; +#endif // !CONFIG_SINGLEPASS + cfg_.rc_max_quantizer = 224; cfg_.rc_min_quantizer = 0; } @@ -232,14 +234,16 @@ if (encoding_mode_ != ::libaom_test::kRealTime) { cfg_.g_lag_in_frames = 5; cfg_.rc_end_usage = AOM_VBR; +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS } else { cfg_.g_lag_in_frames = 0; cfg_.rc_end_usage = AOM_CBR; cfg_.g_error_resilient = 1; } - cfg_.rc_max_quantizer = 56; + cfg_.rc_max_quantizer = 224; cfg_.rc_min_quantizer = 0; } @@ -438,6 +442,10 @@ DoTest(); } +#if CONFIG_SINGLEPASS +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AVxFirstPassEncoderThreadTest); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AVxEncoderThreadTest); +#else // first pass stats test AV1_INSTANTIATE_TEST_SUITE(AVxFirstPassEncoderThreadTest, ::testing::Values(::libaom_test::kTwoPassGood), @@ -450,14 +458,23 @@ ::testing::Values(::libaom_test::kTwoPassGood), ::testing::Values(2), ::testing::Values(0, 2), ::testing::Values(0, 2), ::testing::Values(0, 1)); +#endif // CONFIG_SINGLEPASS // Test cpu_used 0, 1, 3 and 5. +#if CONFIG_SINGLEPASS AV1_INSTANTIATE_TEST_SUITE(AVxEncoderThreadTestLarge, - ::testing::Values(::libaom_test::kTwoPassGood, - ::libaom_test::kOnePassGood), + ::testing::Values(::libaom_test::kOnePassGood), ::testing::Values(0, 1, 3, 5), - ::testing::Values(1, 6), ::testing::Values(1, 6), + ::testing::Values(0, 1, 2, 6), + ::testing::Values(0, 1, 2, 6), ::testing::Values(0, 1)); +#else +AV1_INSTANTIATE_TEST_SUITE( + AVxEncoderThreadTestLarge, + ::testing::Values(::libaom_test::kTwoPassGood, ::libaom_test::kOnePassGood), + ::testing::Values(0, 1, 3, 5), ::testing::Values(0, 1, 2, 6), + ::testing::Values(0, 1, 2, 6), ::testing::Values(0, 1)); +#endif // CONFIG_SINGLEPASS class AVxEncoderThreadLSTest : public AVxEncoderThreadTest { virtual void SetTileSize(libaom_test::Encoder *encoder) { @@ -493,9 +510,7 @@ DoTest(); } -AV1_INSTANTIATE_TEST_SUITE(AVxEncoderThreadLSTestLarge, - ::testing::Values(::libaom_test::kTwoPassGood, - ::libaom_test::kOnePassGood), - ::testing::Values(1, 3), ::testing::Values(0, 6), - ::testing::Values(0, 6), ::testing::Values(1)); +AV1_INSTANTIATE_TEST_SUITE(AVxEncoderThreadLSTestLarge, NONREALTIME_TEST_MODES, + ::testing::Range(0, 4), ::testing::Values(0, 6), + ::testing::Values(0, 6), ::testing::Values(0, 1)); } // namespace
diff --git a/test/examples.sh b/test/examples.sh index 2cdb89d..0a52847 100755 --- a/test/examples.sh +++ b/test/examples.sh
@@ -16,6 +16,8 @@ # List of script names to exclude. exclude_list="best_encode examples run_encodes tools_common" +[ "$(aom_config_option_enabled CONFIG_SINGLEPASS)" = "yes" ] && \ + exclude_list="$exclude_list twopass_encoder lightfield_test" # Filter out the scripts in $exclude_list. for word in ${exclude_list}; do
diff --git a/test/fwd_kf_test.cc b/test/fwd_kf_test.cc index fb12402..299314c 100644 --- a/test/fwd_kf_test.cc +++ b/test/fwd_kf_test.cc
@@ -110,9 +110,7 @@ << "kf max dist = " << kf_max_dist_; } -AV1_INSTANTIATE_TEST_SUITE(ForwardKeyTest, - ::testing::Values(::libaom_test::kTwoPassGood, - ::libaom_test::kOnePassGood), +AV1_INSTANTIATE_TEST_SUITE(ForwardKeyTest, NONREALTIME_TEST_MODES, ::testing::ValuesIn(kTestParams)); typedef struct { @@ -189,9 +187,7 @@ ASSERT_EQ(is_fwd_kf_present_, 1); } -AV1_INSTANTIATE_TEST_SUITE(ForwardKeyPresenceTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(ForwardKeyPresenceTestLarge, NONREALTIME_TEST_MODES, ::testing::ValuesIn(kfTestParams), ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ)); } // namespace
diff --git a/test/gf_pyr_height_test.cc b/test/gf_pyr_height_test.cc index 87a0d0d..7b301e8 100644 --- a/test/gf_pyr_height_test.cc +++ b/test/gf_pyr_height_test.cc
@@ -111,7 +111,7 @@ if (video->frame() == 0) { encoder->Control(AOME_SET_CPUUSED, cpu_used_); if (rc_mode_ == AOM_Q) { - encoder->Control(AOME_SET_CQ_LEVEL, 32); + encoder->Control(AOME_SET_QP, 32); } if (encoding_mode_ != ::libaom_test::kRealTime) { encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
diff --git a/test/horz_superres_test.cc b/test/horz_superres_test.cc index 4b96d44..fca8573 100644 --- a/test/horz_superres_test.cc +++ b/test/horz_superres_test.cc
@@ -76,9 +76,9 @@ // Superres q thresholds and superres kf q thresholds to be tested typedef tuple<int, int> SuperresQThresholdPair; const SuperresQThresholdPair kSuperresQThresholds[] = { - make_tuple(63, 63), make_tuple(63, 41), make_tuple(17, 63), - make_tuple(41, 11), make_tuple(1, 37), make_tuple(11, 11), - make_tuple(1, 1), make_tuple(17, 29), make_tuple(29, 11), + make_tuple(255, 255), make_tuple(255, 164), make_tuple(68, 255), + make_tuple(164, 44), make_tuple(4, 148), make_tuple(44, 44), + make_tuple(4, 4), make_tuple(68, 116), make_tuple(116, 44), }; /* END (TESTING PARAMETERS) */ @@ -101,7 +101,11 @@ virtual void SetUp() { InitializeConfig(); +#if CONFIG_SINGLEPASS + SetMode(::libaom_test::kOnePassGood); +#else SetMode(::libaom_test::kTwoPassGood); +#endif // CONFIG_SINGLEPASS cfg_.g_lag_in_frames = 5; cfg_.rc_end_usage = AOM_Q; cfg_.rc_target_bitrate = kBitrate; @@ -204,7 +208,11 @@ virtual void SetUp() { InitializeConfig(); +#if CONFIG_SINGLEPASS + SetMode(::libaom_test::kOnePassGood); +#else SetMode(::libaom_test::kTwoPassGood); +#endif // CONFIG_SINGLEPASS cfg_.g_lag_in_frames = 5; cfg_.rc_end_usage = AOM_VBR; cfg_.rc_target_bitrate = kBitrate; @@ -315,7 +323,11 @@ virtual void SetUp() { InitializeConfig(); +#if CONFIG_SINGLEPASS + SetMode(::libaom_test::kOnePassGood); +#else SetMode(::libaom_test::kTwoPassGood); +#endif // CONFIG_SINGLEPASS cfg_.g_lag_in_frames = 5; cfg_.rc_end_usage = AOM_VBR; cfg_.rc_target_bitrate = kBitrate;
diff --git a/test/kf_test.cc b/test/kf_test.cc index 0b36881..21eb444 100644 --- a/test/kf_test.cc +++ b/test/kf_test.cc
@@ -248,17 +248,13 @@ } } -AV1_INSTANTIATE_TEST_SUITE(KeyFrameIntervalTestLarge, - testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(KeyFrameIntervalTestLarge, NONREALTIME_TEST_MODES, ::testing::ValuesIn(kfTestParams), ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ)); // TODO(anyone): Add CBR to list of rc_modes once forced kf placement after // lag in frames bug is fixed. -AV1_INSTANTIATE_TEST_SUITE(ForcedKeyTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(ForcedKeyTestLarge, NONREALTIME_TEST_MODES, ::testing::Values(0, 1), ::testing::Values(0, 1), ::testing::Values(2, 5), ::testing::Values(AOM_Q, AOM_VBR, AOM_CQ));
diff --git a/test/level_test.cc b/test/level_test.cc index 82ada98..0739df3 100644 --- a/test/level_test.cc +++ b/test/level_test.cc
@@ -153,8 +153,13 @@ } } +#if CONFIG_SINGLEPASS AV1_INSTANTIATE_TEST_SUITE(LevelTest, - ::testing::Values(::libaom_test::kTwoPassGood, - ::libaom_test::kOnePassGood), + ::testing::Values(::libaom_test::kOnePassGood), ::testing::ValuesIn(kCpuUsedVectors)); +#else +AV1_INSTANTIATE_TEST_SUITE(LevelTest, + ::testing::Values(::libaom_test::kTwoPassGood), + ::testing::ValuesIn(kCpuUsedVectors)); +#endif // CONFIG_SINGLEPASS } // namespace
diff --git a/test/lossless_test.cc b/test/lossless_test.cc index b56b43a..85eced7 100644 --- a/test/lossless_test.cc +++ b/test/lossless_test.cc
@@ -125,8 +125,8 @@ cfg_.g_lag_in_frames = 25; // Intentionally set Q > 0, to make sure control can be used to activate // lossless - cfg_.rc_min_quantizer = 10; - cfg_.rc_max_quantizer = 20; + cfg_.rc_min_quantizer = 40; + cfg_.rc_max_quantizer = 80; init_flags_ = AOM_CODEC_USE_PSNR; @@ -137,8 +137,6 @@ EXPECT_GE(psnr_lossless, kMaxPsnr); } -AV1_INSTANTIATE_TEST_SUITE(LosslessTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(LosslessTestLarge, NONREALTIME_TEST_MODES, ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ)); } // namespace
diff --git a/test/metadata_test.cc b/test/metadata_test.cc index c102b7a..1b7e586 100644 --- a/test/metadata_test.cc +++ b/test/metadata_test.cc
@@ -175,8 +175,8 @@ cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_optimal_sz = 600; cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 2; - cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 8; + cfg_.rc_max_quantizer = 224; cfg_.rc_undershoot_pct = 50; cfg_.rc_overshoot_pct = 50; cfg_.rc_end_usage = AOM_CBR;
diff --git a/test/monochrome_test.cc b/test/monochrome_test.cc index 4688961..f09a148 100644 --- a/test/monochrome_test.cc +++ b/test/monochrome_test.cc
@@ -77,6 +77,7 @@ frame0_psnr_y_ = pkt->data.psnr.psnr[1]; EXPECT_GT(frame0_psnr_y_, 29.); } + EXPECT_GT(pkt->data.psnr.psnr[1], 29.); EXPECT_NEAR(pkt->data.psnr.psnr[1], frame0_psnr_y_, 2.5); } @@ -96,8 +97,8 @@ cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_optimal_sz = 600; cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 2; - cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 8; + cfg_.rc_max_quantizer = 224; cfg_.rc_undershoot_pct = 50; cfg_.rc_overshoot_pct = 50; cfg_.rc_end_usage = AOM_CBR; @@ -124,8 +125,6 @@ } } -AV1_INSTANTIATE_TEST_SUITE(MonochromeTest, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood)); +AV1_INSTANTIATE_TEST_SUITE(MonochromeTest, NONREALTIME_TEST_MODES); } // namespace
diff --git a/test/motion_vector_test.cc b/test/motion_vector_test.cc index 7516a36..4a0a399 100644 --- a/test/motion_vector_test.cc +++ b/test/motion_vector_test.cc
@@ -24,7 +24,9 @@ // Encoding modes const libaom_test::TestMode kEncodingModeVectors[] = { +#if !CONFIG_SINGLEPASS ::libaom_test::kTwoPassGood, +#endif // !CONFIG_SINGLEPASS ::libaom_test::kOnePassGood, };
diff --git a/test/quant_test.cc b/test/quant_test.cc index 2ef3a76..3974284 100644 --- a/test/quant_test.cc +++ b/test/quant_test.cc
@@ -49,8 +49,8 @@ qm_min_ = qm_min; qm_max_ = qm_max; cfg_.kf_max_dist = 12; - cfg_.rc_min_quantizer = 8; - cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 32; + cfg_.rc_max_quantizer = 224; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 6; cfg_.rc_buf_initial_sz = 500; @@ -87,7 +87,7 @@ } QuantParam; const QuantParam QuantTestParams[] = { - { 0, 10 }, { 0, 60 }, { 20, 35 }, { 35, 50 }, { 50, 63 } + { 0, 50 }, { 0, 240 }, { 100, 150 }, { 150, 200 }, { 200, 255 } }; std::ostream &operator<<(std::ostream &os, const QuantParam &test_arg) { @@ -142,8 +142,8 @@ aom_codec_ctx_t *ctx_dec = decoder->GetDecoder(); AOM_CODEC_CONTROL_TYPECHECKED(ctx_dec, AOMD_GET_LAST_QUANTIZER, &base_qindex_); - min_bound_qindex_ = av1_quantizer_to_qindex(cfg_.rc_min_quantizer); - max_bound_qindex_ = av1_quantizer_to_qindex(cfg_.rc_max_quantizer); + min_bound_qindex_ = cfg_.rc_min_quantizer; + max_bound_qindex_ = cfg_.rc_max_quantizer; if ((base_qindex_ < min_bound_qindex_ || base_qindex_ > max_bound_qindex_) && quant_bound_violated_ == false) { @@ -171,8 +171,7 @@ } AV1_INSTANTIATE_TEST_SUITE(QuantizerBoundsCheckTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), + NONREALTIME_TEST_MODES, ::testing::ValuesIn(QuantTestParams), ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ)); } // namespace
diff --git a/test/resize_test.cc b/test/resize_test.cc index f4ad15f..41c0024 100644 --- a/test/resize_test.cc +++ b/test/resize_test.cc
@@ -331,7 +331,7 @@ change_config_ = false; // q picked such that initial keyframe on this clip is ~30dB PSNR - cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48; + cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 192; // If the number of frames being encoded is smaller than g_lag_in_frames // the encoded frame is unavailable using the current API. Comparing @@ -431,8 +431,8 @@ cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_optimal_sz = 600; cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 2; - cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 8; + cfg_.rc_max_quantizer = 224; cfg_.rc_undershoot_pct = 50; cfg_.rc_overshoot_pct = 50; cfg_.rc_end_usage = AOM_CBR; @@ -775,7 +775,7 @@ for (const aom_img_fmt_t &img_format : image_formats) { ResizingCspVideoSource video(img_format); init_flags_ = AOM_CODEC_USE_PSNR; - cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48; + cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 192; cfg_.g_lag_in_frames = 0; cfg_.g_profile = (img_format == AOM_IMG_FMT_I420) ? 0 : 1; ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
diff --git a/test/sb_multipass_test.cc b/test/sb_multipass_test.cc index d2f56db..f5ea5b3 100644 --- a/test/sb_multipass_test.cc +++ b/test/sb_multipass_test.cc
@@ -46,14 +46,20 @@ virtual void SetUp() { InitializeConfig(); +#if CONFIG_SINGLEPASS + SetMode(::libaom_test::kOnePassGood); +#else SetMode(::libaom_test::kTwoPassGood); +#endif // CONFIG_SINGLEPASS cfg_.g_lag_in_frames = 5; cfg_.rc_end_usage = AOM_VBR; +#if !CONFIG_SINGLEPASS cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_maxsection_pct = 2000; +#endif // !CONFIG_SINGLEPASS - cfg_.rc_max_quantizer = 56; + cfg_.rc_max_quantizer = 224; cfg_.rc_min_quantizer = 0; }
diff --git a/test/scalability_test.cc b/test/scalability_test.cc index d38d8ab..24618b8 100644 --- a/test/scalability_test.cc +++ b/test/scalability_test.cc
@@ -46,7 +46,7 @@ AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY; encoder->Control(AOME_SET_SPATIAL_LAYER_ID, 1); - encoder->Control(AOME_SET_CQ_LEVEL, kEnhancementLayerQp); + encoder->Control(AOME_SET_QP, kEnhancementLayerQp); } else { frame_flags_ = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | @@ -54,7 +54,7 @@ AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY; encoder->Control(AOME_SET_SPATIAL_LAYER_ID, 0); - encoder->Control(AOME_SET_CQ_LEVEL, kBaseLayerQp); + encoder->Control(AOME_SET_QP, kBaseLayerQp); } }
diff --git a/test/screen_content_test.cc b/test/screen_content_test.cc index ecf2ef5..e050eda 100644 --- a/test/screen_content_test.cc +++ b/test/screen_content_test.cc
@@ -107,8 +107,6 @@ // << "Failed detection of screen content(lowres)"; } -AV1_INSTANTIATE_TEST_SUITE(ScreenContentToolsTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(ScreenContentToolsTestLarge, NONREALTIME_TEST_MODES, ::testing::Values(AOM_Q)); } // namespace
diff --git a/test/still_picture_test.cc b/test/still_picture_test.cc index dc88ef0..77d52c8 100644 --- a/test/still_picture_test.cc +++ b/test/still_picture_test.cc
@@ -90,7 +90,5 @@ } AV1_INSTANTIATE_TEST_SUITE(StillPicturePresenceTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), - ::testing::Values(1, 0)); + NONREALTIME_TEST_MODES, ::testing::Values(1, 0)); } // namespace
diff --git a/test/stream_iter_test.cc b/test/stream_iter_test.cc new file mode 100644 index 0000000..f7376ac --- /dev/null +++ b/test/stream_iter_test.cc
@@ -0,0 +1,285 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include <stdbool.h> +#include "common/stream_iter.h" +#include "third_party/googletest/src/googletest/include/gtest/gtest.h" + +namespace { + +// Dummy class that increments the width field in the image, which is used +// as a placeholder for the frame number. Stops iterating after N frames. +int dummy_reader(StreamIter *iter, aom_image_t *raw) { + if (iter->current >= iter->n) { + return 0; + } + ++iter->current; + raw->w = iter->current; + return 1; +} + +void dummy_stream_iter_init(StreamIter *iter, int total) { + iter->current = 0; + iter->n = total; + iter->reader = dummy_reader; +} + +class StreamIterTest : public ::testing::Test {}; + +TEST_F(StreamIterTest, Skip0) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter skip; + skip_stream_iter_init(&skip, &input, 0); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&skip, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_TRUE(read_stream_iter(&skip, &img)); + EXPECT_EQ(2U, img.w); + + EXPECT_TRUE(read_stream_iter(&skip, &img)); + EXPECT_EQ(3U, img.w); + + EXPECT_FALSE(read_stream_iter(&skip, &img)); +} + +TEST_F(StreamIterTest, Skip1) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter skip; + skip_stream_iter_init(&skip, &input, 1); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&skip, &img)); + EXPECT_EQ(2U, img.w); + + EXPECT_TRUE(read_stream_iter(&skip, &img)); + EXPECT_EQ(3U, img.w); + + EXPECT_FALSE(read_stream_iter(&skip, &img)); +} + +TEST_F(StreamIterTest, Skip2) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter skip; + skip_stream_iter_init(&skip, &input, 2); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&skip, &img)); + EXPECT_EQ(3U, img.w); + + EXPECT_FALSE(read_stream_iter(&skip, &img)); +} + +TEST_F(StreamIterTest, Skip3) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter skip; + skip_stream_iter_init(&skip, &input, 3); + + aom_image_t img; + EXPECT_FALSE(read_stream_iter(&skip, &img)); +} + +TEST_F(StreamIterTest, Skip4) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter skip; + skip_stream_iter_init(&skip, &input, 4); + + aom_image_t img; + EXPECT_FALSE(read_stream_iter(&skip, &img)); +} + +// limit=0 is a special case meaning "no limit." +TEST_F(StreamIterTest, Limit0) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter limit; + limit_stream_iter_init(&limit, &input, 0); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(2U, img.w); + + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(3U, img.w); + + EXPECT_FALSE(read_stream_iter(&limit, &img)); +} + +TEST_F(StreamIterTest, Limit1) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter limit; + limit_stream_iter_init(&limit, &input, 1); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_FALSE(read_stream_iter(&limit, &img)); +} + +TEST_F(StreamIterTest, Limit2) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter limit; + limit_stream_iter_init(&limit, &input, 2); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(2U, img.w); + + EXPECT_FALSE(read_stream_iter(&limit, &img)); +} + +TEST_F(StreamIterTest, Limit3) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter limit; + limit_stream_iter_init(&limit, &input, 3); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(2U, img.w); + + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(3U, img.w); + + EXPECT_FALSE(read_stream_iter(&limit, &img)); +} + +TEST_F(StreamIterTest, Limit4) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter limit; + limit_stream_iter_init(&limit, &input, 4); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(2U, img.w); + + EXPECT_TRUE(read_stream_iter(&limit, &img)); + EXPECT_EQ(3U, img.w); + + EXPECT_FALSE(read_stream_iter(&limit, &img)); +} + +TEST_F(StreamIterTest, Step1) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter step; + step_stream_iter_init(&step, &input, 1); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(2U, img.w); + + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(3U, img.w); + + EXPECT_FALSE(read_stream_iter(&step, &img)); +} + +TEST_F(StreamIterTest, Step2) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter step; + step_stream_iter_init(&step, &input, 2); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(3U, img.w); + + EXPECT_FALSE(read_stream_iter(&step, &img)); +} + +TEST_F(StreamIterTest, Step3) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter step; + step_stream_iter_init(&step, &input, 3); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_FALSE(read_stream_iter(&step, &img)); +} + +TEST_F(StreamIterTest, Step4) { + StreamIter input; + dummy_stream_iter_init(&input, 3); + + StreamIter step; + step_stream_iter_init(&step, &input, 4); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_FALSE(read_stream_iter(&step, &img)); +} + +// Test when the step size is an even divisor of the number of frames. +TEST_F(StreamIterTest, Step5) { + StreamIter input; + dummy_stream_iter_init(&input, 10); + + StreamIter step; + step_stream_iter_init(&step, &input, 5); + + aom_image_t img; + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(1U, img.w); + + EXPECT_TRUE(read_stream_iter(&step, &img)); + EXPECT_EQ(6U, img.w); + + EXPECT_FALSE(read_stream_iter(&step, &img)); +} + +} // namespace
diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc index 774593c..f91f1b8 100644 --- a/test/svc_datarate_test.cc +++ b/test/svc_datarate_test.cc
@@ -384,8 +384,8 @@ svc_params->number_spatial_layers = number_spatial_layers; svc_params->number_temporal_layers = number_temporal_layers; for (int i = 0; i < number_temporal_layers * number_spatial_layers; ++i) { - svc_params->max_quantizers[i] = 60; - svc_params->min_quantizers[i] = 2; + svc_params->max_quantizers[i] = 240; + svc_params->min_quantizers[i] = 8; svc_params->layer_target_bitrate[i] = target_layer_bitrate_[i]; } // Do at most 3 spatial or temporal layers here. @@ -421,7 +421,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 1; @@ -450,7 +450,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 1; @@ -498,7 +498,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 1; @@ -527,7 +527,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 1; @@ -557,7 +557,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 1; @@ -599,7 +599,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 1; @@ -640,7 +640,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 1; @@ -684,7 +684,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; cfg_.g_error_resilient = 1; @@ -773,7 +773,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; // error_resilient can set to off/0, since for SVC the context update @@ -818,7 +818,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0; // error_resilient for sequence can be off/0, since dropped frames (TL2) @@ -863,7 +863,7 @@ cfg_.rc_buf_sz = 1000; cfg_.rc_dropframe_thresh = 0; cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; + cfg_.rc_max_quantizer = 255; cfg_.rc_end_usage = AOM_CBR; cfg_.g_lag_in_frames = 0;
diff --git a/test/test.cmake b/test/test.cmake index eb245cb..43a3deb 100644 --- a/test/test.cmake +++ b/test/test.cmake
@@ -220,6 +220,7 @@ "${AOM_ROOT}/test/pickrst_test.cc" "${AOM_ROOT}/test/quantize_func_test.cc" "${AOM_ROOT}/test/sad_test.cc" + "${AOM_ROOT}/test/stream_iter_test.cc" "${AOM_ROOT}/test/subtract_test.cc" "${AOM_ROOT}/test/reconinter_test.cc" "${AOM_ROOT}/test/sum_squares_test.cc"
diff --git a/test/tile_config_test.cc b/test/tile_config_test.cc index 8c92c14..0508331 100644 --- a/test/tile_config_test.cc +++ b/test/tile_config_test.cc
@@ -255,15 +255,12 @@ ASSERT_EQ(tile_config_violated_, false); } -AV1_INSTANTIATE_TEST_SUITE(UniformTileConfigTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(UniformTileConfigTestLarge, NONREALTIME_TEST_MODES, ::testing::ValuesIn(uniformTileConfigParams), ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ)); AV1_INSTANTIATE_TEST_SUITE(NonUniformTileConfigTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), + NONREALTIME_TEST_MODES, ::testing::ValuesIn(nonUniformTileConfigParams), ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ)); @@ -354,8 +351,6 @@ ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); } -AV1_INSTANTIATE_TEST_SUITE(TileGroupTestLarge, - ::testing::Values(::libaom_test::kOnePassGood, - ::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_SUITE(TileGroupTestLarge, NONREALTIME_TEST_MODES, ::testing::ValuesIn(tileGroupTestParams)); } // namespace
diff --git a/test/tile_independence_test.cc b/test/tile_independence_test.cc index 5f167be..559a2ce 100644 --- a/test/tile_independence_test.cc +++ b/test/tile_independence_test.cc
@@ -54,7 +54,11 @@ virtual void SetUp() { InitializeConfig(); +#if CONFIG_SINGLEPASS + SetMode(libaom_test::kOnePassGood); +#else SetMode(libaom_test::kTwoPassGood); +#endif // CONFIG_SINGLEPASS } virtual void PreEncodeFrameHook(libaom_test::VideoSource *video,
diff --git a/test/time_stamp_test.cc b/test/time_stamp_test.cc index 3e2fa97..3e91bee 100644 --- a/test/time_stamp_test.cc +++ b/test/time_stamp_test.cc
@@ -99,7 +99,12 @@ ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); } +#if CONFIG_SINGLEPASS +AV1_INSTANTIATE_TEST_SUITE(TimestampTest, + ::testing::Values(::libaom_test::kOnePassGood)); +#else AV1_INSTANTIATE_TEST_SUITE(TimestampTest, ::testing::Values(::libaom_test::kTwoPassGood)); +#endif // CONFIG_SINGLEPASS } // namespace
diff --git a/test/webmenc_test.cc b/test/webmenc_test.cc index acd795f..c028f22 100644 --- a/test/webmenc_test.cc +++ b/test/webmenc_test.cc
@@ -40,10 +40,10 @@ } TEST(WebmencTest, ExtractEncoderSettingsOutput3) { - const char *argv[] = { "aomenc", "--cq-level=63", "--end-usage=q", - "--output=foo", "baz" }; + const char *argv[] = { "aomenc", "--qp=255", "--end-usage=q", "--output=foo", + "baz" }; int argc = 5; - const std::string expected("version:23 --cq-level=63 --end-usage=q"); + const std::string expected("version:23 --qp=255 --end-usage=q"); char *result = extract_encoder_settings("23", argv, argc, "baz"); ASSERT_EQ(expected, std::string(result)); free(result);
diff --git a/third_party/tensorflow b/third_party/tensorflow new file mode 160000 index 0000000..18445b0 --- /dev/null +++ b/third_party/tensorflow
@@ -0,0 +1 @@ +Subproject commit 18445b0e39b677a21c86b4cf3d2bcb823f27e3e2
diff --git a/third_party/tensorflow_dependencies/absl b/third_party/tensorflow_dependencies/absl new file mode 160000 index 0000000..3c2bed2 --- /dev/null +++ b/third_party/tensorflow_dependencies/absl
@@ -0,0 +1 @@ +Subproject commit 3c2bed2e77a8b77ce3092e3f75140dd21879bdba
diff --git a/third_party/tensorflow_dependencies/build.pl b/third_party/tensorflow_dependencies/build.pl new file mode 100755 index 0000000..dcf14e5 --- /dev/null +++ b/third_party/tensorflow_dependencies/build.pl
@@ -0,0 +1,160 @@ +#!/usr/bin/env perl +# +# Copyright (c) 2020, Alliance for Open Media. All rights reserved +# +# This source code is subject to the terms of the BSD 2 Clause License and +# the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +# was not distributed with this source code in the LICENSE file, you can +# obtain it at www.aomedia.org/license/software. If the Alliance for Open +# Media Patent License 1.0 was not distributed with this source code in the +# PATENTS file, you can obtain it at www.aomedia.org/license/patent. +# +########################################################################### +# +# Script to build the static TensorFlow lite library. +# +# Tensorflow's build process generates the static libraries in the same +# directory as the source code. AOM, however, generates binaries/objects/etc. +# in a different directory. This script: +# +# 1.) Copies the TensorFlow code to a temporary directory +# 2.) Copies the necessary dependencies into the temporary directory +# 3.) Compiles it +# 4.) Copies the static library to the AOM build directory +# +# Note that we do not use the download_dependencies.sh script directly, as +# it downloads directly into the source directory. + +use strict; +use warnings; +use autodie; +use Cwd; +use File::Basename; +use File::Copy; +use File::Spec::Functions; +use File::Temp; + +# Apply a tweak to Eigen (TF Lite's "download_dependencies.sh" +# performs 3 tweaks, but only 1 of them is relevant). +sub apply_eigen_tweak { + my $downloads_dir = $_[0]; + my $file = catfile($downloads_dir, "eigen", "Eigen", "src", "Core", + "arch", "NEON", "Complex.h"); + open(my $fh, '<', $file); + my @lines = <$fh>; + close($fh); + open($fh, '>', $file); + foreach my $line (@lines) { + $line =~ s/static uint64x2_t p2ul_CONJ_XOR = vld1q_u64\( p2ul_conj_XOR_DATA \);/static uint64x2_t p2ul_CONJ_XOR;/; + print $fh $line; + } + close($fh); +} + +# Pure Perl implementation of recursive directory-copy - +# File::Copy::Recursive is not part of core. +sub recursive_dircopy { + my $input_dir = $_[0]; + my $output_dir = $_[1]; + # If the output directory does not exist, create it. + if (!(-d $output_dir)) { + mkdir $output_dir; + } + opendir(my $dh, $input_dir); + while (my $file = readdir($dh)) { + # Ignore . and .. entries. + next if ($file eq "." or $file eq ".."); + my $in_file = catfile($input_dir, $file); + my $out_file = catfile($output_dir, $file); + # If it is a directory, recursively call. + if (-d $in_file) { + recursive_dircopy($in_file, $out_file); + } else { + # If a file, copy over. + copy($in_file, $out_file); + # Preserve execute permission. + if (-x $in_file) { + chmod 0755, $out_file; + } + } + } + closedir($dh); +} + +# Finds the first instance of the file in the directory, using a depth-first +# search. Returns "" if unable to find. +sub find_file { + my $source_dir = $_[0]; + my $fname = $_[1]; + opendir(my $dh, $source_dir); + while (my $file = readdir($dh)) { + # Ignore . and .. entries. + next if ($file eq "." or $file eq ".."); + if (-d catfile($source_dir, $file)) { + my $result = find_file(catfile($source_dir, $file), $fname); + if ($result ne "") { + closedir($dh); + return $result; + } + } elsif ($file eq $fname) { + closedir($dh); + return catfile($source_dir, $file); + } + } + closedir($dh); + return ""; +} + +sub copy_tensorflow_lite_dependencies { + my $source_dir = $_[0]; + my $output_dir = $_[1]; + my $dependencies_dir = catfile($source_dir, "third_party", + "tensorflow_dependencies"); + opendir(my $dh, $dependencies_dir); + while (my $file = readdir($dh)) { + # Ignore . and .. entries. + next if ($file eq "." or $file eq ".."); + # Ignore non-directories. + next unless (-d catfile($dependencies_dir, $file)); + # Copy the directory. + print " * $file\n"; + recursive_dircopy( + catfile($dependencies_dir, $file), + catfile($output_dir, $file)); + } + closedir($dh); +} + +# Start of program logic. +if ($#ARGV + 1 != 2) { + my $prog = basename($0); + warn("Usage: $prog <source directory> <output directory>\n"); + exit(1); +} +my ($source_dir, $output_dir) = @ARGV; + +my $temp_dir = File::Temp::tempdir( CLEANUP => 1 ); + +print "Copying TensorFlow code to temporary directory for building...\n"; +my $tf_dir = catfile($source_dir, "third_party", "tensorflow"); +recursive_dircopy($tf_dir, $temp_dir); + +my $downloads_dir = catfile($temp_dir, "tensorflow", "lite", "tools", + "make", "downloads"); +mkdir $downloads_dir; +print "Copying TensorFlow Lite dependencies to temporary directory...\n"; +copy_tensorflow_lite_dependencies($source_dir, $downloads_dir); +apply_eigen_tweak($downloads_dir); + +print "Building TensorFlow Lite...\n"; +my $build_sh = catfile($temp_dir, "tensorflow", "lite", "tools", "make", + "build_lib.sh"); +`$build_sh`; +# Find the libtensorflow-lite.a file, which is generated under +# tensorflow/lite/tools/make/gen (but in a different sub-directory depending +# on the architecture). +my $gen_dir = catfile($temp_dir, "tensorflow", "lite", "tools", "make", "gen"); +my $liblite = find_file($gen_dir, "libtensorflow-lite.a"); +$liblite ne "" or die("Unable to find libtensorflow-lite.a"); +print "Copying static library into build directory...\n"; +copy($liblite, $output_dir);
diff --git a/third_party/tensorflow_dependencies/eigen b/third_party/tensorflow_dependencies/eigen new file mode 160000 index 0000000..b11f817 --- /dev/null +++ b/third_party/tensorflow_dependencies/eigen
@@ -0,0 +1 @@ +Subproject commit b11f817bcff04276f3024d6780f56a137968b81a
diff --git a/third_party/tensorflow_dependencies/farmhash b/third_party/tensorflow_dependencies/farmhash new file mode 160000 index 0000000..0d859a8 --- /dev/null +++ b/third_party/tensorflow_dependencies/farmhash
@@ -0,0 +1 @@ +Subproject commit 0d859a811870d10f53a594927d0d0b97573ad06d
diff --git a/third_party/tensorflow_dependencies/fft2d/alloc.c b/third_party/tensorflow_dependencies/fft2d/alloc.c new file mode 100644 index 0000000..7833d88 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/alloc.c
@@ -0,0 +1,153 @@ +/* ---- memory allocation ---- */ +#include "alloc.h" + + +#define alloc_error_check(p) { \ + if ((p) == NULL) { \ + fprintf(stderr, "Allocation Failure!\n"); \ + exit(1); \ + } \ +} + + +int *alloc_1d_int(int n1) +{ + int *i; + + i = (int *) malloc(sizeof(int) * n1); + alloc_error_check(i); + return i; +} + + +void free_1d_int(int *i) +{ + free(i); +} + + +double *alloc_1d_double(int n1) +{ + double *d; + + d = (double *) malloc(sizeof(double) * n1); + alloc_error_check(d); + return d; +} + + +void free_1d_double(double *d) +{ + free(d); +} + + +int **alloc_2d_int(int n1, int n2) +{ + int **ii, *i; + int j; + + ii = (int **) malloc(sizeof(int *) * n1); + alloc_error_check(ii); + i = (int *) malloc(sizeof(int) * n1 * n2); + alloc_error_check(i); + ii[0] = i; + for (j = 1; j < n1; j++) { + ii[j] = ii[j - 1] + n2; + } + return ii; +} + + +void free_2d_int(int **ii) +{ + free(ii[0]); + free(ii); +} + + +double **alloc_2d_double(int n1, int n2) +{ + double **dd, *d; + int j; + + dd = (double **) malloc(sizeof(double *) * n1); + alloc_error_check(dd); + d = (double *) malloc(sizeof(double) * n1 * n2); + alloc_error_check(d); + dd[0] = d; + for (j = 1; j < n1; j++) { + dd[j] = dd[j - 1] + n2; + } + return dd; +} + + +void free_2d_double(double **dd) +{ + free(dd[0]); + free(dd); +} + + +int ***alloc_3d_int(int n1, int n2, int n3) +{ + int ***iii, **ii, *i; + int j; + + iii = (int ***) malloc(sizeof(int **) * n1); + alloc_error_check(iii); + ii = (int **) malloc(sizeof(int *) * n1 * n2); + alloc_error_check(ii); + iii[0] = ii; + for (j = 1; j < n1; j++) { + iii[j] = iii[j - 1] + n2; + } + i = (int *) malloc(sizeof(int) * n1 * n2 * n3); + alloc_error_check(i); + ii[0] = i; + for (j = 1; j < n1 * n2; j++) { + ii[j] = ii[j - 1] + n3; + } + return iii; +} + + +void free_3d_int(int ***iii) +{ + free(iii[0][0]); + free(iii[0]); + free(iii); +} + + +double ***alloc_3d_double(int n1, int n2, int n3) +{ + double ***ddd, **dd, *d; + int j; + + ddd = (double ***) malloc(sizeof(double **) * n1); + alloc_error_check(ddd); + dd = (double **) malloc(sizeof(double *) * n1 * n2); + alloc_error_check(dd); + ddd[0] = dd; + for (j = 1; j < n1; j++) { + ddd[j] = ddd[j - 1] + n2; + } + d = (double *) malloc(sizeof(double) * n1 * n2 * n3); + alloc_error_check(d); + dd[0] = d; + for (j = 1; j < n1 * n2; j++) { + dd[j] = dd[j - 1] + n3; + } + return ddd; +} + + +void free_3d_double(double ***ddd) +{ + free(ddd[0][0]); + free(ddd[0]); + free(ddd); +} +
diff --git a/third_party/tensorflow_dependencies/fft2d/alloc.h b/third_party/tensorflow_dependencies/fft2d/alloc.h new file mode 100644 index 0000000..3467cc4 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/alloc.h
@@ -0,0 +1,20 @@ +/* ---- memory allocation ---- */ + + +#include <stdlib.h> +#include <stdio.h> + + +int *alloc_1d_int(int n1); +void free_1d_int(int *i); +double *alloc_1d_double(int n1); +void free_1d_double(double *d); +int **alloc_2d_int(int n1, int n2); +void free_2d_int(int **ii); +double **alloc_2d_double(int n1, int n2); +void free_2d_double(double **dd); +int ***alloc_3d_int(int n1, int n2, int n3); +void free_3d_int(int ***iii); +double ***alloc_3d_double(int n1, int n2, int n3); +void free_3d_double(double ***ddd); +
diff --git a/third_party/tensorflow_dependencies/fft2d/fft4f2d.c b/third_party/tensorflow_dependencies/fft2d/fft4f2d.c new file mode 100644 index 0000000..354c80e --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/fft4f2d.c
@@ -0,0 +1,1705 @@ +/* +Fast Fourier/Cosine/Sine Transform + dimension :two + data length :power of 2 + decimation :frequency + radix :4, 2, row-column + data :inplace + table :use +functions + cdft2d: Complex Discrete Fourier Transform + rdft2d: Real Discrete Fourier Transform + ddct2d: Discrete Cosine Transform + ddst2d: Discrete Sine Transform +function prototypes + void cdft2d(int, int, int, double **, int *, double *); + void rdft2d(int, int, int, double **, int *, double *); + void ddct2d(int, int, int, double **, double **, int *, double *); + void ddst2d(int, int, int, double **, double **, int *, double *); + + +-------- Complex DFT (Discrete Fourier Transform) -------- + [definition] + <case1> + X[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 x[j1][j2] * + exp(2*pi*i*j1*k1/n1) * + exp(2*pi*i*j2*k2/n2), 0<=k1<n1, 0<=k2<n2 + <case2> + X[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 x[j1][j2] * + exp(-2*pi*i*j1*k1/n1) * + exp(-2*pi*i*j2*k2/n2), 0<=k1<n1, 0<=k2<n2 + (notes: sum_j=0^n-1 is a summation from j=0 to n-1) + [usage] + <case1> + ip[0] = 0; // first time only + cdft2d(n1, 2*n2, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + cdft2d(n1, 2*n2, -1, a, ip, w); + [parameters] + n1 :data length (int) + n1 >= 1, n1 = power of 2 + 2*n2 :data length (int) + n2 >= 1, n2 = power of 2 + a[0...n1-1][0...2*n2-1] + :input/output data (double **) + input data + a[j1][2*j2] = Re(x[j1][j2]), + a[j1][2*j2+1] = Im(x[j1][j2]), + 0<=j1<n1, 0<=j2<n2 + output data + a[k1][2*k2] = Re(X[k1][k2]), + a[k1][2*k2+1] = Im(X[k1][k2]), + 0<=k1<n1, 0<=k2<n2 + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1, n2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1/2, n2/2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + cdft2d(n1, 2*n2, -1, a, ip, w); + is + cdft2d(n1, 2*n2, 1, a, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= 2 * n2 - 1; j2++) { + a[j1][j2] *= 1.0 / (n1 * n2); + } + } + . + + +-------- Real DFT / Inverse of Real DFT -------- + [definition] + <case1> RDFT + R[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2), + 0<=k1<n1, 0<=k2<n2 + I[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2), + 0<=k1<n1, 0<=k2<n2 + <case2> IRDFT (excluding scale) + a[k1][k2] = (1/2) * sum_j1=0^n1-1 sum_j2=0^n2-1 + (R[j1][j2] * + cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2) + + I[j1][j2] * + sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2)), + 0<=k1<n1, 0<=k2<n2 + (notes: R[n1-k1][n2-k2] = R[k1][k2], + I[n1-k1][n2-k2] = -I[k1][k2], + R[n1-k1][0] = R[k1][0], + I[n1-k1][0] = -I[k1][0], + R[0][n2-k2] = R[0][k2], + I[0][n2-k2] = -I[0][k2], + 0<k1<n1, 0<k2<n2) + [usage] + <case1> + ip[0] = 0; // first time only + rdft2d(n1, n2, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + rdft2d(n1, n2, -1, a, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + a[0...n1-1][0...n2-1] + :input/output data (double **) + <case1> + output data + a[k1][2*k2] = R[k1][k2] = R[n1-k1][n2-k2], + a[k1][2*k2+1] = I[k1][k2] = -I[n1-k1][n2-k2], + 0<k1<n1, 0<k2<n2/2, + a[0][2*k2] = R[0][k2] = R[0][n2-k2], + a[0][2*k2+1] = I[0][k2] = -I[0][n2-k2], + 0<k2<n2/2, + a[k1][0] = R[k1][0] = R[n1-k1][0], + a[k1][1] = I[k1][0] = -I[n1-k1][0], + a[n1-k1][1] = R[k1][n2/2] = R[n1-k1][n2/2], + a[n1-k1][0] = -I[k1][n2/2] = I[n1-k1][n2/2], + 0<k1<n1/2, + a[0][0] = R[0][0], + a[0][1] = R[0][n2/2], + a[n1/2][0] = R[n1/2][0], + a[n1/2][1] = R[n1/2][n2/2] + <case2> + input data + a[j1][2*j2] = R[j1][j2] = R[n1-j1][n2-j2], + a[j1][2*j2+1] = I[j1][j2] = -I[n1-j1][n2-j2], + 0<j1<n1, 0<j2<n2/2, + a[0][2*j2] = R[0][j2] = R[0][n2-j2], + a[0][2*j2+1] = I[0][j2] = -I[0][n2-j2], + 0<j2<n2/2, + a[j1][0] = R[j1][0] = R[n1-j1][0], + a[j1][1] = I[j1][0] = -I[n1-j1][0], + a[n1-j1][1] = R[j1][n2/2] = R[n1-j1][n2/2], + a[n1-j1][0] = -I[j1][n2/2] = I[n1-j1][n2/2], + 0<j1<n1/2, + a[0][0] = R[0][0], + a[0][1] = R[0][n2/2], + a[n1/2][0] = R[n1/2][0], + a[n1/2][1] = R[n1/2][n2/2] + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1, n2/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1/2, n2/4) + n2/4 + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + rdft2d(n1, n2, 1, a, ip, w); + is + rdft2d(n1, n2, -1, a, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] *= 2.0 / (n1 * n2); + } + } + . + + +-------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + <case1> IDCT (excluding scale) + C[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + cos(pi*j1*(k1+1/2)/n1) * + cos(pi*j2*(k2+1/2)/n2), + 0<=k1<n1, 0<=k2<n2 + <case2> DCT + C[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + cos(pi*(j1+1/2)*k1/n1) * + cos(pi*(j2+1/2)*k2/n2), + 0<=k1<n1, 0<=k2<n2 + [usage] + <case1> + ip[0] = 0; // first time only + ddct2d(n1, n2, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + ddct2d(n1, n2, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + a[0...n1-1][0...n2-1] + :input/output data (double **) + output data + a[k1][k2] = C[k1][k2], 0<=k1<n1, 0<=k2<n2 + t[0...n1-1][0...n2-1] + :work area (double **) + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1, n2/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1/2, n2/4) + max(n1, n2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddct2d(n1, n2, -1, a, t, ip, w); + is + for (j1 = 0; j1 <= n1 - 1; j1++) { + a[j1][0] *= 0.5; + } + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[0][j2] *= 0.5; + } + ddct2d(n1, n2, 1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] *= 4.0 / (n1 * n2); + } + } + . + + +-------- DST (Discrete Sine Transform) / Inverse of DST -------- + [definition] + <case1> IDST (excluding scale) + S[k1][k2] = sum_j1=1^n1 sum_j2=1^n2 A[j1][j2] * + sin(pi*j1*(k1+1/2)/n1) * + sin(pi*j2*(k2+1/2)/n2), + 0<=k1<n1, 0<=k2<n2 + <case2> DST + S[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + sin(pi*(j1+1/2)*k1/n1) * + sin(pi*(j2+1/2)*k2/n2), + 0<k1<=n1, 0<k2<=n2 + [usage] + <case1> + ip[0] = 0; // first time only + ddst2d(n1, n2, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + ddst2d(n1, n2, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + a[0...n1-1][0...n2-1] + :input/output data (double **) + <case1> + input data + a[j1][j2] = A[j1][j2], 0<j1<n1, 0<j2<n2, + a[j1][0] = A[j1][n2], 0<j1<n1, + a[0][j2] = A[n1][j2], 0<j2<n2, + a[0][0] = A[n1][n2] + (i.e. A[j1][j2] = a[j1 % n1][j2 % n2]) + output data + a[k1][k2] = S[k1][k2], 0<=k1<n1, 0<=k2<n2 + <case2> + output data + a[k1][k2] = S[k1][k2], 0<k1<n1, 0<k2<n2, + a[k1][0] = S[k1][n2], 0<k1<n1, + a[0][k2] = S[n1][k2], 0<k2<n2, + a[0][0] = S[n1][n2] + (i.e. S[k1][k2] = a[k1 % n1][k2 % n2]) + t[0...n1-1][0...n2-1] + :work area (double **) + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1, n2/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1/2, n2/4) + max(n1, n2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddst2d(n1, n2, -1, a, t, ip, w); + is + for (j1 = 0; j1 <= n1 - 1; j1++) { + a[j1][0] *= 0.5; + } + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[0][j2] *= 0.5; + } + ddst2d(n1, n2, 1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] *= 4.0 / (n1 * n2); + } + } + . +*/ + + +void cdft2d(int n1, int n2, int isgn, double **a, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void bitrv2col(int n1, int n, int *ip, double **a); + void bitrv2row(int n, int n2, int *ip, double **a); + void cftbcol(int n1, int n, double **a, double *w); + void cftbrow(int n, int n2, double **a, double *w); + void cftfcol(int n1, int n, double **a, double *w); + void cftfrow(int n, int n2, double **a, double *w); + int n; + + n = n1 << 1; + if (n < n2) { + n = n2; + } + if (n > (ip[0] << 2)) { + makewt(n >> 2, ip, w); + } + if (n2 > 4) { + bitrv2col(n1, n2, ip + 2, a); + } + if (n1 > 2) { + bitrv2row(n1, n2, ip + 2, a); + } + if (isgn < 0) { + cftfcol(n1, n2, a, w); + cftfrow(n1, n2, a, w); + } else { + cftbcol(n1, n2, a, w); + cftbrow(n1, n2, a, w); + } +} + + +void rdft2d(int n1, int n2, int isgn, double **a, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void bitrv2col(int n1, int n, int *ip, double **a); + void bitrv2row(int n, int n2, int *ip, double **a); + void cftbcol(int n1, int n, double **a, double *w); + void cftbrow(int n, int n2, double **a, double *w); + void cftfcol(int n1, int n, double **a, double *w); + void cftfrow(int n, int n2, double **a, double *w); + void rftbcol(int n1, int n, double **a, int nc, double *c); + void rftfcol(int n1, int n, double **a, int nc, double *c); + int n, nw, nc, n1h, i, j; + double xi; + + n = n1 << 1; + if (n < n2) { + n = n2; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n2 > (nc << 2)) { + nc = n2 >> 2; + makect(nc, ip, w + nw); + } + n1h = n1 >> 1; + if (isgn < 0) { + for (i = 1; i <= n1h - 1; i++) { + j = n1 - i; + xi = a[i][0] - a[j][0]; + a[i][0] += a[j][0]; + a[j][0] = xi; + xi = a[j][1] - a[i][1]; + a[i][1] += a[j][1]; + a[j][1] = xi; + } + if (n1 > 2) { + bitrv2row(n1, n2, ip + 2, a); + } + cftfrow(n1, n2, a, w); + for (i = 0; i <= n1 - 1; i++) { + a[i][1] = 0.5 * (a[i][0] - a[i][1]); + a[i][0] -= a[i][1]; + } + if (n2 > 4) { + rftfcol(n1, n2, a, nc, w + nw); + bitrv2col(n1, n2, ip + 2, a); + } + cftfcol(n1, n2, a, w); + } else { + if (n2 > 4) { + bitrv2col(n1, n2, ip + 2, a); + } + cftbcol(n1, n2, a, w); + if (n2 > 4) { + rftbcol(n1, n2, a, nc, w + nw); + } + for (i = 0; i <= n1 - 1; i++) { + xi = a[i][0] - a[i][1]; + a[i][0] += a[i][1]; + a[i][1] = xi; + } + if (n1 > 2) { + bitrv2row(n1, n2, ip + 2, a); + } + cftbrow(n1, n2, a, w); + for (i = 1; i <= n1h - 1; i++) { + j = n1 - i; + a[j][0] = 0.5 * (a[i][0] - a[j][0]); + a[i][0] -= a[j][0]; + a[j][1] = 0.5 * (a[i][1] + a[j][1]); + a[i][1] -= a[j][1]; + } + } +} + + +void ddct2d(int n1, int n2, int isgn, double **a, double **t, + int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void bitrv2col(int n1, int n, int *ip, double **a); + void bitrv2row(int n, int n2, int *ip, double **a); + void cftbcol(int n1, int n, double **a, double *w); + void cftbrow(int n, int n2, double **a, double *w); + void cftfcol(int n1, int n, double **a, double *w); + void cftfrow(int n, int n2, double **a, double *w); + void rftbcol(int n1, int n, double **a, int nc, double *c); + void rftfcol(int n1, int n, double **a, int nc, double *c); + void dctbsub(int n1, int n2, double **a, int nc, double *c); + void dctfsub(int n1, int n2, double **a, int nc, double *c); + int n, nw, nc, n1h, n2h, i, ix, ic, j, jx, jc; + double xi; + + n = n1 << 1; + if (n < n2) { + n = n2; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n1 > nc || n2 > nc) { + if (n1 > n2) { + nc = n1; + } else { + nc = n2; + } + makect(nc, ip, w + nw); + } + n1h = n1 >> 1; + n2h = n2 >> 1; + if (isgn >= 0) { + for (i = 0; i <= n1 - 1; i++) { + for (j = 1; j <= n2h - 1; j++) { + jx = j << 1; + t[i][jx] = a[i][j]; + t[i][jx + 1] = a[i][n2 - j]; + } + } + t[0][0] = a[0][0]; + t[0][1] = a[0][n2h]; + t[n1h][0] = a[n1h][0]; + t[n1h][1] = a[n1h][n2h]; + for (i = 1; i <= n1h - 1; i++) { + ic = n1 - i; + t[i][0] = a[i][0]; + t[ic][1] = a[i][n2h]; + t[i][1] = a[ic][0]; + t[ic][0] = a[ic][n2h]; + } + dctfsub(n1, n2, t, nc, w + nw); + if (n1 > 2) { + bitrv2row(n1, n2, ip + 2, t); + } + cftfrow(n1, n2, t, w); + for (i = 0; i <= n1 - 1; i++) { + t[i][1] = 0.5 * (t[i][0] - t[i][1]); + t[i][0] -= t[i][1]; + } + if (n2 > 4) { + rftfcol(n1, n2, t, nc, w + nw); + bitrv2col(n1, n2, ip + 2, t); + } + cftfcol(n1, n2, t, w); + for (i = 0; i <= n1h - 1; i++) { + ix = i << 1; + ic = n1 - 1 - i; + for (j = 0; j <= n2h - 1; j++) { + jx = j << 1; + jc = n2 - 1 - j; + a[ix][jx] = t[i][j]; + a[ix][jx + 1] = t[i][jc]; + a[ix + 1][jx] = t[ic][j]; + a[ix + 1][jx + 1] = t[ic][jc]; + } + } + } else { + for (i = 0; i <= n1h - 1; i++) { + ix = i << 1; + ic = n1 - 1 - i; + for (j = 0; j <= n2h - 1; j++) { + jx = j << 1; + jc = n2 - 1 - j; + t[i][j] = a[ix][jx]; + t[i][jc] = a[ix][jx + 1]; + t[ic][j] = a[ix + 1][jx]; + t[ic][jc] = a[ix + 1][jx + 1]; + } + } + if (n2 > 4) { + bitrv2col(n1, n2, ip + 2, t); + } + cftbcol(n1, n2, t, w); + if (n2 > 4) { + rftbcol(n1, n2, t, nc, w + nw); + } + for (i = 0; i <= n1 - 1; i++) { + xi = t[i][0] - t[i][1]; + t[i][0] += t[i][1]; + t[i][1] = xi; + } + if (n1 > 2) { + bitrv2row(n1, n2, ip + 2, t); + } + cftbrow(n1, n2, t, w); + dctbsub(n1, n2, t, nc, w + nw); + for (i = 0; i <= n1 - 1; i++) { + for (j = 1; j <= n2h - 1; j++) { + jx = j << 1; + a[i][j] = t[i][jx]; + a[i][n2 - j] = t[i][jx + 1]; + } + } + a[0][0] = t[0][0]; + a[0][n2h] = t[0][1]; + a[n1h][0] = t[n1h][0]; + a[n1h][n2h] = t[n1h][1]; + for (i = 1; i <= n1h - 1; i++) { + ic = n1 - i; + a[i][0] = t[i][0]; + a[i][n2h] = t[ic][1]; + a[ic][0] = t[i][1]; + a[ic][n2h] = t[ic][0]; + } + } +} + + +void ddst2d(int n1, int n2, int isgn, double **a, double **t, + int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void bitrv2col(int n1, int n, int *ip, double **a); + void bitrv2row(int n, int n2, int *ip, double **a); + void cftbcol(int n1, int n, double **a, double *w); + void cftbrow(int n, int n2, double **a, double *w); + void cftfcol(int n1, int n, double **a, double *w); + void cftfrow(int n, int n2, double **a, double *w); + void rftbcol(int n1, int n, double **a, int nc, double *c); + void rftfcol(int n1, int n, double **a, int nc, double *c); + void dstbsub(int n1, int n2, double **a, int nc, double *c); + void dstfsub(int n1, int n2, double **a, int nc, double *c); + int n, nw, nc, n1h, n2h, i, ix, ic, j, jx, jc; + double xi; + + n = n1 << 1; + if (n < n2) { + n = n2; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n1 > nc || n2 > nc) { + if (n1 > n2) { + nc = n1; + } else { + nc = n2; + } + makect(nc, ip, w + nw); + } + n1h = n1 >> 1; + n2h = n2 >> 1; + if (isgn >= 0) { + for (i = 0; i <= n1 - 1; i++) { + for (j = 1; j <= n2h - 1; j++) { + jx = j << 1; + t[i][jx] = a[i][j]; + t[i][jx + 1] = a[i][n2 - j]; + } + } + t[0][0] = a[0][0]; + t[0][1] = a[0][n2h]; + t[n1h][0] = a[n1h][0]; + t[n1h][1] = a[n1h][n2h]; + for (i = 1; i <= n1h - 1; i++) { + ic = n1 - i; + t[i][0] = a[i][0]; + t[ic][1] = a[i][n2h]; + t[i][1] = a[ic][0]; + t[ic][0] = a[ic][n2h]; + } + dstfsub(n1, n2, t, nc, w + nw); + if (n1 > 2) { + bitrv2row(n1, n2, ip + 2, t); + } + cftfrow(n1, n2, t, w); + for (i = 0; i <= n1 - 1; i++) { + t[i][1] = 0.5 * (t[i][0] - t[i][1]); + t[i][0] -= t[i][1]; + } + if (n2 > 4) { + rftfcol(n1, n2, t, nc, w + nw); + bitrv2col(n1, n2, ip + 2, t); + } + cftfcol(n1, n2, t, w); + for (i = 0; i <= n1h - 1; i++) { + ix = i << 1; + ic = n1 - 1 - i; + for (j = 0; j <= n2h - 1; j++) { + jx = j << 1; + jc = n2 - 1 - j; + a[ix][jx] = t[i][j]; + a[ix][jx + 1] = -t[i][jc]; + a[ix + 1][jx] = -t[ic][j]; + a[ix + 1][jx + 1] = t[ic][jc]; + } + } + } else { + for (i = 0; i <= n1h - 1; i++) { + ix = i << 1; + ic = n1 - 1 - i; + for (j = 0; j <= n2h - 1; j++) { + jx = j << 1; + jc = n2 - 1 - j; + t[i][j] = a[ix][jx]; + t[i][jc] = -a[ix][jx + 1]; + t[ic][j] = -a[ix + 1][jx]; + t[ic][jc] = a[ix + 1][jx + 1]; + } + } + if (n2 > 4) { + bitrv2col(n1, n2, ip + 2, t); + } + cftbcol(n1, n2, t, w); + if (n2 > 4) { + rftbcol(n1, n2, t, nc, w + nw); + } + for (i = 0; i <= n1 - 1; i++) { + xi = t[i][0] - t[i][1]; + t[i][0] += t[i][1]; + t[i][1] = xi; + } + if (n1 > 2) { + bitrv2row(n1, n2, ip + 2, t); + } + cftbrow(n1, n2, t, w); + dstbsub(n1, n2, t, nc, w + nw); + for (i = 0; i <= n1 - 1; i++) { + for (j = 1; j <= n2h - 1; j++) { + jx = j << 1; + a[i][j] = t[i][jx]; + a[i][n2 - j] = t[i][jx + 1]; + } + } + a[0][0] = t[0][0]; + a[0][n2h] = t[0][1]; + a[n1h][0] = t[n1h][0]; + a[n1h][n2h] = t[n1h][1]; + for (i = 1; i <= n1h - 1; i++) { + ic = n1 - i; + a[i][0] = t[i][0]; + a[i][n2h] = t[ic][1]; + a[ic][0] = t[i][1]; + a[ic][n2h] = t[ic][0]; + } + } +} + + +/* -------- initializing routines -------- */ + + +#include <math.h> + +void makewt(int nw, int *ip, double *w) +{ + void bitrv2(int n, int *ip, double *a); + int nwh, j; + double delta, x, y; + + ip[0] = nw; + ip[1] = 1; + if (nw > 2) { + nwh = nw >> 1; + delta = atan(1.0) / nwh; + w[0] = 1; + w[1] = 0; + w[nwh] = cos(delta * nwh); + w[nwh + 1] = w[nwh]; + for (j = 2; j <= nwh - 2; j += 2) { + x = cos(delta * j); + y = sin(delta * j); + w[j] = x; + w[j + 1] = y; + w[nw - j] = y; + w[nw - j + 1] = x; + } + bitrv2(nw, ip + 2, w); + } +} + + +void makect(int nc, int *ip, double *c) +{ + int nch, j; + double delta; + + ip[1] = nc; + if (nc > 1) { + nch = nc >> 1; + delta = atan(1.0) / nch; + c[0] = 0.5; + c[nch] = 0.5 * cos(delta * nch); + for (j = 1; j <= nch - 1; j++) { + c[j] = 0.5 * cos(delta * j); + c[nc - j] = 0.5 * sin(delta * j); + } + } +} + + +/* -------- child routines -------- */ + + +void bitrv2(int n, int *ip, double *a) +{ + int j, j1, k, k1, l, m, m2; + double xr, xi; + + ip[0] = 0; + l = n; + m = 1; + while ((m << 2) < l) { + l >>= 1; + for (j = 0; j <= m - 1; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + if ((m << 2) > l) { + for (k = 1; k <= m - 1; k++) { + for (j = 0; j <= k - 1; j++) { + j1 = (j << 1) + ip[k]; + k1 = (k << 1) + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + a[j1] = a[k1]; + a[j1 + 1] = a[k1 + 1]; + a[k1] = xr; + a[k1 + 1] = xi; + } + } + } else { + m2 = m << 1; + for (k = 1; k <= m - 1; k++) { + for (j = 0; j <= k - 1; j++) { + j1 = (j << 1) + ip[k]; + k1 = (k << 1) + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + a[j1] = a[k1]; + a[j1 + 1] = a[k1 + 1]; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + a[j1] = a[k1]; + a[j1 + 1] = a[k1 + 1]; + a[k1] = xr; + a[k1 + 1] = xi; + } + } + } +} + + +void bitrv2col(int n1, int n, int *ip, double **a) +{ + int i, j, j1, k, k1, l, m, m2; + double xr, xi; + + ip[0] = 0; + l = n; + m = 1; + while ((m << 2) < l) { + l >>= 1; + for (j = 0; j <= m - 1; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + if ((m << 2) > l) { + for (i = 0; i <= n1 - 1; i++) { + for (k = 1; k <= m - 1; k++) { + for (j = 0; j <= k - 1; j++) { + j1 = (j << 1) + ip[k]; + k1 = (k << 1) + ip[j]; + xr = a[i][j1]; + xi = a[i][j1 + 1]; + a[i][j1] = a[i][k1]; + a[i][j1 + 1] = a[i][k1 + 1]; + a[i][k1] = xr; + a[i][k1 + 1] = xi; + } + } + } + } else { + m2 = m << 1; + for (i = 0; i <= n1 - 1; i++) { + for (k = 1; k <= m - 1; k++) { + for (j = 0; j <= k - 1; j++) { + j1 = (j << 1) + ip[k]; + k1 = (k << 1) + ip[j]; + xr = a[i][j1]; + xi = a[i][j1 + 1]; + a[i][j1] = a[i][k1]; + a[i][j1 + 1] = a[i][k1 + 1]; + a[i][k1] = xr; + a[i][k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[i][j1]; + xi = a[i][j1 + 1]; + a[i][j1] = a[i][k1]; + a[i][j1 + 1] = a[i][k1 + 1]; + a[i][k1] = xr; + a[i][k1 + 1] = xi; + } + } + } + } +} + + +void bitrv2row(int n, int n2, int *ip, double **a) +{ + int i, j, j1, k, k1, l, m; + double xr, xi; + + ip[0] = 0; + l = n; + m = 1; + while ((m << 1) < l) { + l >>= 1; + for (j = 0; j <= m - 1; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + if ((m << 1) > l) { + for (k = 1; k <= m - 1; k++) { + for (j = 0; j <= k - 1; j++) { + j1 = j + ip[k]; + k1 = k + ip[j]; + for (i = 0; i <= n2 - 2; i += 2) { + xr = a[j1][i]; + xi = a[j1][i + 1]; + a[j1][i] = a[k1][i]; + a[j1][i + 1] = a[k1][i + 1]; + a[k1][i] = xr; + a[k1][i + 1] = xi; + } + } + } + } else { + for (k = 1; k <= m - 1; k++) { + for (j = 0; j <= k - 1; j++) { + j1 = j + ip[k]; + k1 = k + ip[j]; + for (i = 0; i <= n2 - 2; i += 2) { + xr = a[j1][i]; + xi = a[j1][i + 1]; + a[j1][i] = a[k1][i]; + a[j1][i + 1] = a[k1][i + 1]; + a[k1][i] = xr; + a[k1][i + 1] = xi; + } + j1 += m; + k1 += m; + for (i = 0; i <= n2 - 2; i += 2) { + xr = a[j1][i]; + xi = a[j1][i + 1]; + a[j1][i] = a[k1][i]; + a[j1][i + 1] = a[k1][i + 1]; + a[k1][i] = xr; + a[k1][i + 1] = xi; + } + } + } + } +} + + +void cftbcol(int n1, int n, double **a, double *w) +{ + int i, j, j1, j2, j3, k, k1, ks, l, m; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + for (i = 0; i <= n1 - 1; i++) { + l = 2; + while ((l << 1) < n) { + m = l << 2; + for (j = 0; j <= l - 2; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[i][j] + a[i][j1]; + x0i = a[i][j + 1] + a[i][j1 + 1]; + x1r = a[i][j] - a[i][j1]; + x1i = a[i][j + 1] - a[i][j1 + 1]; + x2r = a[i][j2] + a[i][j3]; + x2i = a[i][j2 + 1] + a[i][j3 + 1]; + x3r = a[i][j2] - a[i][j3]; + x3i = a[i][j2 + 1] - a[i][j3 + 1]; + a[i][j] = x0r + x2r; + a[i][j + 1] = x0i + x2i; + a[i][j2] = x0r - x2r; + a[i][j2 + 1] = x0i - x2i; + a[i][j1] = x1r - x3i; + a[i][j1 + 1] = x1i + x3r; + a[i][j3] = x1r + x3i; + a[i][j3 + 1] = x1i - x3r; + } + if (m < n) { + wk1r = w[2]; + for (j = m; j <= l + m - 2; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[i][j] + a[i][j1]; + x0i = a[i][j + 1] + a[i][j1 + 1]; + x1r = a[i][j] - a[i][j1]; + x1i = a[i][j + 1] - a[i][j1 + 1]; + x2r = a[i][j2] + a[i][j3]; + x2i = a[i][j2 + 1] + a[i][j3 + 1]; + x3r = a[i][j2] - a[i][j3]; + x3i = a[i][j2 + 1] - a[i][j3 + 1]; + a[i][j] = x0r + x2r; + a[i][j + 1] = x0i + x2i; + a[i][j2] = x2i - x0i; + a[i][j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[i][j1] = wk1r * (x0r - x0i); + a[i][j1 + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[i][j3] = wk1r * (x0i - x0r); + a[i][j3 + 1] = wk1r * (x0i + x0r); + } + k1 = 1; + ks = -1; + for (k = (m << 1); k <= n - m; k += m) { + k1++; + ks = -ks; + wk1r = w[k1 << 1]; + wk1i = w[(k1 << 1) + 1]; + wk2r = ks * w[k1]; + wk2i = w[k1 + ks]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j <= l + k - 2; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[i][j] + a[i][j1]; + x0i = a[i][j + 1] + a[i][j1 + 1]; + x1r = a[i][j] - a[i][j1]; + x1i = a[i][j + 1] - a[i][j1 + 1]; + x2r = a[i][j2] + a[i][j3]; + x2i = a[i][j2 + 1] + a[i][j3 + 1]; + x3r = a[i][j2] - a[i][j3]; + x3i = a[i][j2 + 1] - a[i][j3 + 1]; + a[i][j] = x0r + x2r; + a[i][j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[i][j2] = wk2r * x0r - wk2i * x0i; + a[i][j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[i][j1] = wk1r * x0r - wk1i * x0i; + a[i][j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[i][j3] = wk3r * x0r - wk3i * x0i; + a[i][j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } + } + l = m; + } + if (l < n) { + for (j = 0; j <= l - 2; j += 2) { + j1 = j + l; + x0r = a[i][j] - a[i][j1]; + x0i = a[i][j + 1] - a[i][j1 + 1]; + a[i][j] += a[i][j1]; + a[i][j + 1] += a[i][j1 + 1]; + a[i][j1] = x0r; + a[i][j1 + 1] = x0i; + } + } + } +} + + +void cftbrow(int n, int n2, double **a, double *w) +{ + int i, j, j1, j2, j3, k, k1, ks, l, m; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 1; + while ((l << 1) < n) { + m = l << 2; + for (j = 0; j <= l - 1; j++) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + for (i = 0; i <= n2 - 2; i += 2) { + x0r = a[j][i] + a[j1][i]; + x0i = a[j][i + 1] + a[j1][i + 1]; + x1r = a[j][i] - a[j1][i]; + x1i = a[j][i + 1] - a[j1][i + 1]; + x2r = a[j2][i] + a[j3][i]; + x2i = a[j2][i + 1] + a[j3][i + 1]; + x3r = a[j2][i] - a[j3][i]; + x3i = a[j2][i + 1] - a[j3][i + 1]; + a[j][i] = x0r + x2r; + a[j][i + 1] = x0i + x2i; + a[j2][i] = x0r - x2r; + a[j2][i + 1] = x0i - x2i; + a[j1][i] = x1r - x3i; + a[j1][i + 1] = x1i + x3r; + a[j3][i] = x1r + x3i; + a[j3][i + 1] = x1i - x3r; + } + } + if (m < n) { + wk1r = w[2]; + for (j = m; j <= l + m - 1; j++) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + for (i = 0; i <= n2 - 2; i += 2) { + x0r = a[j][i] + a[j1][i]; + x0i = a[j][i + 1] + a[j1][i + 1]; + x1r = a[j][i] - a[j1][i]; + x1i = a[j][i + 1] - a[j1][i + 1]; + x2r = a[j2][i] + a[j3][i]; + x2i = a[j2][i + 1] + a[j3][i + 1]; + x3r = a[j2][i] - a[j3][i]; + x3i = a[j2][i + 1] - a[j3][i + 1]; + a[j][i] = x0r + x2r; + a[j][i + 1] = x0i + x2i; + a[j2][i] = x2i - x0i; + a[j2][i + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1][i] = wk1r * (x0r - x0i); + a[j1][i + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3][i] = wk1r * (x0i - x0r); + a[j3][i + 1] = wk1r * (x0i + x0r); + } + } + k1 = 1; + ks = -1; + for (k = (m << 1); k <= n - m; k += m) { + k1++; + ks = -ks; + wk1r = w[k1 << 1]; + wk1i = w[(k1 << 1) + 1]; + wk2r = ks * w[k1]; + wk2i = w[k1 + ks]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j <= l + k - 1; j++) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + for (i = 0; i <= n2 - 2; i += 2) { + x0r = a[j][i] + a[j1][i]; + x0i = a[j][i + 1] + a[j1][i + 1]; + x1r = a[j][i] - a[j1][i]; + x1i = a[j][i + 1] - a[j1][i + 1]; + x2r = a[j2][i] + a[j3][i]; + x2i = a[j2][i + 1] + a[j3][i + 1]; + x3r = a[j2][i] - a[j3][i]; + x3i = a[j2][i + 1] - a[j3][i + 1]; + a[j][i] = x0r + x2r; + a[j][i + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2][i] = wk2r * x0r - wk2i * x0i; + a[j2][i + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1][i] = wk1r * x0r - wk1i * x0i; + a[j1][i + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3][i] = wk3r * x0r - wk3i * x0i; + a[j3][i + 1] = wk3r * x0i + wk3i * x0r; + } + } + } + } + l = m; + } + if (l < n) { + for (j = 0; j <= l - 1; j++) { + j1 = j + l; + for (i = 0; i <= n2 - 2; i += 2) { + x0r = a[j][i] - a[j1][i]; + x0i = a[j][i + 1] - a[j1][i + 1]; + a[j][i] += a[j1][i]; + a[j][i + 1] += a[j1][i + 1]; + a[j1][i] = x0r; + a[j1][i + 1] = x0i; + } + } + } +} + + +void cftfcol(int n1, int n, double **a, double *w) +{ + int i, j, j1, j2, j3, k, k1, ks, l, m; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + for (i = 0; i <= n1 - 1; i++) { + l = 2; + while ((l << 1) < n) { + m = l << 2; + for (j = 0; j <= l - 2; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[i][j] + a[i][j1]; + x0i = a[i][j + 1] + a[i][j1 + 1]; + x1r = a[i][j] - a[i][j1]; + x1i = a[i][j + 1] - a[i][j1 + 1]; + x2r = a[i][j2] + a[i][j3]; + x2i = a[i][j2 + 1] + a[i][j3 + 1]; + x3r = a[i][j2] - a[i][j3]; + x3i = a[i][j2 + 1] - a[i][j3 + 1]; + a[i][j] = x0r + x2r; + a[i][j + 1] = x0i + x2i; + a[i][j2] = x0r - x2r; + a[i][j2 + 1] = x0i - x2i; + a[i][j1] = x1r + x3i; + a[i][j1 + 1] = x1i - x3r; + a[i][j3] = x1r - x3i; + a[i][j3 + 1] = x1i + x3r; + } + if (m < n) { + wk1r = w[2]; + for (j = m; j <= l + m - 2; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[i][j] + a[i][j1]; + x0i = a[i][j + 1] + a[i][j1 + 1]; + x1r = a[i][j] - a[i][j1]; + x1i = a[i][j + 1] - a[i][j1 + 1]; + x2r = a[i][j2] + a[i][j3]; + x2i = a[i][j2 + 1] + a[i][j3 + 1]; + x3r = a[i][j2] - a[i][j3]; + x3i = a[i][j2 + 1] - a[i][j3 + 1]; + a[i][j] = x0r + x2r; + a[i][j + 1] = x0i + x2i; + a[i][j2] = x0i - x2i; + a[i][j2 + 1] = x2r - x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[i][j1] = wk1r * (x0i + x0r); + a[i][j1 + 1] = wk1r * (x0i - x0r); + x0r = x3i - x1r; + x0i = x3r + x1i; + a[i][j3] = wk1r * (x0r + x0i); + a[i][j3 + 1] = wk1r * (x0r - x0i); + } + k1 = 1; + ks = -1; + for (k = (m << 1); k <= n - m; k += m) { + k1++; + ks = -ks; + wk1r = w[k1 << 1]; + wk1i = w[(k1 << 1) + 1]; + wk2r = ks * w[k1]; + wk2i = w[k1 + ks]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j <= l + k - 2; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[i][j] + a[i][j1]; + x0i = a[i][j + 1] + a[i][j1 + 1]; + x1r = a[i][j] - a[i][j1]; + x1i = a[i][j + 1] - a[i][j1 + 1]; + x2r = a[i][j2] + a[i][j3]; + x2i = a[i][j2 + 1] + a[i][j3 + 1]; + x3r = a[i][j2] - a[i][j3]; + x3i = a[i][j2 + 1] - a[i][j3 + 1]; + a[i][j] = x0r + x2r; + a[i][j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[i][j2] = wk2r * x0r + wk2i * x0i; + a[i][j2 + 1] = wk2r * x0i - wk2i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[i][j1] = wk1r * x0r + wk1i * x0i; + a[i][j1 + 1] = wk1r * x0i - wk1i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[i][j3] = wk3r * x0r + wk3i * x0i; + a[i][j3 + 1] = wk3r * x0i - wk3i * x0r; + } + } + } + l = m; + } + if (l < n) { + for (j = 0; j <= l - 2; j += 2) { + j1 = j + l; + x0r = a[i][j] - a[i][j1]; + x0i = a[i][j + 1] - a[i][j1 + 1]; + a[i][j] += a[i][j1]; + a[i][j + 1] += a[i][j1 + 1]; + a[i][j1] = x0r; + a[i][j1 + 1] = x0i; + } + } + } +} + + +void cftfrow(int n, int n2, double **a, double *w) +{ + int i, j, j1, j2, j3, k, k1, ks, l, m; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 1; + while ((l << 1) < n) { + m = l << 2; + for (j = 0; j <= l - 1; j++) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + for (i = 0; i <= n2 - 2; i += 2) { + x0r = a[j][i] + a[j1][i]; + x0i = a[j][i + 1] + a[j1][i + 1]; + x1r = a[j][i] - a[j1][i]; + x1i = a[j][i + 1] - a[j1][i + 1]; + x2r = a[j2][i] + a[j3][i]; + x2i = a[j2][i + 1] + a[j3][i + 1]; + x3r = a[j2][i] - a[j3][i]; + x3i = a[j2][i + 1] - a[j3][i + 1]; + a[j][i] = x0r + x2r; + a[j][i + 1] = x0i + x2i; + a[j2][i] = x0r - x2r; + a[j2][i + 1] = x0i - x2i; + a[j1][i] = x1r + x3i; + a[j1][i + 1] = x1i - x3r; + a[j3][i] = x1r - x3i; + a[j3][i + 1] = x1i + x3r; + } + } + if (m < n) { + wk1r = w[2]; + for (j = m; j <= l + m - 1; j++) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + for (i = 0; i <= n2 - 2; i += 2) { + x0r = a[j][i] + a[j1][i]; + x0i = a[j][i + 1] + a[j1][i + 1]; + x1r = a[j][i] - a[j1][i]; + x1i = a[j][i + 1] - a[j1][i + 1]; + x2r = a[j2][i] + a[j3][i]; + x2i = a[j2][i + 1] + a[j3][i + 1]; + x3r = a[j2][i] - a[j3][i]; + x3i = a[j2][i + 1] - a[j3][i + 1]; + a[j][i] = x0r + x2r; + a[j][i + 1] = x0i + x2i; + a[j2][i] = x0i - x2i; + a[j2][i + 1] = x2r - x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j1][i] = wk1r * (x0i + x0r); + a[j1][i + 1] = wk1r * (x0i - x0r); + x0r = x3i - x1r; + x0i = x3r + x1i; + a[j3][i] = wk1r * (x0r + x0i); + a[j3][i + 1] = wk1r * (x0r - x0i); + } + } + k1 = 1; + ks = -1; + for (k = (m << 1); k <= n - m; k += m) { + k1++; + ks = -ks; + wk1r = w[k1 << 1]; + wk1i = w[(k1 << 1) + 1]; + wk2r = ks * w[k1]; + wk2i = w[k1 + ks]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j <= l + k - 1; j++) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + for (i = 0; i <= n2 - 2; i += 2) { + x0r = a[j][i] + a[j1][i]; + x0i = a[j][i + 1] + a[j1][i + 1]; + x1r = a[j][i] - a[j1][i]; + x1i = a[j][i + 1] - a[j1][i + 1]; + x2r = a[j2][i] + a[j3][i]; + x2i = a[j2][i + 1] + a[j3][i + 1]; + x3r = a[j2][i] - a[j3][i]; + x3i = a[j2][i + 1] - a[j3][i + 1]; + a[j][i] = x0r + x2r; + a[j][i + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2][i] = wk2r * x0r + wk2i * x0i; + a[j2][i + 1] = wk2r * x0i - wk2i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j1][i] = wk1r * x0r + wk1i * x0i; + a[j1][i + 1] = wk1r * x0i - wk1i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j3][i] = wk3r * x0r + wk3i * x0i; + a[j3][i + 1] = wk3r * x0i - wk3i * x0r; + } + } + } + } + l = m; + } + if (l < n) { + for (j = 0; j <= l - 1; j++) { + j1 = j + l; + for (i = 0; i <= n2 - 2; i += 2) { + x0r = a[j][i] - a[j1][i]; + x0i = a[j][i + 1] - a[j1][i + 1]; + a[j][i] += a[j1][i]; + a[j][i + 1] += a[j1][i + 1]; + a[j1][i] = x0r; + a[j1][i + 1] = x0i; + } + } + } +} + + +void rftbcol(int n1, int n, double **a, int nc, double *c) +{ + int i, j, k, kk, ks; + double wkr, wki, xr, xi, yr, yi; + + ks = (nc << 2) / n; + for (i = 0; i <= n1 - 1; i++) { + kk = 0; + for (k = (n >> 1) - 2; k >= 2; k -= 2) { + j = n - k; + kk += ks; + wkr = 0.5 - c[kk]; + wki = c[nc - kk]; + xr = a[i][k] - a[i][j]; + xi = a[i][k + 1] + a[i][j + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[i][k] -= yr; + a[i][k + 1] -= yi; + a[i][j] += yr; + a[i][j + 1] -= yi; + } + } +} + + +void rftfcol(int n1, int n, double **a, int nc, double *c) +{ + int i, j, k, kk, ks; + double wkr, wki, xr, xi, yr, yi; + + ks = (nc << 2) / n; + for (i = 0; i <= n1 - 1; i++) { + kk = 0; + for (k = (n >> 1) - 2; k >= 2; k -= 2) { + j = n - k; + kk += ks; + wkr = 0.5 - c[kk]; + wki = c[nc - kk]; + xr = a[i][k] - a[i][j]; + xi = a[i][k + 1] + a[i][j + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[i][k] -= yr; + a[i][k + 1] -= yi; + a[i][j] += yr; + a[i][j + 1] -= yi; + } + } +} + + +void dctbsub(int n1, int n2, double **a, int nc, double *c) +{ + int kk1, kk2, ks1, ks2, n1h, j1, k1, k2; + double w1r, w1i, wkr, wki, wjr, wji, x0r, x0i, x1r, x1i; + + ks1 = nc / n1; + ks2 = nc / n2; + n1h = n1 >> 1; + kk1 = ks1; + for (k1 = 1; k1 <= n1h - 1; k1++) { + j1 = n1 - k1; + w1r = 2 * c[kk1]; + w1i = 2 * c[nc - kk1]; + kk1 += ks1; + kk2 = ks2; + for (k2 = 2; k2 <= n2 - 2; k2 += 2) { + x0r = w1r * c[kk2]; + x0i = w1i * c[kk2]; + x1r = w1r * c[nc - kk2]; + x1i = w1i * c[nc - kk2]; + wkr = x0r - x1i; + wki = x0i + x1r; + wji = x0r + x1i; + wjr = x0i - x1r; + kk2 += ks2; + x0r = wkr * a[k1][k2] - wki * a[k1][k2 + 1]; + x0i = wkr * a[k1][k2 + 1] + wki * a[k1][k2]; + x1r = wjr * a[j1][k2] - wji * a[j1][k2 + 1]; + x1i = wjr * a[j1][k2 + 1] + wji * a[j1][k2]; + a[k1][k2] = x0r + x1i; + a[k1][k2 + 1] = x0i - x1r; + a[j1][k2] = x1r + x0i; + a[j1][k2 + 1] = x1i - x0r; + } + wkr = w1r * 0.5; + wki = w1i * 0.5; + wjr = w1r * c[kk2]; + wji = w1i * c[kk2]; + x0r = a[k1][0] + a[j1][0]; + x0i = a[k1][1] - a[j1][1]; + x1r = a[k1][0] - a[j1][0]; + x1i = a[k1][1] + a[j1][1]; + a[k1][0] = wkr * x0r - wki * x0i; + a[k1][1] = wkr * x0i + wki * x0r; + a[j1][0] = -wjr * x1r + wji * x1i; + a[j1][1] = wjr * x1i + wji * x1r; + } + w1r = 2 * c[kk1]; + kk2 = ks2; + for (k2 = 2; k2 <= n2 - 2; k2 += 2) { + wkr = 2 * c[kk2]; + wki = 2 * c[nc - kk2]; + wjr = w1r * wkr; + wji = w1r * wki; + kk2 += ks2; + x0i = wkr * a[0][k2 + 1] + wki * a[0][k2]; + a[0][k2] = wkr * a[0][k2] - wki * a[0][k2 + 1]; + a[0][k2 + 1] = x0i; + x0i = wjr * a[n1h][k2 + 1] + wji * a[n1h][k2]; + a[n1h][k2] = wjr * a[n1h][k2] - wji * a[n1h][k2 + 1]; + a[n1h][k2 + 1] = x0i; + } + a[0][1] *= w1r; + a[n1h][0] *= w1r; + a[n1h][1] *= 0.5; +} + + +void dctfsub(int n1, int n2, double **a, int nc, double *c) +{ + int kk1, kk2, ks1, ks2, n1h, j1, k1, k2; + double w1r, w1i, wkr, wki, wjr, wji, x0r, x0i, x1r, x1i; + + ks1 = nc / n1; + ks2 = nc / n2; + n1h = n1 >> 1; + kk1 = ks1; + for (k1 = 1; k1 <= n1h - 1; k1++) { + j1 = n1 - k1; + w1r = 2 * c[kk1]; + w1i = 2 * c[nc - kk1]; + kk1 += ks1; + kk2 = ks2; + for (k2 = 2; k2 <= n2 - 2; k2 += 2) { + x0r = w1r * c[kk2]; + x0i = w1i * c[kk2]; + x1r = w1r * c[nc - kk2]; + x1i = w1i * c[nc - kk2]; + wkr = x0r - x1i; + wki = x0i + x1r; + wji = x0r + x1i; + wjr = x0i - x1r; + kk2 += ks2; + x0r = a[k1][k2] - a[j1][k2 + 1]; + x0i = a[j1][k2] + a[k1][k2 + 1]; + x1r = a[j1][k2] - a[k1][k2 + 1]; + x1i = a[k1][k2] + a[j1][k2 + 1]; + a[k1][k2] = wkr * x0r + wki * x0i; + a[k1][k2 + 1] = wkr * x0i - wki * x0r; + a[j1][k2] = wjr * x1r + wji * x1i; + a[j1][k2 + 1] = wjr * x1i - wji * x1r; + } + x0r = 2 * c[kk2]; + wjr = x0r * w1r; + wji = x0r * w1i; + x0r = w1r * a[k1][0] + w1i * a[k1][1]; + x0i = w1r * a[k1][1] - w1i * a[k1][0]; + x1r = -wjr * a[j1][0] + wji * a[j1][1]; + x1i = wjr * a[j1][1] + wji * a[j1][0]; + a[k1][0] = x0r + x1r; + a[k1][1] = x1i + x0i; + a[j1][0] = x0r - x1r; + a[j1][1] = x1i - x0i; + } + w1r = 2 * c[kk1]; + kk2 = ks2; + for (k2 = 2; k2 <= n2 - 2; k2 += 2) { + wkr = 2 * c[kk2]; + wki = 2 * c[nc - kk2]; + wjr = w1r * wkr; + wji = w1r * wki; + kk2 += ks2; + x0i = wkr * a[0][k2 + 1] - wki * a[0][k2]; + a[0][k2] = wkr * a[0][k2] + wki * a[0][k2 + 1]; + a[0][k2 + 1] = x0i; + x0i = wjr * a[n1h][k2 + 1] - wji * a[n1h][k2]; + a[n1h][k2] = wjr * a[n1h][k2] + wji * a[n1h][k2 + 1]; + a[n1h][k2 + 1] = x0i; + } + w1r *= 2; + a[0][0] *= 2; + a[0][1] *= w1r; + a[n1h][0] *= w1r; +} + + +void dstbsub(int n1, int n2, double **a, int nc, double *c) +{ + int kk1, kk2, ks1, ks2, n1h, j1, k1, k2; + double w1r, w1i, wkr, wki, wjr, wji, x0r, x0i, x1r, x1i; + + ks1 = nc / n1; + ks2 = nc / n2; + n1h = n1 >> 1; + kk1 = ks1; + for (k1 = 1; k1 <= n1h - 1; k1++) { + j1 = n1 - k1; + w1r = 2 * c[kk1]; + w1i = 2 * c[nc - kk1]; + kk1 += ks1; + kk2 = ks2; + for (k2 = 2; k2 <= n2 - 2; k2 += 2) { + x0r = w1r * c[kk2]; + x0i = w1i * c[kk2]; + x1r = w1r * c[nc - kk2]; + x1i = w1i * c[nc - kk2]; + wkr = x0r - x1i; + wki = x0i + x1r; + wji = x0r + x1i; + wjr = x0i - x1r; + kk2 += ks2; + x0r = wkr * a[k1][k2] - wki * a[k1][k2 + 1]; + x0i = wkr * a[k1][k2 + 1] + wki * a[k1][k2]; + x1r = wjr * a[j1][k2] - wji * a[j1][k2 + 1]; + x1i = wjr * a[j1][k2 + 1] + wji * a[j1][k2]; + a[k1][k2] = x1i - x0r; + a[k1][k2 + 1] = x1r + x0i; + a[j1][k2] = x0i - x1r; + a[j1][k2 + 1] = x0r + x1i; + } + wkr = w1r * 0.5; + wki = w1i * 0.5; + wjr = w1r * c[kk2]; + wji = w1i * c[kk2]; + x0r = a[k1][0] + a[j1][0]; + x0i = a[k1][1] - a[j1][1]; + x1r = a[k1][0] - a[j1][0]; + x1i = a[k1][1] + a[j1][1]; + a[k1][1] = wkr * x0r - wki * x0i; + a[k1][0] = wkr * x0i + wki * x0r; + a[j1][1] = -wjr * x1r + wji * x1i; + a[j1][0] = wjr * x1i + wji * x1r; + } + w1r = 2 * c[kk1]; + kk2 = ks2; + for (k2 = 2; k2 <= n2 - 2; k2 += 2) { + wkr = 2 * c[kk2]; + wki = 2 * c[nc - kk2]; + wjr = w1r * wkr; + wji = w1r * wki; + kk2 += ks2; + x0i = wkr * a[0][k2 + 1] + wki * a[0][k2]; + a[0][k2 + 1] = wkr * a[0][k2] - wki * a[0][k2 + 1]; + a[0][k2] = x0i; + x0i = wjr * a[n1h][k2 + 1] + wji * a[n1h][k2]; + a[n1h][k2 + 1] = wjr * a[n1h][k2] - wji * a[n1h][k2 + 1]; + a[n1h][k2] = x0i; + } + a[0][1] *= w1r; + a[n1h][0] *= w1r; + a[n1h][1] *= 0.5; +} + + +void dstfsub(int n1, int n2, double **a, int nc, double *c) +{ + int kk1, kk2, ks1, ks2, n1h, j1, k1, k2; + double w1r, w1i, wkr, wki, wjr, wji, x0r, x0i, x1r, x1i; + + ks1 = nc / n1; + ks2 = nc / n2; + n1h = n1 >> 1; + kk1 = ks1; + for (k1 = 1; k1 <= n1h - 1; k1++) { + j1 = n1 - k1; + w1r = 2 * c[kk1]; + w1i = 2 * c[nc - kk1]; + kk1 += ks1; + kk2 = ks2; + for (k2 = 2; k2 <= n2 - 2; k2 += 2) { + x0r = w1r * c[kk2]; + x0i = w1i * c[kk2]; + x1r = w1r * c[nc - kk2]; + x1i = w1i * c[nc - kk2]; + wkr = x0r - x1i; + wki = x0i + x1r; + wji = x0r + x1i; + wjr = x0i - x1r; + kk2 += ks2; + x0r = a[j1][k2 + 1] - a[k1][k2]; + x0i = a[k1][k2 + 1] + a[j1][k2]; + x1r = a[k1][k2 + 1] - a[j1][k2]; + x1i = a[j1][k2 + 1] + a[k1][k2]; + a[k1][k2] = wkr * x0r + wki * x0i; + a[k1][k2 + 1] = wkr * x0i - wki * x0r; + a[j1][k2] = wjr * x1r + wji * x1i; + a[j1][k2 + 1] = wjr * x1i - wji * x1r; + } + x0r = 2 * c[kk2]; + wjr = x0r * w1r; + wji = x0r * w1i; + x0r = w1r * a[k1][1] + w1i * a[k1][0]; + x0i = w1r * a[k1][0] - w1i * a[k1][1]; + x1r = -wjr * a[j1][1] + wji * a[j1][0]; + x1i = wjr * a[j1][0] + wji * a[j1][1]; + a[k1][0] = x0r + x1r; + a[k1][1] = x1i + x0i; + a[j1][0] = x0r - x1r; + a[j1][1] = x1i - x0i; + } + w1r = 2 * c[kk1]; + kk2 = ks2; + for (k2 = 2; k2 <= n2 - 2; k2 += 2) { + wkr = 2 * c[kk2]; + wki = 2 * c[nc - kk2]; + wjr = w1r * wkr; + wji = w1r * wki; + kk2 += ks2; + x0i = wkr * a[0][k2] - wki * a[0][k2 + 1]; + a[0][k2] = wkr * a[0][k2 + 1] + wki * a[0][k2]; + a[0][k2 + 1] = x0i; + x0i = wjr * a[n1h][k2] - wji * a[n1h][k2 + 1]; + a[n1h][k2] = wjr * a[n1h][k2 + 1] + wji * a[n1h][k2]; + a[n1h][k2 + 1] = x0i; + } + w1r *= 2; + a[0][0] *= 2; + a[0][1] *= w1r; + a[n1h][0] *= w1r; +} +
diff --git a/third_party/tensorflow_dependencies/fft2d/fft4f2d.f b/third_party/tensorflow_dependencies/fft2d/fft4f2d.f new file mode 100644 index 0000000..af529e3 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/fft4f2d.f
@@ -0,0 +1,1591 @@ +! Fast Fourier/Cosine/Sine Transform +! dimension :two +! data length :power of 2 +! decimation :frequency +! radix :4, 2, row-column +! data :inplace +! table :use +! subroutines +! cdft2d: Complex Discrete Fourier Transform +! rdft2d: Real Discrete Fourier Transform +! ddct2d: Discrete Cosine Transform +! ddst2d: Discrete Sine Transform +! +! +! -------- Complex DFT (Discrete Fourier Transform) -------- +! [definition] +! <case1> +! X(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 x(j1,j2) * +! exp(2*pi*i*j1*k1/n1) * +! exp(2*pi*i*j2*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! <case2> +! X(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 x(j1,j2) * +! exp(-2*pi*i*j1*k1/n1) * +! exp(-2*pi*i*j2*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! (notes: sum_j=0^n-1 is a summation from j=0 to n-1) +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call cdft2d(n1max, 2*n1, n2, 1, a, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call cdft2d(n1max, 2*n1, n2, -1, a, ip, w) +! [parameters] +! n1max :row size of the 2D array (integer) +! 2*n1 :data length (integer) +! n1 >= 1, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 1, n2 = power of 2 +! a(0:2*n1-1,0:n2-1) +! :input/output data (real*8) +! input data +! a(2*j1,j2) = Re(x(j1,j2)), +! a(2*j1+1,j2) = Im(x(j1,j2)), +! 0<=j1<n1, 0<=j2<n2 +! output data +! a(2*k1,k2) = Re(X(k1,k2)), +! a(2*k1+1,k2) = Im(X(k1,k2)), +! 0<=k1<n1, 0<=k2<n2 +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1, n2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1/2, n2/2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call cdft2d(n1max, 2*n1, n2, -1, a, ip, w) +! is +! call cdft2d(n1max, 2*n1, n2, 1, a, ip, w) +! do j2 = 0, n2 - 1 +! do j1 = 0, 2 * n1 - 1 +! a(j1, j2) = a(j1, j2) * (1.0d0 / (n1 * n2)) +! end do +! end do +! . +! +! +! -------- Real DFT / Inverse of Real DFT -------- +! [definition] +! <case1> RDFT +! R(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! I(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! <case2> IRDFT (excluding scale) +! a(k1,k2) = (1/2) * sum_j1=0^n1-1 sum_j2=0^n2-1 +! (R(j1,j2) * +! cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2) + +! I(j1,j2) * +! sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2)), +! 0<=k1<n1, 0<=k2<n2 +! (notes: R(n1-k1,n2-k2) = R(k1,k2), +! I(n1-k1,n2-k2) = -I(k1,k2), +! R(n1-k1,0) = R(k1,0), +! I(n1-k1,0) = -I(k1,0), +! R(0,n2-k2) = R(0,k2), +! I(0,n2-k2) = -I(0,k2), +! 0<k1<n1, 0<k2<n2) +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call rdft2d(n1max, n1, n2, 1, a, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call rdft2d(n1max, n1, n2, -1, a, ip, w) +! [parameters] +! n1max :row size of the 2D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! a(0:n1-1,0:n2-1) +! :input/output data (real*8) +! <case1> +! output data +! a(2*k1,k2) = R(k1,k2) = R(n1-k1,n2-k2), +! a(2*k1+1,k2) = I(k1,k2) = -I(n1-k1,n2-k2), +! 0<k1<n1/2, 0<k2<n2, +! a(2*k1,0) = R(k1,0) = R(n1-k1,0), +! a(2*k1+1,0) = I(k1,0) = -I(n1-k1,0), +! 0<k1<n1/2, +! a(0,k2) = R(0,k2) = R(0,n2-k2), +! a(1,k2) = I(0,k2) = -I(0,n2-k2), +! a(1,n2-k2) = R(n1/2,k2) = R(n1/2,n2-k2), +! a(0,n2-k2) = -I(n1/2,k2) = I(n1/2,n2-k2), +! 0<k2<n2/2, +! a(0,0) = R(0,0), +! a(1,0) = R(n1/2,0), +! a(0,n2/2) = R(0,n2/2), +! a(1,n2/2) = R(n1/2,n2/2) +! <case2> +! input data +! a(2*j1,j2) = R(j1,j2) = R(n1-j1,n2-j2), +! a(2*j1+1,j2) = I(j1,j2) = -I(n1-j1,n2-j2), +! 0<j1<n1/2, 0<j2<n2, +! a(2*j1,0) = R(j1,0) = R(n1-j1,0), +! a(2*j1+1,0) = I(j1,0) = -I(n1-j1,0), +! 0<j1<n1/2, +! a(0,j2) = R(0,j2) = R(0,n2-j2), +! a(1,j2) = I(0,j2) = -I(0,n2-j2), +! a(1,n2-j2) = R(n1/2,j2) = R(n1/2,n2-j2), +! a(0,n2-j2) = -I(n1/2,j2) = I(n1/2,n2-j2), +! 0<j2<n2/2, +! a(0,0) = R(0,0), +! a(1,0) = R(n1/2,0), +! a(0,n2/2) = R(0,n2/2), +! a(1,n2/2) = R(n1/2,n2/2) +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1/4, n2/2) + n1/4 +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call rdft2d(n1max, n1, n2, 1, a, ip, w) +! is +! call rdft2d(n1max, n1, n2, -1, a, ip, w) +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1, j2) = a(j1, j2) * (2.0d0 / (n1 * n2)) +! end do +! end do +! . +! +! +! -------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- +! [definition] +! <case1> IDCT (excluding scale) +! C(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! cos(pi*j1*(k1+1/2)/n1) * +! cos(pi*j2*(k2+1/2)/n2), +! 0<=k1<n1, 0<=k2<n2 +! <case2> DCT +! C(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! cos(pi*(j1+1/2)*k1/n1) * +! cos(pi*(j2+1/2)*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call ddct2d(n1max, n1, n2, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call ddct2d(n1max, n1, n2, -1, a, t, ip, w) +! [parameters] +! n1max :row size of the 2D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! a(0:n1-1,0:n2-1) +! :input/output data (real*8) +! output data +! a(k1,k2) = C(k1,k2), 0<=k1<n1, 0<=k2<n2 +! t(0:n1-1,0:n2-1) +! :work area (real*8) +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1/4, n2/2) + max(n1, n2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call ddct2d(n1max, n1, n2, -1, a, t, ip, w) +! is +! do j1 = 0, n1 - 1 +! a(j1, 0) = a(j1, 0) * 0.5d0 +! end do +! do j2 = 0, n2 - 1 +! a(0, j2) = a(0, j2) * 0.5d0 +! end do +! call ddct2d(n1max, n1, n2, 1, a, t, ip, w) +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1, j2) = a(j1, j2) * (4.0d0 / (n1 * n2)) +! end do +! end do +! . +! +! +! -------- DST (Discrete Sine Transform) / Inverse of DST -------- +! [definition] +! <case1> IDST (excluding scale) +! S(k1,k2) = sum_j1=1^n1 sum_j2=1^n2 A(j1,j2) * +! sin(pi*j1*(k1+1/2)/n1) * +! sin(pi*j2*(k2+1/2)/n2), +! 0<=k1<n1, 0<=k2<n2 +! <case2> DST +! S(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! sin(pi*(j1+1/2)*k1/n1) * +! sin(pi*(j2+1/2)*k2/n2), +! 0<k1<=n1, 0<k2<=n2 +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call ddst2d(n1max, n1, n2, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call ddst2d(n1max, n1, n2, -1, a, t, ip, w) +! [parameters] +! n1max :row size of the 2D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! a(0:n1-1,0:n2-1) +! :input/output data (real*8) +! <case1> +! input data +! a(j1,j2) = A(j1,j2), 0<j1<n1, 0<j2<n2, +! a(j1,0) = A(j1,n2), 0<j1<n1, +! a(0,j2) = A(n1,j2), 0<j2<n2, +! a(0,0) = A(n1,n2) +! (i.e. A(j1,j2) = a(mod(j1,n1),mod(j2,n2))) +! output data +! a(k1,k2) = S(k1,k2), 0<=k1<n1, 0<=k2<n2 +! <case2> +! output data +! a(k1,k2) = S(k1,k2), 0<k1<n1, 0<k2<n2, +! a(k1,0) = S(k1,n2), 0<k1<n1, +! a(0,k2) = S(n1,k2), 0<k2<n2, +! a(0,0) = S(n1,n2) +! (i.e. S(k1,k2) = a(mod(k1,n1),mod(k2,n2))) +! t(0:n1-1,0:n2-1) +! :work area (real*8) +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1/4, n2/2) + max(n1, n2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call ddst2d(n1max, n1, n2, -1, a, t, ip, w) +! is +! do j1 = 0, n1 - 1 +! a(j1, 0) = a(j1, 0) * 0.5d0 +! end do +! do j2 = 0, n2 - 1 +! a(0, j2) = a(0, j2) * 0.5d0 +! end do +! call ddst2d(n1max, n1, n2, 1, a, t, ip, w) +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1, j2) = a(j1, j2) * (4.0d0 / (n1 * n2)) +! end do +! end do +! . +! +! + subroutine cdft2d(n1max, n1, n2, isgn, a, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), n + real*8 a(0 : n1max - 1, 0 : n2 - 1), w(0 : *) + n = max(n1, 2 * n2) + if (n .gt. 4 * ip(0)) then + call makewt(n / 4, ip, w) + end if + if (n1 .gt. 4) then + call bitrv2row(n1max, n1, n2, ip(2), a) + end if + if (n2 .gt. 2) then + call bitrv2col(n1max, n1, n2, ip(2), a) + end if + if (isgn .lt. 0) then + call cftfrow(n1max, n1, n2, a, w) + call cftfcol(n1max, n1, n2, a, w) + else + call cftbrow(n1max, n1, n2, a, w) + call cftbcol(n1max, n1, n2, a, w) + end if + end +! + subroutine rdft2d(n1max, n1, n2, isgn, a, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), n, nw, nc, n2h, i, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), w(0 : *), xi + n = max(n1, 2 * n2) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n1 .gt. 4 * nc) then + nc = n1 / 4 + call makect(nc, ip, w(nw)) + end if + n2h = n2 / 2 + if (isgn .lt. 0) then + do i = 1, n2h - 1 + j = n2 - i + xi = a(0, i) - a(0, j) + a(0, i) = a(0, i) + a(0, j) + a(0, j) = xi + xi = a(1, j) - a(1, i) + a(1, i) = a(1, i) + a(1, j) + a(1, j) = xi + end do + if (n2 .gt. 2) then + call bitrv2col(n1max, n1, n2, ip(2), a) + end if + call cftfcol(n1max, n1, n2, a, w) + do i = 0, n2 - 1 + a(1, i) = 0.5d0 * (a(0, i) - a(1, i)) + a(0, i) = a(0, i) - a(1, i) + end do + if (n1 .gt. 4) then + call rftfrow(n1max, n1, n2, a, nc, w(nw)) + call bitrv2row(n1max, n1, n2, ip(2), a) + end if + call cftfrow(n1max, n1, n2, a, w) + else + if (n1 .gt. 4) then + call bitrv2row(n1max, n1, n2, ip(2), a) + end if + call cftbrow(n1max, n1, n2, a, w) + if (n1 .gt. 4) then + call rftbrow(n1max, n1, n2, a, nc, w(nw)) + end if + do i = 0, n2 - 1 + xi = a(0, i) - a(1, i) + a(0, i) = a(0, i) + a(1, i) + a(1, i) = xi + end do + if (n2 .gt. 2) then + call bitrv2col(n1max, n1, n2, ip(2), a) + end if + call cftbcol(n1max, n1, n2, a, w) + do i = 1, n2h - 1 + j = n2 - i + a(0, j) = 0.5d0 * (a(0, i) - a(0, j)) + a(0, i) = a(0, i) - a(0, j) + a(1, j) = 0.5d0 * (a(1, i) + a(1, j)) + a(1, i) = a(1, i) - a(1, j) + end do + end if + end +! + subroutine ddct2d(n1max, n1, n2, isgn, a, t, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), n, nw, nc, n1h, n2h, + & i, ix, ic, j, jx, jc + real*8 a(0 : n1max - 1, 0 : n2 - 1), + & t(0 : n1max - 1, 0 : n2 - 1), w(0 : *), xi + n = max(n1, 2 * n2) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n1 .gt. nc .or. n2 .gt. nc) then + nc = max(n1, n2) + call makect(nc, ip, w(nw)) + end if + n1h = n1 / 2 + n2h = n2 / 2 + if (isgn .ge. 0) then + do i = 0, n2 - 1 + do j = 1, n1h - 1 + jx = 2 * j + t(jx, i) = a(j, i) + t(jx + 1, i) = a(n1 - j, i) + end do + end do + t(0, 0) = a(0, 0) + t(1, 0) = a(n1h, 0) + t(0, n2h) = a(0, n2h) + t(1, n2h) = a(n1h, n2h) + do i = 1, n2h - 1 + ic = n2 - i + t(0, i) = a(0, i) + t(1, ic) = a(n1h, i) + t(1, i) = a(0, ic) + t(0, ic) = a(n1h, ic) + end do + call dctfsub(n1max, n1, n2, t, nc, w(nw)) + if (n2 .gt. 2) then + call bitrv2col(n1max, n1, n2, ip(2), t) + end if + call cftfcol(n1max, n1, n2, t, w) + do i = 0, n2 - 1 + t(1, i) = 0.5d0 * (t(0, i) - t(1, i)) + t(0, i) = t(0, i) - t(1, i) + end do + if (n1 .gt. 4) then + call rftfrow(n1max, n1, n2, t, nc, w(nw)) + call bitrv2row(n1max, n1, n2, ip(2), t) + end if + call cftfrow(n1max, n1, n2, t, w) + do i = 0, n2h - 1 + ix = 2 * i + ic = n2 - 1 - i + do j = 0, n1h - 1 + jx = 2 * j + jc = n1 - 1 - j + a(jx, ix) = t(j, i) + a(jx + 1, ix) = t(jc, i) + a(jx, ix + 1) = t(j, ic) + a(jx + 1, ix + 1) = t(jc, ic) + end do + end do + else + do i = 0, n2h - 1 + ix = 2 * i + ic = n2 - 1 - i + do j = 0, n1h - 1 + jx = 2 * j + jc = n1 - 1 - j + t(j, i) = a(jx, ix) + t(jc, i) = a(jx + 1, ix) + t(j, ic) = a(jx, ix + 1) + t(jc, ic) = a(jx + 1, ix + 1) + end do + end do + if (n1 .gt. 4) then + call bitrv2row(n1max, n1, n2, ip(2), t) + end if + call cftbrow(n1max, n1, n2, t, w) + if (n1 .gt. 4) then + call rftbrow(n1max, n1, n2, t, nc, w(nw)) + end if + do i = 0, n2 - 1 + xi = t(0, i) - t(1, i) + t(0, i) = t(0, i) + t(1, i) + t(1, i) = xi + end do + if (n2 .gt. 2) then + call bitrv2col(n1max, n1, n2, ip(2), t) + end if + call cftbcol(n1max, n1, n2, t, w) + call dctbsub(n1max, n1, n2, t, nc, w(nw)) + do i = 0, n2 - 1 + do j = 1, n1h - 1 + jx = 2 * j + a(j, i) = t(jx, i) + a(n1 - j, i) = t(jx + 1, i) + end do + end do + a(0, 0) = t(0, 0) + a(n1h, 0) = t(1, 0) + a(0, n2h) = t(0, n2h) + a(n1h, n2h) = t(1, n2h) + do i = 1, n2h - 1 + ic = n2 - i + a(0, i) = t(0, i) + a(n1h, i) = t(1, ic) + a(0, ic) = t(1, i) + a(n1h, ic) = t(0, ic) + end do + end if + end +! + subroutine ddst2d(n1max, n1, n2, isgn, a, t, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), n, nw, nc, n1h, n2h, + & i, ix, ic, j, jx, jc + real*8 a(0 : n1max - 1, 0 : n2 - 1), + & t(0 : n1max - 1, 0 : n2 - 1), w(0 : *), xi + n = max(n1, 2 * n2) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n1 .gt. nc .or. n2 .gt. nc) then + nc = max(n1, n2) + call makect(nc, ip, w(nw)) + end if + n1h = n1 / 2 + n2h = n2 / 2 + if (isgn .ge. 0) then + do i = 0, n2 - 1 + do j = 1, n1h - 1 + jx = 2 * j + t(jx, i) = a(j, i) + t(jx + 1, i) = a(n1 - j, i) + end do + end do + t(0, 0) = a(0, 0) + t(1, 0) = a(n1h, 0) + t(0, n2h) = a(0, n2h) + t(1, n2h) = a(n1h, n2h) + do i = 1, n2h - 1 + ic = n2 - i + t(0, i) = a(0, i) + t(1, ic) = a(n1h, i) + t(1, i) = a(0, ic) + t(0, ic) = a(n1h, ic) + end do + call dstfsub(n1max, n1, n2, t, nc, w(nw)) + if (n2 .gt. 2) then + call bitrv2col(n1max, n1, n2, ip(2), t) + end if + call cftfcol(n1max, n1, n2, t, w) + do i = 0, n2 - 1 + t(1, i) = 0.5d0 * (t(0, i) - t(1, i)) + t(0, i) = t(0, i) - t(1, i) + end do + if (n1 .gt. 4) then + call rftfrow(n1max, n1, n2, t, nc, w(nw)) + call bitrv2row(n1max, n1, n2, ip(2), t) + end if + call cftfrow(n1max, n1, n2, t, w) + do i = 0, n2h - 1 + ix = 2 * i + ic = n2 - 1 - i + do j = 0, n1h - 1 + jx = 2 * j + jc = n1 - 1 - j + a(jx, ix) = t(j, i) + a(jx + 1, ix) = -t(jc, i) + a(jx, ix + 1) = -t(j, ic) + a(jx + 1, ix + 1) = t(jc, ic) + end do + end do + else + do i = 0, n2h - 1 + ix = 2 * i + ic = n2 - 1 - i + do j = 0, n1h - 1 + jx = 2 * j + jc = n1 - 1 - j + t(j, i) = a(jx, ix) + t(jc, i) = -a(jx + 1, ix) + t(j, ic) = -a(jx, ix + 1) + t(jc, ic) = a(jx + 1, ix + 1) + end do + end do + if (n1 .gt. 4) then + call bitrv2row(n1max, n1, n2, ip(2), t) + end if + call cftbrow(n1max, n1, n2, t, w) + if (n1 .gt. 4) then + call rftbrow(n1max, n1, n2, t, nc, w(nw)) + end if + do i = 0, n2 - 1 + xi = t(0, i) - t(1, i) + t(0, i) = t(0, i) + t(1, i) + t(1, i) = xi + end do + if (n2 .gt. 2) then + call bitrv2col(n1max, n1, n2, ip(2), t) + end if + call cftbcol(n1max, n1, n2, t, w) + call dstbsub(n1max, n1, n2, t, nc, w(nw)) + do i = 0, n2 - 1 + do j = 1, n1h - 1 + jx = 2 * j + a(j, i) = t(jx, i) + a(n1 - j, i) = t(jx + 1, i) + end do + end do + a(0, 0) = t(0, 0) + a(n1h, 0) = t(1, 0) + a(0, n2h) = t(0, n2h) + a(n1h, n2h) = t(1, n2h) + do i = 1, n2h - 1 + ic = n2 - i + a(0, i) = t(0, i) + a(n1h, i) = t(1, ic) + a(0, ic) = t(1, i) + a(n1h, ic) = t(0, ic) + end do + end if + end +! +! -------- initializing routines -------- +! + subroutine makewt(nw, ip, w) + integer nw, ip(0 : *), nwh, j + real*8 w(0 : nw - 1), delta, x, y + ip(0) = nw + ip(1) = 1 + if (nw .gt. 2) then + nwh = nw / 2 + delta = atan(1.0d0) / nwh + w(0) = 1 + w(1) = 0 + w(nwh) = cos(delta * nwh) + w(nwh + 1) = w(nwh) + do j = 2, nwh - 2, 2 + x = cos(delta * j) + y = sin(delta * j) + w(j) = x + w(j + 1) = y + w(nw - j) = y + w(nw - j + 1) = x + end do + call bitrv2(nw, ip(2), w) + end if + end +! + subroutine makect(nc, ip, c) + integer nc, ip(0 : *), nch, j + real*8 c(0 : nc - 1), delta + ip(1) = nc + if (nc .gt. 1) then + nch = nc / 2 + delta = atan(1.0d0) / nch + c(0) = 0.5d0 + c(nch) = 0.5d0 * cos(delta * nch) + do j = 1, nch - 1 + c(j) = 0.5d0 * cos(delta * j) + c(nc - j) = 0.5d0 * sin(delta * j) + end do + end if + end +! +! -------- child routines -------- +! + subroutine bitrv2(n, ip, a) + integer n, ip(0 : *), j, j1, k, k1, l, m, m2 + real*8 a(0 : n - 1), xr, xi + ip(0) = 0 + l = n + m = 1 + do while (4 * m .lt. l) + l = l / 2 + do j = 0, m - 1 + ip(m + j) = ip(j) + l + end do + m = m * 2 + end do + if (4 * m .gt. l) then + do k = 1, m - 1 + do j = 0, k - 1 + j1 = 2 * j + ip(k) + k1 = 2 * k + ip(j) + xr = a(j1) + xi = a(j1 + 1) + a(j1) = a(k1) + a(j1 + 1) = a(k1 + 1) + a(k1) = xr + a(k1 + 1) = xi + end do + end do + else + m2 = 2 * m + do k = 1, m - 1 + do j = 0, k - 1 + j1 = 2 * j + ip(k) + k1 = 2 * k + ip(j) + xr = a(j1) + xi = a(j1 + 1) + a(j1) = a(k1) + a(j1 + 1) = a(k1 + 1) + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + m2 + k1 = k1 + m2 + xr = a(j1) + xi = a(j1 + 1) + a(j1) = a(k1) + a(j1 + 1) = a(k1 + 1) + a(k1) = xr + a(k1 + 1) = xi + end do + end do + end if + end +! + subroutine bitrv2row(n1max, n, n2, ip, a) + integer n1max, n, n2, ip(0 : *), i, j, j1, k, k1, l, m, m2 + real*8 a(0 : n1max - 1, 0 : n2 - 1), xr, xi + ip(0) = 0 + l = n + m = 1 + do while (4 * m .lt. l) + l = l / 2 + do j = 0, m - 1 + ip(m + j) = ip(j) + l + end do + m = m * 2 + end do + if (4 * m .gt. l) then + do i = 0, n2 - 1 + do k = 1, m - 1 + do j = 0, k - 1 + j1 = 2 * j + ip(k) + k1 = 2 * k + ip(j) + xr = a(j1, i) + xi = a(j1 + 1, i) + a(j1, i) = a(k1, i) + a(j1 + 1, i) = a(k1 + 1, i) + a(k1, i) = xr + a(k1 + 1, i) = xi + end do + end do + end do + else + m2 = 2 * m + do i = 0, n2 - 1 + do k = 1, m - 1 + do j = 0, k - 1 + j1 = 2 * j + ip(k) + k1 = 2 * k + ip(j) + xr = a(j1, i) + xi = a(j1 + 1, i) + a(j1, i) = a(k1, i) + a(j1 + 1, i) = a(k1 + 1, i) + a(k1, i) = xr + a(k1 + 1, i) = xi + j1 = j1 + m2 + k1 = k1 + m2 + xr = a(j1, i) + xi = a(j1 + 1, i) + a(j1, i) = a(k1, i) + a(j1 + 1, i) = a(k1 + 1, i) + a(k1, i) = xr + a(k1 + 1, i) = xi + end do + end do + end do + end if + end +! + subroutine bitrv2col(n1max, n1, n, ip, a) + integer n1max, n1, n, ip(0 : *), i, j, j1, k, k1, l, m + real*8 a(0 : n1max - 1, 0 : n - 1), xr, xi + ip(0) = 0 + l = n + m = 1 + do while (2 * m .lt. l) + l = l / 2 + do j = 0, m - 1 + ip(m + j) = ip(j) + l + end do + m = m * 2 + end do + if (2 * m .gt. l) then + do k = 1, m - 1 + do j = 0, k - 1 + j1 = j + ip(k) + k1 = k + ip(j) + do i = 0, n1 - 2, 2 + xr = a(i, j1) + xi = a(i + 1, j1) + a(i, j1) = a(i, k1) + a(i + 1, j1) = a(i + 1, k1) + a(i, k1) = xr + a(i + 1, k1) = xi + end do + end do + end do + else + do k = 1, m - 1 + do j = 0, k - 1 + j1 = j + ip(k) + k1 = k + ip(j) + do i = 0, n1 - 2, 2 + xr = a(i, j1) + xi = a(i + 1, j1) + a(i, j1) = a(i, k1) + a(i + 1, j1) = a(i + 1, k1) + a(i, k1) = xr + a(i + 1, k1) = xi + end do + j1 = j1 + m + k1 = k1 + m + do i = 0, n1 - 2, 2 + xr = a(i, j1) + xi = a(i + 1, j1) + a(i, j1) = a(i, k1) + a(i + 1, j1) = a(i + 1, k1) + a(i, k1) = xr + a(i + 1, k1) = xi + end do + end do + end do + end if + end +! + subroutine cftbrow(n1max, n, n2, a, w) + integer n1max, n, n2, i, j, j1, j2, j3, k, k1, ks, l, m + real*8 a(0 : n1max - 1, 0 : n2 - 1), w(0 : *) + real*8 wk1r, wk1i, wk2r, wk2i, wk3r, wk3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + do i = 0, n2 - 1 + l = 2 + do while (2 * l .lt. n) + m = 4 * l + do j = 0, l - 2, 2 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + x0r = a(j, i) + a(j1, i) + x0i = a(j + 1, i) + a(j1 + 1, i) + x1r = a(j, i) - a(j1, i) + x1i = a(j + 1, i) - a(j1 + 1, i) + x2r = a(j2, i) + a(j3, i) + x2i = a(j2 + 1, i) + a(j3 + 1, i) + x3r = a(j2, i) - a(j3, i) + x3i = a(j2 + 1, i) - a(j3 + 1, i) + a(j, i) = x0r + x2r + a(j + 1, i) = x0i + x2i + a(j2, i) = x0r - x2r + a(j2 + 1, i) = x0i - x2i + a(j1, i) = x1r - x3i + a(j1 + 1, i) = x1i + x3r + a(j3, i) = x1r + x3i + a(j3 + 1, i) = x1i - x3r + end do + if (m .lt. n) then + wk1r = w(2) + do j = m, l + m - 2, 2 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + x0r = a(j, i) + a(j1, i) + x0i = a(j + 1, i) + a(j1 + 1, i) + x1r = a(j, i) - a(j1, i) + x1i = a(j + 1, i) - a(j1 + 1, i) + x2r = a(j2, i) + a(j3, i) + x2i = a(j2 + 1, i) + a(j3 + 1, i) + x3r = a(j2, i) - a(j3, i) + x3i = a(j2 + 1, i) - a(j3 + 1, i) + a(j, i) = x0r + x2r + a(j + 1, i) = x0i + x2i + a(j2, i) = x2i - x0i + a(j2 + 1, i) = x0r - x2r + x0r = x1r - x3i + x0i = x1i + x3r + a(j1, i) = wk1r * (x0r - x0i) + a(j1 + 1, i) = wk1r * (x0r + x0i) + x0r = x3i + x1r + x0i = x3r - x1i + a(j3, i) = wk1r * (x0i - x0r) + a(j3 + 1, i) = wk1r * (x0i + x0r) + end do + k1 = 1 + ks = -1 + do k = 2 * m, n - m, m + k1 = k1 + 1 + ks = -ks + wk1r = w(2 * k1) + wk1i = w(2 * k1 + 1) + wk2r = ks * w(k1) + wk2i = w(k1 + ks) + wk3r = wk1r - 2 * wk2i * wk1i + wk3i = 2 * wk2i * wk1r - wk1i + do j = k, l + k - 2, 2 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + x0r = a(j, i) + a(j1, i) + x0i = a(j + 1, i) + a(j1 + 1, i) + x1r = a(j, i) - a(j1, i) + x1i = a(j + 1, i) - a(j1 + 1, i) + x2r = a(j2, i) + a(j3, i) + x2i = a(j2 + 1, i) + a(j3 + 1, i) + x3r = a(j2, i) - a(j3, i) + x3i = a(j2 + 1, i) - a(j3 + 1, i) + a(j, i) = x0r + x2r + a(j + 1, i) = x0i + x2i + x0r = x0r - x2r + x0i = x0i - x2i + a(j2, i) = wk2r * x0r - wk2i * x0i + a(j2 + 1, i) = wk2r * x0i + wk2i * x0r + x0r = x1r - x3i + x0i = x1i + x3r + a(j1, i) = wk1r * x0r - wk1i * x0i + a(j1 + 1, i) = wk1r * x0i + wk1i * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j3, i) = wk3r * x0r - wk3i * x0i + a(j3 + 1, i) = wk3r * x0i + wk3i * x0r + end do + end do + end if + l = m + end do + if (l .lt. n) then + do j = 0, l - 2, 2 + j1 = j + l + x0r = a(j, i) - a(j1, i) + x0i = a(j + 1, i) - a(j1 + 1, i) + a(j, i) = a(j, i) + a(j1, i) + a(j + 1, i) = a(j + 1, i) + a(j1 + 1, i) + a(j1, i) = x0r + a(j1 + 1, i) = x0i + end do + end if + end do + end +! + subroutine cftbcol(n1max, n1, n, a, w) + integer n1max, n1, n, i, j, j1, j2, j3, k, k1, ks, l, m + real*8 a(0 : n1max - 1, 0 : n - 1), w(0 : *) + real*8 wk1r, wk1i, wk2r, wk2i, wk3r, wk3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + l = 1 + do while (2 * l .lt. n) + m = 4 * l + do j = 0, l - 1 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + do i = 0, n1 - 2, 2 + x0r = a(i, j) + a(i, j1) + x0i = a(i + 1, j) + a(i + 1, j1) + x1r = a(i, j) - a(i, j1) + x1i = a(i + 1, j) - a(i + 1, j1) + x2r = a(i, j2) + a(i, j3) + x2i = a(i + 1, j2) + a(i + 1, j3) + x3r = a(i, j2) - a(i, j3) + x3i = a(i + 1, j2) - a(i + 1, j3) + a(i, j) = x0r + x2r + a(i + 1, j) = x0i + x2i + a(i, j2) = x0r - x2r + a(i + 1, j2) = x0i - x2i + a(i, j1) = x1r - x3i + a(i + 1, j1) = x1i + x3r + a(i, j3) = x1r + x3i + a(i + 1, j3) = x1i - x3r + end do + end do + if (m .lt. n) then + wk1r = w(2) + do j = m, l + m - 1 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + do i = 0, n1 - 2, 2 + x0r = a(i, j) + a(i, j1) + x0i = a(i + 1, j) + a(i + 1, j1) + x1r = a(i, j) - a(i, j1) + x1i = a(i + 1, j) - a(i + 1, j1) + x2r = a(i, j2) + a(i, j3) + x2i = a(i + 1, j2) + a(i + 1, j3) + x3r = a(i, j2) - a(i, j3) + x3i = a(i + 1, j2) - a(i + 1, j3) + a(i, j) = x0r + x2r + a(i + 1, j) = x0i + x2i + a(i, j2) = x2i - x0i + a(i + 1, j2) = x0r - x2r + x0r = x1r - x3i + x0i = x1i + x3r + a(i, j1) = wk1r * (x0r - x0i) + a(i + 1, j1) = wk1r * (x0r + x0i) + x0r = x3i + x1r + x0i = x3r - x1i + a(i, j3) = wk1r * (x0i - x0r) + a(i + 1, j3) = wk1r * (x0i + x0r) + end do + end do + k1 = 1 + ks = -1 + do k = 2 * m, n - m, m + k1 = k1 + 1 + ks = -ks + wk1r = w(2 * k1) + wk1i = w(2 * k1 + 1) + wk2r = ks * w(k1) + wk2i = w(k1 + ks) + wk3r = wk1r - 2 * wk2i * wk1i + wk3i = 2 * wk2i * wk1r - wk1i + do j = k, l + k - 1 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + do i = 0, n1 - 2, 2 + x0r = a(i, j) + a(i, j1) + x0i = a(i + 1, j) + a(i + 1, j1) + x1r = a(i, j) - a(i, j1) + x1i = a(i + 1, j) - a(i + 1, j1) + x2r = a(i, j2) + a(i, j3) + x2i = a(i + 1, j2) + a(i + 1, j3) + x3r = a(i, j2) - a(i, j3) + x3i = a(i + 1, j2) - a(i + 1, j3) + a(i, j) = x0r + x2r + a(i + 1, j) = x0i + x2i + x0r = x0r - x2r + x0i = x0i - x2i + a(i, j2) = wk2r * x0r - wk2i * x0i + a(i + 1, j2) = wk2r * x0i + wk2i * x0r + x0r = x1r - x3i + x0i = x1i + x3r + a(i, j1) = wk1r * x0r - wk1i * x0i + a(i + 1, j1) = wk1r * x0i + wk1i * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(i, j3) = wk3r * x0r - wk3i * x0i + a(i + 1, j3) = wk3r * x0i + wk3i * x0r + end do + end do + end do + end if + l = m + end do + if (l .lt. n) then + do j = 0, l - 1 + j1 = j + l + do i = 0, n1 - 2, 2 + x0r = a(i, j) - a(i, j1) + x0i = a(i + 1, j) - a(i + 1, j1) + a(i, j) = a(i, j) + a(i, j1) + a(i + 1, j) = a(i + 1, j) + a(i + 1, j1) + a(i, j1) = x0r + a(i + 1, j1) = x0i + end do + end do + end if + end +! + subroutine cftfrow(n1max, n, n2, a, w) + integer n1max, n, n2, i, j, j1, j2, j3, k, k1, ks, l, m + real*8 a(0 : n1max - 1, 0 : n2 - 1), w(0 : *) + real*8 wk1r, wk1i, wk2r, wk2i, wk3r, wk3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + do i = 0, n2 - 1 + l = 2 + do while (2 * l .lt. n) + m = 4 * l + do j = 0, l - 2, 2 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + x0r = a(j, i) + a(j1, i) + x0i = a(j + 1, i) + a(j1 + 1, i) + x1r = a(j, i) - a(j1, i) + x1i = a(j + 1, i) - a(j1 + 1, i) + x2r = a(j2, i) + a(j3, i) + x2i = a(j2 + 1, i) + a(j3 + 1, i) + x3r = a(j2, i) - a(j3, i) + x3i = a(j2 + 1, i) - a(j3 + 1, i) + a(j, i) = x0r + x2r + a(j + 1, i) = x0i + x2i + a(j2, i) = x0r - x2r + a(j2 + 1, i) = x0i - x2i + a(j1, i) = x1r + x3i + a(j1 + 1, i) = x1i - x3r + a(j3, i) = x1r - x3i + a(j3 + 1, i) = x1i + x3r + end do + if (m .lt. n) then + wk1r = w(2) + do j = m, l + m - 2, 2 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + x0r = a(j, i) + a(j1, i) + x0i = a(j + 1, i) + a(j1 + 1, i) + x1r = a(j, i) - a(j1, i) + x1i = a(j + 1, i) - a(j1 + 1, i) + x2r = a(j2, i) + a(j3, i) + x2i = a(j2 + 1, i) + a(j3 + 1, i) + x3r = a(j2, i) - a(j3, i) + x3i = a(j2 + 1, i) - a(j3 + 1, i) + a(j, i) = x0r + x2r + a(j + 1, i) = x0i + x2i + a(j2, i) = x0i - x2i + a(j2 + 1, i) = x2r - x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j1, i) = wk1r * (x0i + x0r) + a(j1 + 1, i) = wk1r * (x0i - x0r) + x0r = x3i - x1r + x0i = x3r + x1i + a(j3, i) = wk1r * (x0r + x0i) + a(j3 + 1, i) = wk1r * (x0r - x0i) + end do + k1 = 1 + ks = -1 + do k = 2 * m, n - m, m + k1 = k1 + 1 + ks = -ks + wk1r = w(2 * k1) + wk1i = w(2 * k1 + 1) + wk2r = ks * w(k1) + wk2i = w(k1 + ks) + wk3r = wk1r - 2 * wk2i * wk1i + wk3i = 2 * wk2i * wk1r - wk1i + do j = k, l + k - 2, 2 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + x0r = a(j, i) + a(j1, i) + x0i = a(j + 1, i) + a(j1 + 1, i) + x1r = a(j, i) - a(j1, i) + x1i = a(j + 1, i) - a(j1 + 1, i) + x2r = a(j2, i) + a(j3, i) + x2i = a(j2 + 1, i) + a(j3 + 1, i) + x3r = a(j2, i) - a(j3, i) + x3i = a(j2 + 1, i) - a(j3 + 1, i) + a(j, i) = x0r + x2r + a(j + 1, i) = x0i + x2i + x0r = x0r - x2r + x0i = x0i - x2i + a(j2, i) = wk2r * x0r + wk2i * x0i + a(j2 + 1, i) = wk2r * x0i - wk2i * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j1, i) = wk1r * x0r + wk1i * x0i + a(j1 + 1, i) = wk1r * x0i - wk1i * x0r + x0r = x1r - x3i + x0i = x1i + x3r + a(j3, i) = wk3r * x0r + wk3i * x0i + a(j3 + 1, i) = wk3r * x0i - wk3i * x0r + end do + end do + end if + l = m + end do + if (l .lt. n) then + do j = 0, l - 2, 2 + j1 = j + l + x0r = a(j, i) - a(j1, i) + x0i = a(j + 1, i) - a(j1 + 1, i) + a(j, i) = a(j, i) + a(j1, i) + a(j + 1, i) = a(j + 1, i) + a(j1 + 1, i) + a(j1, i) = x0r + a(j1 + 1, i) = x0i + end do + end if + end do + end +! + subroutine cftfcol(n1max, n1, n, a, w) + integer n1max, n1, n, i, j, j1, j2, j3, k, k1, ks, l, m + real*8 a(0 : n1max - 1, 0 : n - 1), w(0 : *) + real*8 wk1r, wk1i, wk2r, wk2i, wk3r, wk3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + l = 1 + do while (2 * l .lt. n) + m = 4 * l + do j = 0, l - 1 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + do i = 0, n1 - 2, 2 + x0r = a(i, j) + a(i, j1) + x0i = a(i + 1, j) + a(i + 1, j1) + x1r = a(i, j) - a(i, j1) + x1i = a(i + 1, j) - a(i + 1, j1) + x2r = a(i, j2) + a(i, j3) + x2i = a(i + 1, j2) + a(i + 1, j3) + x3r = a(i, j2) - a(i, j3) + x3i = a(i + 1, j2) - a(i + 1, j3) + a(i, j) = x0r + x2r + a(i + 1, j) = x0i + x2i + a(i, j2) = x0r - x2r + a(i + 1, j2) = x0i - x2i + a(i, j1) = x1r + x3i + a(i + 1, j1) = x1i - x3r + a(i, j3) = x1r - x3i + a(i + 1, j3) = x1i + x3r + end do + end do + if (m .lt. n) then + wk1r = w(2) + do j = m, l + m - 1 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + do i = 0, n1 - 2, 2 + x0r = a(i, j) + a(i, j1) + x0i = a(i + 1, j) + a(i + 1, j1) + x1r = a(i, j) - a(i, j1) + x1i = a(i + 1, j) - a(i + 1, j1) + x2r = a(i, j2) + a(i, j3) + x2i = a(i + 1, j2) + a(i + 1, j3) + x3r = a(i, j2) - a(i, j3) + x3i = a(i + 1, j2) - a(i + 1, j3) + a(i, j) = x0r + x2r + a(i + 1, j) = x0i + x2i + a(i, j2) = x0i - x2i + a(i + 1, j2) = x2r - x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(i, j1) = wk1r * (x0i + x0r) + a(i + 1, j1) = wk1r * (x0i - x0r) + x0r = x3i - x1r + x0i = x3r + x1i + a(i, j3) = wk1r * (x0r + x0i) + a(i + 1, j3) = wk1r * (x0r - x0i) + end do + end do + k1 = 1 + ks = -1 + do k = 2 * m, n - m, m + k1 = k1 + 1 + ks = -ks + wk1r = w(2 * k1) + wk1i = w(2 * k1 + 1) + wk2r = ks * w(k1) + wk2i = w(k1 + ks) + wk3r = wk1r - 2 * wk2i * wk1i + wk3i = 2 * wk2i * wk1r - wk1i + do j = k, l + k - 1 + j1 = j + l + j2 = j1 + l + j3 = j2 + l + do i = 0, n1 - 2, 2 + x0r = a(i, j) + a(i, j1) + x0i = a(i + 1, j) + a(i + 1, j1) + x1r = a(i, j) - a(i, j1) + x1i = a(i + 1, j) - a(i + 1, j1) + x2r = a(i, j2) + a(i, j3) + x2i = a(i + 1, j2) + a(i + 1, j3) + x3r = a(i, j2) - a(i, j3) + x3i = a(i + 1, j2) - a(i + 1, j3) + a(i, j) = x0r + x2r + a(i + 1, j) = x0i + x2i + x0r = x0r - x2r + x0i = x0i - x2i + a(i, j2) = wk2r * x0r + wk2i * x0i + a(i + 1, j2) = wk2r * x0i - wk2i * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(i, j1) = wk1r * x0r + wk1i * x0i + a(i + 1, j1) = wk1r * x0i - wk1i * x0r + x0r = x1r - x3i + x0i = x1i + x3r + a(i, j3) = wk3r * x0r + wk3i * x0i + a(i + 1, j3) = wk3r * x0i - wk3i * x0r + end do + end do + end do + end if + l = m + end do + if (l .lt. n) then + do j = 0, l - 1 + j1 = j + l + do i = 0, n1 - 2, 2 + x0r = a(i, j) - a(i, j1) + x0i = a(i + 1, j) - a(i + 1, j1) + a(i, j) = a(i, j) + a(i, j1) + a(i + 1, j) = a(i + 1, j) + a(i + 1, j1) + a(i, j1) = x0r + a(i + 1, j1) = x0i + end do + end do + end if + end +! + subroutine rftbrow(n1max, n, n2, a, nc, c) + integer n1max, n, n2, nc, i, j, k, kk, ks + real*8 a(0 : n1max - 1, 0 : n2 - 1), c(0 : nc - 1), + & wkr, wki, xr, xi, yr, yi + ks = 4 * nc / n + do i = 0, n2 - 1 + kk = 0 + do k = n / 2 - 2, 2, -2 + j = n - k + kk = kk + ks + wkr = 0.5d0 - c(kk) + wki = c(nc - kk) + xr = a(k, i) - a(j, i) + xi = a(k + 1, i) + a(j + 1, i) + yr = wkr * xr - wki * xi + yi = wkr * xi + wki * xr + a(k, i) = a(k, i) - yr + a(k + 1, i) = a(k + 1, i) - yi + a(j, i) = a(j, i) + yr + a(j + 1, i) = a(j + 1, i) - yi + end do + end do + end +! + subroutine rftfrow(n1max, n, n2, a, nc, c) + integer n1max, n, n2, nc, i, j, k, kk, ks + real*8 a(0 : n1max - 1, 0 : n2 - 1), c(0 : nc - 1), + & wkr, wki, xr, xi, yr, yi + ks = 4 * nc / n + do i = 0, n2 - 1 + kk = 0 + do k = n / 2 - 2, 2, -2 + j = n - k + kk = kk + ks + wkr = 0.5d0 - c(kk) + wki = c(nc - kk) + xr = a(k, i) - a(j, i) + xi = a(k + 1, i) + a(j + 1, i) + yr = wkr * xr + wki * xi + yi = wkr * xi - wki * xr + a(k, i) = a(k, i) - yr + a(k + 1, i) = a(k + 1, i) - yi + a(j, i) = a(j, i) + yr + a(j + 1, i) = a(j + 1, i) - yi + end do + end do + end +! + subroutine dctbsub(n1max, n1, n2, a, nc, c) + integer n1max, n1, n2, nc, kk1, kk2, ks1, ks2, n2h, j2, + & k1, k2 + real*8 a(0 : n1max - 1, 0 : n2 - 1), c(0 : nc - 1), + & w2r, w2i, wkr, wki, wjr, wji, x0r, x0i, x1r, x1i + ks1 = nc / n1 + ks2 = nc / n2 + n2h = n2 / 2 + kk2 = ks2 + do k2 = 1, n2h - 1 + j2 = n2 - k2 + w2r = 2 * c(kk2) + w2i = 2 * c(nc - kk2) + kk2 = kk2 + ks2 + kk1 = ks1 + do k1 = 2, n1 - 2, 2 + x0r = w2r * c(kk1) + x0i = w2i * c(kk1) + x1r = w2r * c(nc - kk1) + x1i = w2i * c(nc - kk1) + wkr = x0r - x1i + wki = x0i + x1r + wji = x0r + x1i + wjr = x0i - x1r + kk1 = kk1 + ks1 + x0r = wkr * a(k1, k2) - wki * a(k1 + 1, k2) + x0i = wkr * a(k1 + 1, k2) + wki * a(k1, k2) + x1r = wjr * a(k1, j2) - wji * a(k1 + 1, j2) + x1i = wjr * a(k1 + 1, j2) + wji * a(k1, j2) + a(k1, k2) = x0r + x1i + a(k1 + 1, k2) = x0i - x1r + a(k1, j2) = x1r + x0i + a(k1 + 1, j2) = x1i - x0r + end do + wkr = w2r * 0.5d0 + wki = w2i * 0.5d0 + wjr = w2r * c(kk1) + wji = w2i * c(kk1) + x0r = a(0, k2) + a(0, j2) + x0i = a(1, k2) - a(1, j2) + x1r = a(0, k2) - a(0, j2) + x1i = a(1, k2) + a(1, j2) + a(0, k2) = wkr * x0r - wki * x0i + a(1, k2) = wkr * x0i + wki * x0r + a(0, j2) = -wjr * x1r + wji * x1i + a(1, j2) = wjr * x1i + wji * x1r + end do + w2r = 2 * c(kk2) + kk1 = ks1 + do k1 = 2, n1 - 2, 2 + wkr = 2 * c(kk1) + wki = 2 * c(nc - kk1) + wjr = w2r * wkr + wji = w2r * wki + kk1 = kk1 + ks1 + x0i = wkr * a(k1 + 1, 0) + wki * a(k1, 0) + a(k1, 0) = wkr * a(k1, 0) - wki * a(k1 + 1, 0) + a(k1 + 1, 0) = x0i + x0i = wjr * a(k1 + 1, n2h) + wji * a(k1, n2h) + a(k1, n2h) = wjr * a(k1, n2h) - wji * a(k1 + 1, n2h) + a(k1 + 1, n2h) = x0i + end do + a(1, 0) = a(1, 0) * w2r + a(0, n2h) = a(0, n2h) * w2r + a(1, n2h) = a(1, n2h) * 0.5d0 + end +! + subroutine dctfsub(n1max, n1, n2, a, nc, c) + integer n1max, n1, n2, nc, kk1, kk2, ks1, ks2, n2h, j2, + & k1, k2 + real*8 a(0 : n1max - 1, 0 : n2 - 1), c(0 : nc - 1), + & w2r, w2i, wkr, wki, wjr, wji, x0r, x0i, x1r, x1i + ks1 = nc / n1 + ks2 = nc / n2 + n2h = n2 / 2 + kk2 = ks2 + do k2 = 1, n2h - 1 + j2 = n2 - k2 + w2r = 2 * c(kk2) + w2i = 2 * c(nc - kk2) + kk2 = kk2 + ks2 + kk1 = ks1 + do k1 = 2, n1 - 2, 2 + x0r = w2r * c(kk1) + x0i = w2i * c(kk1) + x1r = w2r * c(nc - kk1) + x1i = w2i * c(nc - kk1) + wkr = x0r - x1i + wki = x0i + x1r + wji = x0r + x1i + wjr = x0i - x1r + kk1 = kk1 + ks1 + x0r = a(k1, k2) - a(k1 + 1, j2) + x0i = a(k1, j2) + a(k1 + 1, k2) + x1r = a(k1, j2) - a(k1 + 1, k2) + x1i = a(k1, k2) + a(k1 + 1, j2) + a(k1, k2) = wkr * x0r + wki * x0i + a(k1 + 1, k2) = wkr * x0i - wki * x0r + a(k1, j2) = wjr * x1r + wji * x1i + a(k1 + 1, j2) = wjr * x1i - wji * x1r + end do + x0r = 2 * c(kk1) + wjr = x0r * w2r + wji = x0r * w2i + x0r = w2r * a(0, k2) + w2i * a(1, k2) + x0i = w2r * a(1, k2) - w2i * a(0, k2) + x1r = -wjr * a(0, j2) + wji * a(1, j2) + x1i = wjr * a(1, j2) + wji * a(0, j2) + a(0, k2) = x0r + x1r + a(1, k2) = x1i + x0i + a(0, j2) = x0r - x1r + a(1, j2) = x1i - x0i + end do + w2r = 2 * c(kk2) + kk1 = ks1 + do k1 = 2, n1 - 2, 2 + wkr = 2 * c(kk1) + wki = 2 * c(nc - kk1) + wjr = w2r * wkr + wji = w2r * wki + kk1 = kk1 + ks1 + x0i = wkr * a(k1 + 1, 0) - wki * a(k1, 0) + a(k1, 0) = wkr * a(k1, 0) + wki * a(k1 + 1, 0) + a(k1 + 1, 0) = x0i + x0i = wjr * a(k1 + 1, n2h) - wji * a(k1, n2h) + a(k1, n2h) = wjr * a(k1, n2h) + wji * a(k1 + 1, n2h) + a(k1 + 1, n2h) = x0i + end do + w2r = w2r * 2 + a(0, 0) = a(0, 0) * 2 + a(1, 0) = a(1, 0) * w2r + a(0, n2h) = a(0, n2h) * w2r + end +! + subroutine dstbsub(n1max, n1, n2, a, nc, c) + integer n1max, n1, n2, nc, kk1, kk2, ks1, ks2, n2h, j2, + & k1, k2 + real*8 a(0 : n1max - 1, 0 : n2 - 1), c(0 : nc - 1), + & w2r, w2i, wkr, wki, wjr, wji, x0r, x0i, x1r, x1i + ks1 = nc / n1 + ks2 = nc / n2 + n2h = n2 / 2 + kk2 = ks2 + do k2 = 1, n2h - 1 + j2 = n2 - k2 + w2r = 2 * c(kk2) + w2i = 2 * c(nc - kk2) + kk2 = kk2 + ks2 + kk1 = ks1 + do k1 = 2, n1 - 2, 2 + x0r = w2r * c(kk1) + x0i = w2i * c(kk1) + x1r = w2r * c(nc - kk1) + x1i = w2i * c(nc - kk1) + wkr = x0r - x1i + wki = x0i + x1r + wji = x0r + x1i + wjr = x0i - x1r + kk1 = kk1 + ks1 + x0r = wkr * a(k1, k2) - wki * a(k1 + 1, k2) + x0i = wkr * a(k1 + 1, k2) + wki * a(k1, k2) + x1r = wjr * a(k1, j2) - wji * a(k1 + 1, j2) + x1i = wjr * a(k1 + 1, j2) + wji * a(k1, j2) + a(k1, k2) = x1i - x0r + a(k1 + 1, k2) = x1r + x0i + a(k1, j2) = x0i - x1r + a(k1 + 1, j2) = x0r + x1i + end do + wkr = w2r * 0.5d0 + wki = w2i * 0.5d0 + wjr = w2r * c(kk1) + wji = w2i * c(kk1) + x0r = a(0, k2) + a(0, j2) + x0i = a(1, k2) - a(1, j2) + x1r = a(0, k2) - a(0, j2) + x1i = a(1, k2) + a(1, j2) + a(1, k2) = wkr * x0r - wki * x0i + a(0, k2) = wkr * x0i + wki * x0r + a(1, j2) = -wjr * x1r + wji * x1i + a(0, j2) = wjr * x1i + wji * x1r + end do + w2r = 2 * c(kk2) + kk1 = ks1 + do k1 = 2, n1 - 2, 2 + wkr = 2 * c(kk1) + wki = 2 * c(nc - kk1) + wjr = w2r * wkr + wji = w2r * wki + kk1 = kk1 + ks1 + x0i = wkr * a(k1 + 1, 0) + wki * a(k1, 0) + a(k1 + 1, 0) = wkr * a(k1, 0) - wki * a(k1 + 1, 0) + a(k1, 0) = x0i + x0i = wjr * a(k1 + 1, n2h) + wji * a(k1, n2h) + a(k1 + 1, n2h) = wjr * a(k1, n2h) - wji * a(k1 + 1, n2h) + a(k1, n2h) = x0i + end do + a(1, 0) = a(1, 0) * w2r + a(0, n2h) = a(0, n2h) * w2r + a(1, n2h) = a(1, n2h) * 0.5d0 + end +! + subroutine dstfsub(n1max, n1, n2, a, nc, c) + integer n1max, n1, n2, nc, kk1, kk2, ks1, ks2, n2h, j2, + & k1, k2 + real*8 a(0 : n1max - 1, 0 : n2 - 1), c(0 : nc - 1), + & w2r, w2i, wkr, wki, wjr, wji, x0r, x0i, x1r, x1i + ks1 = nc / n1 + ks2 = nc / n2 + n2h = n2 / 2 + kk2 = ks2 + do k2 = 1, n2h - 1 + j2 = n2 - k2 + w2r = 2 * c(kk2) + w2i = 2 * c(nc - kk2) + kk2 = kk2 + ks2 + kk1 = ks1 + do k1 = 2, n1 - 2, 2 + x0r = w2r * c(kk1) + x0i = w2i * c(kk1) + x1r = w2r * c(nc - kk1) + x1i = w2i * c(nc - kk1) + wkr = x0r - x1i + wki = x0i + x1r + wji = x0r + x1i + wjr = x0i - x1r + kk1 = kk1 + ks1 + x0r = a(k1 + 1, j2) - a(k1, k2) + x0i = a(k1 + 1, k2) + a(k1, j2) + x1r = a(k1 + 1, k2) - a(k1, j2) + x1i = a(k1 + 1, j2) + a(k1, k2) + a(k1, k2) = wkr * x0r + wki * x0i + a(k1 + 1, k2) = wkr * x0i - wki * x0r + a(k1, j2) = wjr * x1r + wji * x1i + a(k1 + 1, j2) = wjr * x1i - wji * x1r + end do + x0r = 2 * c(kk1) + wjr = x0r * w2r + wji = x0r * w2i + x0r = w2r * a(1, k2) + w2i * a(0, k2) + x0i = w2r * a(0, k2) - w2i * a(1, k2) + x1r = -wjr * a(1, j2) + wji * a(0, j2) + x1i = wjr * a(0, j2) + wji * a(1, j2) + a(0, k2) = x0r + x1r + a(1, k2) = x1i + x0i + a(0, j2) = x0r - x1r + a(1, j2) = x1i - x0i + end do + w2r = 2 * c(kk2) + kk1 = ks1 + do k1 = 2, n1 - 2, 2 + wkr = 2 * c(kk1) + wki = 2 * c(nc - kk1) + wjr = w2r * wkr + wji = w2r * wki + kk1 = kk1 + ks1 + x0i = wkr * a(k1, 0) - wki * a(k1 + 1, 0) + a(k1, 0) = wkr * a(k1 + 1, 0) + wki * a(k1, 0) + a(k1 + 1, 0) = x0i + x0i = wjr * a(k1, n2h) - wji * a(k1 + 1, n2h) + a(k1, n2h) = wjr * a(k1 + 1, n2h) + wji * a(k1, n2h) + a(k1 + 1, n2h) = x0i + end do + w2r = w2r * 2 + a(0, 0) = a(0, 0) * 2 + a(1, 0) = a(1, 0) * w2r + a(0, n2h) = a(0, n2h) * w2r + end +!
diff --git a/third_party/tensorflow_dependencies/fft2d/fftsg.c b/third_party/tensorflow_dependencies/fft2d/fftsg.c new file mode 100644 index 0000000..43d7534 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/fftsg.c
@@ -0,0 +1,3314 @@ +/* +Fast Fourier/Cosine/Sine Transform + dimension :one + data length :power of 2 + decimation :frequency + radix :split-radix + data :inplace + table :use +functions + cdft: Complex Discrete Fourier Transform + rdft: Real Discrete Fourier Transform + ddct: Discrete Cosine Transform + ddst: Discrete Sine Transform + dfct: Cosine Transform of RDFT (Real Symmetric DFT) + dfst: Sine Transform of RDFT (Real Anti-symmetric DFT) +function prototypes + void cdft(int, int, double *, int *, double *); + void rdft(int, int, double *, int *, double *); + void ddct(int, int, double *, int *, double *); + void ddst(int, int, double *, int *, double *); + void dfct(int, double *, double *, int *, double *); + void dfst(int, double *, double *, int *, double *); +macro definitions + USE_CDFT_PTHREADS : default=not defined + CDFT_THREADS_BEGIN_N : must be >= 512, default=8192 + CDFT_4THREADS_BEGIN_N : must be >= 512, default=65536 + USE_CDFT_WINTHREADS : default=not defined + CDFT_THREADS_BEGIN_N : must be >= 512, default=32768 + CDFT_4THREADS_BEGIN_N : must be >= 512, default=524288 + + +-------- Complex DFT (Discrete Fourier Transform) -------- + [definition] + <case1> + X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n + <case2> + X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n + (notes: sum_j=0^n-1 is a summation from j=0 to n-1) + [usage] + <case1> + ip[0] = 0; // first time only + cdft(2*n, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + cdft(2*n, -1, a, ip, w); + [parameters] + 2*n :data length (int) + n >= 1, n = power of 2 + a[0...2*n-1] :input/output data (double *) + input data + a[2*j] = Re(x[j]), + a[2*j+1] = Im(x[j]), 0<=j<n + output data + a[2*k] = Re(X[k]), + a[2*k+1] = Im(X[k]), 0<=k<n + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + strictly, + length of ip >= + 2+(1<<(int)(log(n+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n/2-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + cdft(2*n, -1, a, ip, w); + is + cdft(2*n, 1, a, ip, w); + for (j = 0; j <= 2 * n - 1; j++) { + a[j] *= 1.0 / n; + } + . + + +-------- Real DFT / Inverse of Real DFT -------- + [definition] + <case1> RDFT + R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2 + I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2 + <case2> IRDFT (excluding scale) + a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + + sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + + sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n + [usage] + <case1> + ip[0] = 0; // first time only + rdft(n, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + rdft(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + <case1> + output data + a[2*k] = R[k], 0<=k<n/2 + a[2*k+1] = I[k], 0<k<n/2 + a[1] = R[n/2] + <case2> + input data + a[2*j] = R[j], 0<=j<n/2 + a[2*j+1] = I[j], 0<j<n/2 + a[1] = R[n/2] + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n/2-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + rdft(n, 1, a, ip, w); + is + rdft(n, -1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + <case1> IDCT (excluding scale) + C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n + <case2> DCT + C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n + [usage] + <case1> + ip[0] = 0; // first time only + ddct(n, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + ddct(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + output data + a[k] = C[k], 0<=k<n + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/4-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddct(n, -1, a, ip, w); + is + a[0] *= 0.5; + ddct(n, 1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- DST (Discrete Sine Transform) / Inverse of DST -------- + [definition] + <case1> IDST (excluding scale) + S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n + <case2> DST + S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n + [usage] + <case1> + ip[0] = 0; // first time only + ddst(n, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + ddst(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + <case1> + input data + a[j] = A[j], 0<j<n + a[0] = A[n] + output data + a[k] = S[k], 0<=k<n + <case2> + output data + a[k] = S[k], 0<k<n + a[0] = S[n] + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/4-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddst(n, -1, a, ip, w); + is + a[0] *= 0.5; + ddst(n, 1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- Cosine Transform of RDFT (Real Symmetric DFT) -------- + [definition] + C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n + [usage] + ip[0] = 0; // first time only + dfct(n, a, t, ip, w); + [parameters] + n :data length - 1 (int) + n >= 2, n = power of 2 + a[0...n] :input/output data (double *) + output data + a[k] = C[k], 0<=k<=n + t[0...n/2] :work area (double *) + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/4) + strictly, + length of ip >= + 2+(1<<(int)(log(n/4+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/8-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + a[0] *= 0.5; + a[n] *= 0.5; + dfct(n, a, t, ip, w); + is + a[0] *= 0.5; + a[n] *= 0.5; + dfct(n, a, t, ip, w); + for (j = 0; j <= n; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- Sine Transform of RDFT (Real Anti-symmetric DFT) -------- + [definition] + S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n + [usage] + ip[0] = 0; // first time only + dfst(n, a, t, ip, w); + [parameters] + n :data length + 1 (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + output data + a[k] = S[k], 0<k<n + (a[0] is used for work area) + t[0...n/2-1] :work area (double *) + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/4) + strictly, + length of ip >= + 2+(1<<(int)(log(n/4+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/8-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + dfst(n, a, t, ip, w); + is + dfst(n, a, t, ip, w); + for (j = 1; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +Appendix : + The cos/sin table is recalculated when the larger table required. + w[] and ip[] are compatible with all routines. +*/ + + +void cdft(int n, int isgn, double *a, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void cftfsub(int n, double *a, int *ip, int nw, double *w); + void cftbsub(int n, double *a, int *ip, int nw, double *w); + int nw; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + if (isgn >= 0) { + cftfsub(n, a, ip, nw, w); + } else { + cftbsub(n, a, ip, nw, w); + } +} + + +void rdft(int n, int isgn, double *a, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void cftfsub(int n, double *a, int *ip, int nw, double *w); + void cftbsub(int n, double *a, int *ip, int nw, double *w); + void rftfsub(int n, double *a, int nc, double *c); + void rftbsub(int n, double *a, int nc, double *c); + int nw, nc; + double xi; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 2)) { + nc = n >> 2; + makect(nc, ip, w + nw); + } + if (isgn >= 0) { + if (n > 4) { + cftfsub(n, a, ip, nw, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, ip, nw, w); + } + xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; + } else { + a[1] = 0.5 * (a[0] - a[1]); + a[0] -= a[1]; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + cftbsub(n, a, ip, nw, w); + } else if (n == 4) { + cftbsub(n, a, ip, nw, w); + } + } +} + + +void ddct(int n, int isgn, double *a, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void cftfsub(int n, double *a, int *ip, int nw, double *w); + void cftbsub(int n, double *a, int *ip, int nw, double *w); + void rftfsub(int n, double *a, int nc, double *c); + void rftbsub(int n, double *a, int nc, double *c); + void dctsub(int n, double *a, int nc, double *c); + int j, nw, nc; + double xr; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + if (isgn < 0) { + xr = a[n - 1]; + for (j = n - 2; j >= 2; j -= 2) { + a[j + 1] = a[j] - a[j - 1]; + a[j] += a[j - 1]; + } + a[1] = a[0] - xr; + a[0] += xr; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + cftbsub(n, a, ip, nw, w); + } else if (n == 4) { + cftbsub(n, a, ip, nw, w); + } + } + dctsub(n, a, nc, w + nw); + if (isgn >= 0) { + if (n > 4) { + cftfsub(n, a, ip, nw, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, ip, nw, w); + } + xr = a[0] - a[1]; + a[0] += a[1]; + for (j = 2; j < n; j += 2) { + a[j - 1] = a[j] - a[j + 1]; + a[j] += a[j + 1]; + } + a[n - 1] = xr; + } +} + + +void ddst(int n, int isgn, double *a, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void cftfsub(int n, double *a, int *ip, int nw, double *w); + void cftbsub(int n, double *a, int *ip, int nw, double *w); + void rftfsub(int n, double *a, int nc, double *c); + void rftbsub(int n, double *a, int nc, double *c); + void dstsub(int n, double *a, int nc, double *c); + int j, nw, nc; + double xr; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + if (isgn < 0) { + xr = a[n - 1]; + for (j = n - 2; j >= 2; j -= 2) { + a[j + 1] = -a[j] - a[j - 1]; + a[j] -= a[j - 1]; + } + a[1] = a[0] + xr; + a[0] -= xr; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + cftbsub(n, a, ip, nw, w); + } else if (n == 4) { + cftbsub(n, a, ip, nw, w); + } + } + dstsub(n, a, nc, w + nw); + if (isgn >= 0) { + if (n > 4) { + cftfsub(n, a, ip, nw, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, ip, nw, w); + } + xr = a[0] - a[1]; + a[0] += a[1]; + for (j = 2; j < n; j += 2) { + a[j - 1] = -a[j] - a[j + 1]; + a[j] -= a[j + 1]; + } + a[n - 1] = -xr; + } +} + + +void dfct(int n, double *a, double *t, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void cftfsub(int n, double *a, int *ip, int nw, double *w); + void rftfsub(int n, double *a, int nc, double *c); + void dctsub(int n, double *a, int nc, double *c); + int j, k, l, m, mh, nw, nc; + double xr, xi, yr, yi; + + nw = ip[0]; + if (n > (nw << 3)) { + nw = n >> 3; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 1)) { + nc = n >> 1; + makect(nc, ip, w + nw); + } + m = n >> 1; + yi = a[m]; + xi = a[0] + a[n]; + a[0] -= a[n]; + t[0] = xi - yi; + t[m] = xi + yi; + if (n > 2) { + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + xr = a[j] - a[n - j]; + xi = a[j] + a[n - j]; + yr = a[k] - a[n - k]; + yi = a[k] + a[n - k]; + a[j] = xr; + a[k] = yr; + t[j] = xi - yi; + t[k] = xi + yi; + } + t[mh] = a[mh] + a[n - mh]; + a[mh] -= a[n - mh]; + dctsub(m, a, nc, w + nw); + if (m > 4) { + cftfsub(m, a, ip, nw, w); + rftfsub(m, a, nc, w + nw); + } else if (m == 4) { + cftfsub(m, a, ip, nw, w); + } + a[n - 1] = a[0] - a[1]; + a[1] = a[0] + a[1]; + for (j = m - 2; j >= 2; j -= 2) { + a[2 * j + 1] = a[j] + a[j + 1]; + a[2 * j - 1] = a[j] - a[j + 1]; + } + l = 2; + m = mh; + while (m >= 2) { + dctsub(m, t, nc, w + nw); + if (m > 4) { + cftfsub(m, t, ip, nw, w); + rftfsub(m, t, nc, w + nw); + } else if (m == 4) { + cftfsub(m, t, ip, nw, w); + } + a[n - l] = t[0] - t[1]; + a[l] = t[0] + t[1]; + k = 0; + for (j = 2; j < m; j += 2) { + k += l << 2; + a[k - l] = t[j] - t[j + 1]; + a[k + l] = t[j] + t[j + 1]; + } + l <<= 1; + mh = m >> 1; + for (j = 0; j < mh; j++) { + k = m - j; + t[j] = t[m + k] - t[m + j]; + t[k] = t[m + k] + t[m + j]; + } + t[mh] = t[m + mh]; + m = mh; + } + a[l] = t[0]; + a[n] = t[2] - t[1]; + a[0] = t[2] + t[1]; + } else { + a[1] = a[0]; + a[2] = t[0]; + a[0] = t[1]; + } +} + + +void dfst(int n, double *a, double *t, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void cftfsub(int n, double *a, int *ip, int nw, double *w); + void rftfsub(int n, double *a, int nc, double *c); + void dstsub(int n, double *a, int nc, double *c); + int j, k, l, m, mh, nw, nc; + double xr, xi, yr, yi; + + nw = ip[0]; + if (n > (nw << 3)) { + nw = n >> 3; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 1)) { + nc = n >> 1; + makect(nc, ip, w + nw); + } + if (n > 2) { + m = n >> 1; + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + xr = a[j] + a[n - j]; + xi = a[j] - a[n - j]; + yr = a[k] + a[n - k]; + yi = a[k] - a[n - k]; + a[j] = xr; + a[k] = yr; + t[j] = xi + yi; + t[k] = xi - yi; + } + t[0] = a[mh] - a[n - mh]; + a[mh] += a[n - mh]; + a[0] = a[m]; + dstsub(m, a, nc, w + nw); + if (m > 4) { + cftfsub(m, a, ip, nw, w); + rftfsub(m, a, nc, w + nw); + } else if (m == 4) { + cftfsub(m, a, ip, nw, w); + } + a[n - 1] = a[1] - a[0]; + a[1] = a[0] + a[1]; + for (j = m - 2; j >= 2; j -= 2) { + a[2 * j + 1] = a[j] - a[j + 1]; + a[2 * j - 1] = -a[j] - a[j + 1]; + } + l = 2; + m = mh; + while (m >= 2) { + dstsub(m, t, nc, w + nw); + if (m > 4) { + cftfsub(m, t, ip, nw, w); + rftfsub(m, t, nc, w + nw); + } else if (m == 4) { + cftfsub(m, t, ip, nw, w); + } + a[n - l] = t[1] - t[0]; + a[l] = t[0] + t[1]; + k = 0; + for (j = 2; j < m; j += 2) { + k += l << 2; + a[k - l] = -t[j] - t[j + 1]; + a[k + l] = t[j] - t[j + 1]; + } + l <<= 1; + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + t[j] = t[m + k] + t[m + j]; + t[k] = t[m + k] - t[m + j]; + } + t[0] = t[m + mh]; + m = mh; + } + a[l] = t[0]; + } + a[0] = 0; +} + + +/* -------- initializing routines -------- */ + + +#include <math.h> + +void makewt(int nw, int *ip, double *w) +{ + void makeipt(int nw, int *ip); + int j, nwh, nw0, nw1; + double delta, wn4r, wk1r, wk1i, wk3r, wk3i; + + ip[0] = nw; + ip[1] = 1; + if (nw > 2) { + nwh = nw >> 1; + delta = atan(1.0) / nwh; + wn4r = cos(delta * nwh); + w[0] = 1; + w[1] = wn4r; + if (nwh == 4) { + w[2] = cos(delta * 2); + w[3] = sin(delta * 2); + } else if (nwh > 4) { + makeipt(nw, ip); + w[2] = 0.5 / cos(delta * 2); + w[3] = 0.5 / cos(delta * 6); + for (j = 4; j < nwh; j += 4) { + w[j] = cos(delta * j); + w[j + 1] = sin(delta * j); + w[j + 2] = cos(3 * delta * j); + w[j + 3] = -sin(3 * delta * j); + } + } + nw0 = 0; + while (nwh > 2) { + nw1 = nw0 + nwh; + nwh >>= 1; + w[nw1] = 1; + w[nw1 + 1] = wn4r; + if (nwh == 4) { + wk1r = w[nw0 + 4]; + wk1i = w[nw0 + 5]; + w[nw1 + 2] = wk1r; + w[nw1 + 3] = wk1i; + } else if (nwh > 4) { + wk1r = w[nw0 + 4]; + wk3r = w[nw0 + 6]; + w[nw1 + 2] = 0.5 / wk1r; + w[nw1 + 3] = 0.5 / wk3r; + for (j = 4; j < nwh; j += 4) { + wk1r = w[nw0 + 2 * j]; + wk1i = w[nw0 + 2 * j + 1]; + wk3r = w[nw0 + 2 * j + 2]; + wk3i = w[nw0 + 2 * j + 3]; + w[nw1 + j] = wk1r; + w[nw1 + j + 1] = wk1i; + w[nw1 + j + 2] = wk3r; + w[nw1 + j + 3] = wk3i; + } + } + nw0 = nw1; + } + } +} + + +void makeipt(int nw, int *ip) +{ + int j, l, m, m2, p, q; + + ip[2] = 0; + ip[3] = 16; + m = 2; + for (l = nw; l > 32; l >>= 2) { + m2 = m << 1; + q = m2 << 3; + for (j = m; j < m2; j++) { + p = ip[j] << 2; + ip[m + j] = p; + ip[m2 + j] = p + q; + } + m = m2; + } +} + + +void makect(int nc, int *ip, double *c) +{ + int j, nch; + double delta; + + ip[1] = nc; + if (nc > 1) { + nch = nc >> 1; + delta = atan(1.0) / nch; + c[0] = cos(delta * nch); + c[nch] = 0.5 * c[0]; + for (j = 1; j < nch; j++) { + c[j] = 0.5 * cos(delta * j); + c[nc - j] = 0.5 * sin(delta * j); + } + } +} + + +/* -------- child routines -------- */ + + +#ifdef USE_CDFT_PTHREADS +#define USE_CDFT_THREADS +#ifndef CDFT_THREADS_BEGIN_N +#define CDFT_THREADS_BEGIN_N 8192 +#endif +#ifndef CDFT_4THREADS_BEGIN_N +#define CDFT_4THREADS_BEGIN_N 65536 +#endif +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#define cdft_thread_t pthread_t +#define cdft_thread_create(thp,func,argp) { \ + if (pthread_create(thp, NULL, func, (void *) argp) != 0) { \ + fprintf(stderr, "cdft thread error\n"); \ + exit(1); \ + } \ +} +#define cdft_thread_wait(th) { \ + if (pthread_join(th, NULL) != 0) { \ + fprintf(stderr, "cdft thread error\n"); \ + exit(1); \ + } \ +} +#endif /* USE_CDFT_PTHREADS */ + + +#ifdef USE_CDFT_WINTHREADS +#define USE_CDFT_THREADS +#ifndef CDFT_THREADS_BEGIN_N +#define CDFT_THREADS_BEGIN_N 32768 +#endif +#ifndef CDFT_4THREADS_BEGIN_N +#define CDFT_4THREADS_BEGIN_N 524288 +#endif +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#define cdft_thread_t HANDLE +#define cdft_thread_create(thp,func,argp) { \ + DWORD thid; \ + *(thp) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, (LPVOID) argp, 0, &thid); \ + if (*(thp) == 0) { \ + fprintf(stderr, "cdft thread error\n"); \ + exit(1); \ + } \ +} +#define cdft_thread_wait(th) { \ + WaitForSingleObject(th, INFINITE); \ + CloseHandle(th); \ +} +#endif /* USE_CDFT_WINTHREADS */ + + +void cftfsub(int n, double *a, int *ip, int nw, double *w) +{ + void bitrv2(int n, int *ip, double *a); + void bitrv216(double *a); + void bitrv208(double *a); + void cftf1st(int n, double *a, double *w); + void cftrec4(int n, double *a, int nw, double *w); + void cftleaf(int n, int isplt, double *a, int nw, double *w); + void cftfx41(int n, double *a, int nw, double *w); + void cftf161(double *a, double *w); + void cftf081(double *a, double *w); + void cftf040(double *a); + void cftx020(double *a); +#ifdef USE_CDFT_THREADS + void cftrec4_th(int n, double *a, int nw, double *w); +#endif /* USE_CDFT_THREADS */ + + if (n > 8) { + if (n > 32) { + cftf1st(n, a, &w[nw - (n >> 2)]); +#ifdef USE_CDFT_THREADS + if (n > CDFT_THREADS_BEGIN_N) { + cftrec4_th(n, a, nw, w); + } else +#endif /* USE_CDFT_THREADS */ + if (n > 512) { + cftrec4(n, a, nw, w); + } else if (n > 128) { + cftleaf(n, 1, a, nw, w); + } else { + cftfx41(n, a, nw, w); + } + bitrv2(n, ip, a); + } else if (n == 32) { + cftf161(a, &w[nw - 8]); + bitrv216(a); + } else { + cftf081(a, w); + bitrv208(a); + } + } else if (n == 8) { + cftf040(a); + } else if (n == 4) { + cftx020(a); + } +} + + +void cftbsub(int n, double *a, int *ip, int nw, double *w) +{ + void bitrv2conj(int n, int *ip, double *a); + void bitrv216neg(double *a); + void bitrv208neg(double *a); + void cftb1st(int n, double *a, double *w); + void cftrec4(int n, double *a, int nw, double *w); + void cftleaf(int n, int isplt, double *a, int nw, double *w); + void cftfx41(int n, double *a, int nw, double *w); + void cftf161(double *a, double *w); + void cftf081(double *a, double *w); + void cftb040(double *a); + void cftx020(double *a); +#ifdef USE_CDFT_THREADS + void cftrec4_th(int n, double *a, int nw, double *w); +#endif /* USE_CDFT_THREADS */ + + if (n > 8) { + if (n > 32) { + cftb1st(n, a, &w[nw - (n >> 2)]); +#ifdef USE_CDFT_THREADS + if (n > CDFT_THREADS_BEGIN_N) { + cftrec4_th(n, a, nw, w); + } else +#endif /* USE_CDFT_THREADS */ + if (n > 512) { + cftrec4(n, a, nw, w); + } else if (n > 128) { + cftleaf(n, 1, a, nw, w); + } else { + cftfx41(n, a, nw, w); + } + bitrv2conj(n, ip, a); + } else if (n == 32) { + cftf161(a, &w[nw - 8]); + bitrv216neg(a); + } else { + cftf081(a, w); + bitrv208neg(a); + } + } else if (n == 8) { + cftb040(a); + } else if (n == 4) { + cftx020(a); + } +} + + +void bitrv2(int n, int *ip, double *a) +{ + int j, j1, k, k1, l, m, nh, nm; + double xr, xi, yr, yi; + + m = 1; + for (l = n >> 2; l > 8; l >>= 2) { + m <<= 1; + } + nh = n >> 1; + nm = 4 * m; + if (l == 8) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 4 * j + 2 * ip[m + k]; + k1 = 4 * k + 2 * ip[m + j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 -= nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh; + k1 += 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 += nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += 2; + k1 += nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 -= nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh; + k1 -= 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 += nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + k1 = 4 * k + 2 * ip[m + k]; + j1 = k1 + 2; + k1 += nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 -= nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= 2; + k1 -= nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh + 2; + k1 += nh + 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh - nm; + k1 += 2 * nm - 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } else { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 4 * j + ip[m + k]; + k1 = 4 * k + ip[m + j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh; + k1 += 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += 2; + k1 += nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh; + k1 -= 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + k1 = 4 * k + ip[m + k]; + j1 = k1 + 2; + k1 += nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += nm; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } +} + + +void bitrv2conj(int n, int *ip, double *a) +{ + int j, j1, k, k1, l, m, nh, nm; + double xr, xi, yr, yi; + + m = 1; + for (l = n >> 2; l > 8; l >>= 2) { + m <<= 1; + } + nh = n >> 1; + nm = 4 * m; + if (l == 8) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 4 * j + 2 * ip[m + k]; + k1 = 4 * k + 2 * ip[m + j]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 -= nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh; + k1 += 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 += nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += 2; + k1 += nh; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 -= nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh; + k1 -= 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 += nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + k1 = 4 * k + 2 * ip[m + k]; + j1 = k1 + 2; + k1 += nh; + a[j1 - 1] = -a[j1 - 1]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + a[k1 + 3] = -a[k1 + 3]; + j1 += nm; + k1 += 2 * nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 -= nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= 2; + k1 -= nh; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh + 2; + k1 += nh + 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh - nm; + k1 += 2 * nm - 2; + a[j1 - 1] = -a[j1 - 1]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + a[k1 + 3] = -a[k1 + 3]; + } + } else { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 4 * j + ip[m + k]; + k1 = 4 * k + ip[m + j]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh; + k1 += 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += 2; + k1 += nh; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nm; + k1 += nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh; + k1 -= 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nm; + k1 -= nm; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + k1 = 4 * k + ip[m + k]; + j1 = k1 + 2; + k1 += nh; + a[j1 - 1] = -a[j1 - 1]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + a[k1 + 3] = -a[k1 + 3]; + j1 += nm; + k1 += nm; + a[j1 - 1] = -a[j1 - 1]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + a[k1 + 3] = -a[k1 + 3]; + } + } +} + + +void bitrv216(double *a) +{ + double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, + x5r, x5i, x7r, x7i, x8r, x8i, x10r, x10i, + x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i; + + x1r = a[2]; + x1i = a[3]; + x2r = a[4]; + x2i = a[5]; + x3r = a[6]; + x3i = a[7]; + x4r = a[8]; + x4i = a[9]; + x5r = a[10]; + x5i = a[11]; + x7r = a[14]; + x7i = a[15]; + x8r = a[16]; + x8i = a[17]; + x10r = a[20]; + x10i = a[21]; + x11r = a[22]; + x11i = a[23]; + x12r = a[24]; + x12i = a[25]; + x13r = a[26]; + x13i = a[27]; + x14r = a[28]; + x14i = a[29]; + a[2] = x8r; + a[3] = x8i; + a[4] = x4r; + a[5] = x4i; + a[6] = x12r; + a[7] = x12i; + a[8] = x2r; + a[9] = x2i; + a[10] = x10r; + a[11] = x10i; + a[14] = x14r; + a[15] = x14i; + a[16] = x1r; + a[17] = x1i; + a[20] = x5r; + a[21] = x5i; + a[22] = x13r; + a[23] = x13i; + a[24] = x3r; + a[25] = x3i; + a[26] = x11r; + a[27] = x11i; + a[28] = x7r; + a[29] = x7i; +} + + +void bitrv216neg(double *a) +{ + double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, + x5r, x5i, x6r, x6i, x7r, x7i, x8r, x8i, + x9r, x9i, x10r, x10i, x11r, x11i, x12r, x12i, + x13r, x13i, x14r, x14i, x15r, x15i; + + x1r = a[2]; + x1i = a[3]; + x2r = a[4]; + x2i = a[5]; + x3r = a[6]; + x3i = a[7]; + x4r = a[8]; + x4i = a[9]; + x5r = a[10]; + x5i = a[11]; + x6r = a[12]; + x6i = a[13]; + x7r = a[14]; + x7i = a[15]; + x8r = a[16]; + x8i = a[17]; + x9r = a[18]; + x9i = a[19]; + x10r = a[20]; + x10i = a[21]; + x11r = a[22]; + x11i = a[23]; + x12r = a[24]; + x12i = a[25]; + x13r = a[26]; + x13i = a[27]; + x14r = a[28]; + x14i = a[29]; + x15r = a[30]; + x15i = a[31]; + a[2] = x15r; + a[3] = x15i; + a[4] = x7r; + a[5] = x7i; + a[6] = x11r; + a[7] = x11i; + a[8] = x3r; + a[9] = x3i; + a[10] = x13r; + a[11] = x13i; + a[12] = x5r; + a[13] = x5i; + a[14] = x9r; + a[15] = x9i; + a[16] = x1r; + a[17] = x1i; + a[18] = x14r; + a[19] = x14i; + a[20] = x6r; + a[21] = x6i; + a[22] = x10r; + a[23] = x10i; + a[24] = x2r; + a[25] = x2i; + a[26] = x12r; + a[27] = x12i; + a[28] = x4r; + a[29] = x4i; + a[30] = x8r; + a[31] = x8i; +} + + +void bitrv208(double *a) +{ + double x1r, x1i, x3r, x3i, x4r, x4i, x6r, x6i; + + x1r = a[2]; + x1i = a[3]; + x3r = a[6]; + x3i = a[7]; + x4r = a[8]; + x4i = a[9]; + x6r = a[12]; + x6i = a[13]; + a[2] = x4r; + a[3] = x4i; + a[6] = x6r; + a[7] = x6i; + a[8] = x1r; + a[9] = x1i; + a[12] = x3r; + a[13] = x3i; +} + + +void bitrv208neg(double *a) +{ + double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, + x5r, x5i, x6r, x6i, x7r, x7i; + + x1r = a[2]; + x1i = a[3]; + x2r = a[4]; + x2i = a[5]; + x3r = a[6]; + x3i = a[7]; + x4r = a[8]; + x4i = a[9]; + x5r = a[10]; + x5i = a[11]; + x6r = a[12]; + x6i = a[13]; + x7r = a[14]; + x7i = a[15]; + a[2] = x7r; + a[3] = x7i; + a[4] = x3r; + a[5] = x3i; + a[6] = x5r; + a[7] = x5i; + a[8] = x1r; + a[9] = x1i; + a[10] = x6r; + a[11] = x6i; + a[12] = x2r; + a[13] = x2i; + a[14] = x4r; + a[15] = x4i; +} + + +void cftf1st(int n, double *a, double *w) +{ + int j, j0, j1, j2, j3, k, m, mh; + double wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i, + wd1r, wd1i, wd3r, wd3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i; + + mh = n >> 3; + m = 2 * mh; + j1 = m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[0] + a[j2]; + x0i = a[1] + a[j2 + 1]; + x1r = a[0] - a[j2]; + x1i = a[1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + a[j2] = x1r - x3i; + a[j2 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + wn4r = w[1]; + csc1 = w[2]; + csc3 = w[3]; + wd1r = 1; + wd1i = 0; + wd3r = 1; + wd3i = 0; + k = 0; + for (j = 2; j < mh - 2; j += 4) { + k += 4; + wk1r = csc1 * (wd1r + w[k]); + wk1i = csc1 * (wd1i + w[k + 1]); + wk3r = csc3 * (wd3r + w[k + 2]); + wk3i = csc3 * (wd3i + w[k + 3]); + wd1r = w[k]; + wd1i = w[k + 1]; + wd3r = w[k + 2]; + wd3i = w[k + 3]; + j1 = j + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j] + a[j2]; + x0i = a[j + 1] + a[j2 + 1]; + x1r = a[j] - a[j2]; + x1i = a[j + 1] - a[j2 + 1]; + y0r = a[j + 2] + a[j2 + 2]; + y0i = a[j + 3] + a[j2 + 3]; + y1r = a[j + 2] - a[j2 + 2]; + y1i = a[j + 3] - a[j2 + 3]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + y2r = a[j1 + 2] + a[j3 + 2]; + y2i = a[j1 + 3] + a[j3 + 3]; + y3r = a[j1 + 2] - a[j3 + 2]; + y3i = a[j1 + 3] - a[j3 + 3]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j + 2] = y0r + y2r; + a[j + 3] = y0i + y2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + a[j1 + 2] = y0r - y2r; + a[j1 + 3] = y0i - y2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = wk1r * x0r - wk1i * x0i; + a[j2 + 1] = wk1r * x0i + wk1i * x0r; + x0r = y1r - y3i; + x0i = y1i + y3r; + a[j2 + 2] = wd1r * x0r - wd1i * x0i; + a[j2 + 3] = wd1r * x0i + wd1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r + wk3i * x0i; + a[j3 + 1] = wk3r * x0i - wk3i * x0r; + x0r = y1r + y3i; + x0i = y1i - y3r; + a[j3 + 2] = wd3r * x0r + wd3i * x0i; + a[j3 + 3] = wd3r * x0i - wd3i * x0r; + j0 = m - j; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] + a[j2]; + x0i = a[j0 + 1] + a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = a[j0 + 1] - a[j2 + 1]; + y0r = a[j0 - 2] + a[j2 - 2]; + y0i = a[j0 - 1] + a[j2 - 1]; + y1r = a[j0 - 2] - a[j2 - 2]; + y1i = a[j0 - 1] - a[j2 - 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + y2r = a[j1 - 2] + a[j3 - 2]; + y2i = a[j1 - 1] + a[j3 - 1]; + y3r = a[j1 - 2] - a[j3 - 2]; + y3i = a[j1 - 1] - a[j3 - 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j0 - 2] = y0r + y2r; + a[j0 - 1] = y0i + y2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + a[j1 - 2] = y0r - y2r; + a[j1 - 1] = y0i - y2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = wk1i * x0r - wk1r * x0i; + a[j2 + 1] = wk1i * x0i + wk1r * x0r; + x0r = y1r - y3i; + x0i = y1i + y3r; + a[j2 - 2] = wd1i * x0r - wd1r * x0i; + a[j2 - 1] = wd1i * x0i + wd1r * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3i * x0r + wk3r * x0i; + a[j3 + 1] = wk3i * x0i - wk3r * x0r; + x0r = y1r + y3i; + x0i = y1i - y3r; + a[j3 - 2] = wd3i * x0r + wd3r * x0i; + a[j3 - 1] = wd3i * x0i - wd3r * x0r; + } + wk1r = csc1 * (wd1r + wn4r); + wk1i = csc1 * (wd1i + wn4r); + wk3r = csc3 * (wd3r - wn4r); + wk3i = csc3 * (wd3i - wn4r); + j0 = mh; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0 - 2] + a[j2 - 2]; + x0i = a[j0 - 1] + a[j2 - 1]; + x1r = a[j0 - 2] - a[j2 - 2]; + x1i = a[j0 - 1] - a[j2 - 1]; + x2r = a[j1 - 2] + a[j3 - 2]; + x2i = a[j1 - 1] + a[j3 - 1]; + x3r = a[j1 - 2] - a[j3 - 2]; + x3i = a[j1 - 1] - a[j3 - 1]; + a[j0 - 2] = x0r + x2r; + a[j0 - 1] = x0i + x2i; + a[j1 - 2] = x0r - x2r; + a[j1 - 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2 - 2] = wk1r * x0r - wk1i * x0i; + a[j2 - 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 - 2] = wk3r * x0r + wk3i * x0i; + a[j3 - 1] = wk3r * x0i - wk3i * x0r; + x0r = a[j0] + a[j2]; + x0i = a[j0 + 1] + a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = a[j0 + 1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = wn4r * (x0r - x0i); + a[j2 + 1] = wn4r * (x0i + x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = -wn4r * (x0r + x0i); + a[j3 + 1] = -wn4r * (x0i - x0r); + x0r = a[j0 + 2] + a[j2 + 2]; + x0i = a[j0 + 3] + a[j2 + 3]; + x1r = a[j0 + 2] - a[j2 + 2]; + x1i = a[j0 + 3] - a[j2 + 3]; + x2r = a[j1 + 2] + a[j3 + 2]; + x2i = a[j1 + 3] + a[j3 + 3]; + x3r = a[j1 + 2] - a[j3 + 2]; + x3i = a[j1 + 3] - a[j3 + 3]; + a[j0 + 2] = x0r + x2r; + a[j0 + 3] = x0i + x2i; + a[j1 + 2] = x0r - x2r; + a[j1 + 3] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2 + 2] = wk1i * x0r - wk1r * x0i; + a[j2 + 3] = wk1i * x0i + wk1r * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 + 2] = wk3i * x0r + wk3r * x0i; + a[j3 + 3] = wk3i * x0i - wk3r * x0r; +} + + +void cftb1st(int n, double *a, double *w) +{ + int j, j0, j1, j2, j3, k, m, mh; + double wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i, + wd1r, wd1i, wd3r, wd3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i; + + mh = n >> 3; + m = 2 * mh; + j1 = m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[0] + a[j2]; + x0i = -a[1] - a[j2 + 1]; + x1r = a[0] - a[j2]; + x1i = -a[1] + a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[0] = x0r + x2r; + a[1] = x0i - x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i + x2i; + a[j2] = x1r + x3i; + a[j2 + 1] = x1i + x3r; + a[j3] = x1r - x3i; + a[j3 + 1] = x1i - x3r; + wn4r = w[1]; + csc1 = w[2]; + csc3 = w[3]; + wd1r = 1; + wd1i = 0; + wd3r = 1; + wd3i = 0; + k = 0; + for (j = 2; j < mh - 2; j += 4) { + k += 4; + wk1r = csc1 * (wd1r + w[k]); + wk1i = csc1 * (wd1i + w[k + 1]); + wk3r = csc3 * (wd3r + w[k + 2]); + wk3i = csc3 * (wd3i + w[k + 3]); + wd1r = w[k]; + wd1i = w[k + 1]; + wd3r = w[k + 2]; + wd3i = w[k + 3]; + j1 = j + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j] + a[j2]; + x0i = -a[j + 1] - a[j2 + 1]; + x1r = a[j] - a[j2]; + x1i = -a[j + 1] + a[j2 + 1]; + y0r = a[j + 2] + a[j2 + 2]; + y0i = -a[j + 3] - a[j2 + 3]; + y1r = a[j + 2] - a[j2 + 2]; + y1i = -a[j + 3] + a[j2 + 3]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + y2r = a[j1 + 2] + a[j3 + 2]; + y2i = a[j1 + 3] + a[j3 + 3]; + y3r = a[j1 + 2] - a[j3 + 2]; + y3i = a[j1 + 3] - a[j3 + 3]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j + 2] = y0r + y2r; + a[j + 3] = y0i - y2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i + x2i; + a[j1 + 2] = y0r - y2r; + a[j1 + 3] = y0i + y2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2] = wk1r * x0r - wk1i * x0i; + a[j2 + 1] = wk1r * x0i + wk1i * x0r; + x0r = y1r + y3i; + x0i = y1i + y3r; + a[j2 + 2] = wd1r * x0r - wd1i * x0i; + a[j2 + 3] = wd1r * x0i + wd1i * x0r; + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r + wk3i * x0i; + a[j3 + 1] = wk3r * x0i - wk3i * x0r; + x0r = y1r - y3i; + x0i = y1i - y3r; + a[j3 + 2] = wd3r * x0r + wd3i * x0i; + a[j3 + 3] = wd3r * x0i - wd3i * x0r; + j0 = m - j; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] + a[j2]; + x0i = -a[j0 + 1] - a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = -a[j0 + 1] + a[j2 + 1]; + y0r = a[j0 - 2] + a[j2 - 2]; + y0i = -a[j0 - 1] - a[j2 - 1]; + y1r = a[j0 - 2] - a[j2 - 2]; + y1i = -a[j0 - 1] + a[j2 - 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + y2r = a[j1 - 2] + a[j3 - 2]; + y2i = a[j1 - 1] + a[j3 - 1]; + y3r = a[j1 - 2] - a[j3 - 2]; + y3i = a[j1 - 1] - a[j3 - 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i - x2i; + a[j0 - 2] = y0r + y2r; + a[j0 - 1] = y0i - y2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i + x2i; + a[j1 - 2] = y0r - y2r; + a[j1 - 1] = y0i + y2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2] = wk1i * x0r - wk1r * x0i; + a[j2 + 1] = wk1i * x0i + wk1r * x0r; + x0r = y1r + y3i; + x0i = y1i + y3r; + a[j2 - 2] = wd1i * x0r - wd1r * x0i; + a[j2 - 1] = wd1i * x0i + wd1r * x0r; + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3] = wk3i * x0r + wk3r * x0i; + a[j3 + 1] = wk3i * x0i - wk3r * x0r; + x0r = y1r - y3i; + x0i = y1i - y3r; + a[j3 - 2] = wd3i * x0r + wd3r * x0i; + a[j3 - 1] = wd3i * x0i - wd3r * x0r; + } + wk1r = csc1 * (wd1r + wn4r); + wk1i = csc1 * (wd1i + wn4r); + wk3r = csc3 * (wd3r - wn4r); + wk3i = csc3 * (wd3i - wn4r); + j0 = mh; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0 - 2] + a[j2 - 2]; + x0i = -a[j0 - 1] - a[j2 - 1]; + x1r = a[j0 - 2] - a[j2 - 2]; + x1i = -a[j0 - 1] + a[j2 - 1]; + x2r = a[j1 - 2] + a[j3 - 2]; + x2i = a[j1 - 1] + a[j3 - 1]; + x3r = a[j1 - 2] - a[j3 - 2]; + x3i = a[j1 - 1] - a[j3 - 1]; + a[j0 - 2] = x0r + x2r; + a[j0 - 1] = x0i - x2i; + a[j1 - 2] = x0r - x2r; + a[j1 - 1] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2 - 2] = wk1r * x0r - wk1i * x0i; + a[j2 - 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3 - 2] = wk3r * x0r + wk3i * x0i; + a[j3 - 1] = wk3r * x0i - wk3i * x0r; + x0r = a[j0] + a[j2]; + x0i = -a[j0 + 1] - a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = -a[j0 + 1] + a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i - x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2] = wn4r * (x0r - x0i); + a[j2 + 1] = wn4r * (x0i + x0r); + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3] = -wn4r * (x0r + x0i); + a[j3 + 1] = -wn4r * (x0i - x0r); + x0r = a[j0 + 2] + a[j2 + 2]; + x0i = -a[j0 + 3] - a[j2 + 3]; + x1r = a[j0 + 2] - a[j2 + 2]; + x1i = -a[j0 + 3] + a[j2 + 3]; + x2r = a[j1 + 2] + a[j3 + 2]; + x2i = a[j1 + 3] + a[j3 + 3]; + x3r = a[j1 + 2] - a[j3 + 2]; + x3i = a[j1 + 3] - a[j3 + 3]; + a[j0 + 2] = x0r + x2r; + a[j0 + 3] = x0i - x2i; + a[j1 + 2] = x0r - x2r; + a[j1 + 3] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2 + 2] = wk1i * x0r - wk1r * x0i; + a[j2 + 3] = wk1i * x0i + wk1r * x0r; + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3 + 2] = wk3i * x0r + wk3r * x0i; + a[j3 + 3] = wk3i * x0i - wk3r * x0r; +} + + +#ifdef USE_CDFT_THREADS +struct cdft_arg_st { + int n0; + int n; + double *a; + int nw; + double *w; +}; +typedef struct cdft_arg_st cdft_arg_t; + + +void cftrec4_th(int n, double *a, int nw, double *w) +{ + void *cftrec1_th(void *p); + void *cftrec2_th(void *p); + int i, idiv4, m, nthread; + cdft_thread_t th[4]; + cdft_arg_t ag[4]; + + nthread = 2; + idiv4 = 0; + m = n >> 1; + if (n > CDFT_4THREADS_BEGIN_N) { + nthread = 4; + idiv4 = 1; + m >>= 1; + } + for (i = 0; i < nthread; i++) { + ag[i].n0 = n; + ag[i].n = m; + ag[i].a = &a[i * m]; + ag[i].nw = nw; + ag[i].w = w; + if (i != idiv4) { + cdft_thread_create(&th[i], cftrec1_th, &ag[i]); + } else { + cdft_thread_create(&th[i], cftrec2_th, &ag[i]); + } + } + for (i = 0; i < nthread; i++) { + cdft_thread_wait(th[i]); + } +} + + +void *cftrec1_th(void *p) +{ + int cfttree(int n, int j, int k, double *a, int nw, double *w); + void cftleaf(int n, int isplt, double *a, int nw, double *w); + void cftmdl1(int n, double *a, double *w); + int isplt, j, k, m, n, n0, nw; + double *a, *w; + + n0 = ((cdft_arg_t *) p)->n0; + n = ((cdft_arg_t *) p)->n; + a = ((cdft_arg_t *) p)->a; + nw = ((cdft_arg_t *) p)->nw; + w = ((cdft_arg_t *) p)->w; + m = n0; + while (m > 512) { + m >>= 2; + cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]); + } + cftleaf(m, 1, &a[n - m], nw, w); + k = 0; + for (j = n - m; j > 0; j -= m) { + k++; + isplt = cfttree(m, j, k, a, nw, w); + cftleaf(m, isplt, &a[j - m], nw, w); + } + return (void *) 0; +} + + +void *cftrec2_th(void *p) +{ + int cfttree(int n, int j, int k, double *a, int nw, double *w); + void cftleaf(int n, int isplt, double *a, int nw, double *w); + void cftmdl2(int n, double *a, double *w); + int isplt, j, k, m, n, n0, nw; + double *a, *w; + + n0 = ((cdft_arg_t *) p)->n0; + n = ((cdft_arg_t *) p)->n; + a = ((cdft_arg_t *) p)->a; + nw = ((cdft_arg_t *) p)->nw; + w = ((cdft_arg_t *) p)->w; + k = 1; + m = n0; + while (m > 512) { + m >>= 2; + k <<= 2; + cftmdl2(m, &a[n - m], &w[nw - m]); + } + cftleaf(m, 0, &a[n - m], nw, w); + k >>= 1; + for (j = n - m; j > 0; j -= m) { + k++; + isplt = cfttree(m, j, k, a, nw, w); + cftleaf(m, isplt, &a[j - m], nw, w); + } + return (void *) 0; +} +#endif /* USE_CDFT_THREADS */ + + +void cftrec4(int n, double *a, int nw, double *w) +{ + int cfttree(int n, int j, int k, double *a, int nw, double *w); + void cftleaf(int n, int isplt, double *a, int nw, double *w); + void cftmdl1(int n, double *a, double *w); + int isplt, j, k, m; + + m = n; + while (m > 512) { + m >>= 2; + cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]); + } + cftleaf(m, 1, &a[n - m], nw, w); + k = 0; + for (j = n - m; j > 0; j -= m) { + k++; + isplt = cfttree(m, j, k, a, nw, w); + cftleaf(m, isplt, &a[j - m], nw, w); + } +} + + +int cfttree(int n, int j, int k, double *a, int nw, double *w) +{ + void cftmdl1(int n, double *a, double *w); + void cftmdl2(int n, double *a, double *w); + int i, isplt, m; + + if ((k & 3) != 0) { + isplt = k & 1; + if (isplt != 0) { + cftmdl1(n, &a[j - n], &w[nw - (n >> 1)]); + } else { + cftmdl2(n, &a[j - n], &w[nw - n]); + } + } else { + m = n; + for (i = k; (i & 3) == 0; i >>= 2) { + m <<= 2; + } + isplt = i & 1; + if (isplt != 0) { + while (m > 128) { + cftmdl1(m, &a[j - m], &w[nw - (m >> 1)]); + m >>= 2; + } + } else { + while (m > 128) { + cftmdl2(m, &a[j - m], &w[nw - m]); + m >>= 2; + } + } + } + return isplt; +} + + +void cftleaf(int n, int isplt, double *a, int nw, double *w) +{ + void cftmdl1(int n, double *a, double *w); + void cftmdl2(int n, double *a, double *w); + void cftf161(double *a, double *w); + void cftf162(double *a, double *w); + void cftf081(double *a, double *w); + void cftf082(double *a, double *w); + + if (n == 512) { + cftmdl1(128, a, &w[nw - 64]); + cftf161(a, &w[nw - 8]); + cftf162(&a[32], &w[nw - 32]); + cftf161(&a[64], &w[nw - 8]); + cftf161(&a[96], &w[nw - 8]); + cftmdl2(128, &a[128], &w[nw - 128]); + cftf161(&a[128], &w[nw - 8]); + cftf162(&a[160], &w[nw - 32]); + cftf161(&a[192], &w[nw - 8]); + cftf162(&a[224], &w[nw - 32]); + cftmdl1(128, &a[256], &w[nw - 64]); + cftf161(&a[256], &w[nw - 8]); + cftf162(&a[288], &w[nw - 32]); + cftf161(&a[320], &w[nw - 8]); + cftf161(&a[352], &w[nw - 8]); + if (isplt != 0) { + cftmdl1(128, &a[384], &w[nw - 64]); + cftf161(&a[480], &w[nw - 8]); + } else { + cftmdl2(128, &a[384], &w[nw - 128]); + cftf162(&a[480], &w[nw - 32]); + } + cftf161(&a[384], &w[nw - 8]); + cftf162(&a[416], &w[nw - 32]); + cftf161(&a[448], &w[nw - 8]); + } else { + cftmdl1(64, a, &w[nw - 32]); + cftf081(a, &w[nw - 8]); + cftf082(&a[16], &w[nw - 8]); + cftf081(&a[32], &w[nw - 8]); + cftf081(&a[48], &w[nw - 8]); + cftmdl2(64, &a[64], &w[nw - 64]); + cftf081(&a[64], &w[nw - 8]); + cftf082(&a[80], &w[nw - 8]); + cftf081(&a[96], &w[nw - 8]); + cftf082(&a[112], &w[nw - 8]); + cftmdl1(64, &a[128], &w[nw - 32]); + cftf081(&a[128], &w[nw - 8]); + cftf082(&a[144], &w[nw - 8]); + cftf081(&a[160], &w[nw - 8]); + cftf081(&a[176], &w[nw - 8]); + if (isplt != 0) { + cftmdl1(64, &a[192], &w[nw - 32]); + cftf081(&a[240], &w[nw - 8]); + } else { + cftmdl2(64, &a[192], &w[nw - 64]); + cftf082(&a[240], &w[nw - 8]); + } + cftf081(&a[192], &w[nw - 8]); + cftf082(&a[208], &w[nw - 8]); + cftf081(&a[224], &w[nw - 8]); + } +} + + +void cftmdl1(int n, double *a, double *w) +{ + int j, j0, j1, j2, j3, k, m, mh; + double wn4r, wk1r, wk1i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + mh = n >> 3; + m = 2 * mh; + j1 = m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[0] + a[j2]; + x0i = a[1] + a[j2 + 1]; + x1r = a[0] - a[j2]; + x1i = a[1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + a[j2] = x1r - x3i; + a[j2 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + wn4r = w[1]; + k = 0; + for (j = 2; j < mh; j += 2) { + k += 4; + wk1r = w[k]; + wk1i = w[k + 1]; + wk3r = w[k + 2]; + wk3i = w[k + 3]; + j1 = j + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j] + a[j2]; + x0i = a[j + 1] + a[j2 + 1]; + x1r = a[j] - a[j2]; + x1i = a[j + 1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = wk1r * x0r - wk1i * x0i; + a[j2 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r + wk3i * x0i; + a[j3 + 1] = wk3r * x0i - wk3i * x0r; + j0 = m - j; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] + a[j2]; + x0i = a[j0 + 1] + a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = a[j0 + 1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = wk1i * x0r - wk1r * x0i; + a[j2 + 1] = wk1i * x0i + wk1r * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3i * x0r + wk3r * x0i; + a[j3 + 1] = wk3i * x0i - wk3r * x0r; + } + j0 = mh; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] + a[j2]; + x0i = a[j0 + 1] + a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = a[j0 + 1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = wn4r * (x0r - x0i); + a[j2 + 1] = wn4r * (x0i + x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = -wn4r * (x0r + x0i); + a[j3 + 1] = -wn4r * (x0i - x0r); +} + + +void cftmdl2(int n, double *a, double *w) +{ + int j, j0, j1, j2, j3, k, kr, m, mh; + double wn4r, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y2r, y2i; + + mh = n >> 3; + m = 2 * mh; + wn4r = w[1]; + j1 = m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[0] - a[j2 + 1]; + x0i = a[1] + a[j2]; + x1r = a[0] + a[j2 + 1]; + x1i = a[1] - a[j2]; + x2r = a[j1] - a[j3 + 1]; + x2i = a[j1 + 1] + a[j3]; + x3r = a[j1] + a[j3 + 1]; + x3i = a[j1 + 1] - a[j3]; + y0r = wn4r * (x2r - x2i); + y0i = wn4r * (x2i + x2r); + a[0] = x0r + y0r; + a[1] = x0i + y0i; + a[j1] = x0r - y0r; + a[j1 + 1] = x0i - y0i; + y0r = wn4r * (x3r - x3i); + y0i = wn4r * (x3i + x3r); + a[j2] = x1r - y0i; + a[j2 + 1] = x1i + y0r; + a[j3] = x1r + y0i; + a[j3 + 1] = x1i - y0r; + k = 0; + kr = 2 * m; + for (j = 2; j < mh; j += 2) { + k += 4; + wk1r = w[k]; + wk1i = w[k + 1]; + wk3r = w[k + 2]; + wk3i = w[k + 3]; + kr -= 4; + wd1i = w[kr]; + wd1r = w[kr + 1]; + wd3i = w[kr + 2]; + wd3r = w[kr + 3]; + j1 = j + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j] - a[j2 + 1]; + x0i = a[j + 1] + a[j2]; + x1r = a[j] + a[j2 + 1]; + x1i = a[j + 1] - a[j2]; + x2r = a[j1] - a[j3 + 1]; + x2i = a[j1 + 1] + a[j3]; + x3r = a[j1] + a[j3 + 1]; + x3i = a[j1 + 1] - a[j3]; + y0r = wk1r * x0r - wk1i * x0i; + y0i = wk1r * x0i + wk1i * x0r; + y2r = wd1r * x2r - wd1i * x2i; + y2i = wd1r * x2i + wd1i * x2r; + a[j] = y0r + y2r; + a[j + 1] = y0i + y2i; + a[j1] = y0r - y2r; + a[j1 + 1] = y0i - y2i; + y0r = wk3r * x1r + wk3i * x1i; + y0i = wk3r * x1i - wk3i * x1r; + y2r = wd3r * x3r + wd3i * x3i; + y2i = wd3r * x3i - wd3i * x3r; + a[j2] = y0r + y2r; + a[j2 + 1] = y0i + y2i; + a[j3] = y0r - y2r; + a[j3 + 1] = y0i - y2i; + j0 = m - j; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] - a[j2 + 1]; + x0i = a[j0 + 1] + a[j2]; + x1r = a[j0] + a[j2 + 1]; + x1i = a[j0 + 1] - a[j2]; + x2r = a[j1] - a[j3 + 1]; + x2i = a[j1 + 1] + a[j3]; + x3r = a[j1] + a[j3 + 1]; + x3i = a[j1 + 1] - a[j3]; + y0r = wd1i * x0r - wd1r * x0i; + y0i = wd1i * x0i + wd1r * x0r; + y2r = wk1i * x2r - wk1r * x2i; + y2i = wk1i * x2i + wk1r * x2r; + a[j0] = y0r + y2r; + a[j0 + 1] = y0i + y2i; + a[j1] = y0r - y2r; + a[j1 + 1] = y0i - y2i; + y0r = wd3i * x1r + wd3r * x1i; + y0i = wd3i * x1i - wd3r * x1r; + y2r = wk3i * x3r + wk3r * x3i; + y2i = wk3i * x3i - wk3r * x3r; + a[j2] = y0r + y2r; + a[j2 + 1] = y0i + y2i; + a[j3] = y0r - y2r; + a[j3 + 1] = y0i - y2i; + } + wk1r = w[m]; + wk1i = w[m + 1]; + j0 = mh; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] - a[j2 + 1]; + x0i = a[j0 + 1] + a[j2]; + x1r = a[j0] + a[j2 + 1]; + x1i = a[j0 + 1] - a[j2]; + x2r = a[j1] - a[j3 + 1]; + x2i = a[j1 + 1] + a[j3]; + x3r = a[j1] + a[j3 + 1]; + x3i = a[j1 + 1] - a[j3]; + y0r = wk1r * x0r - wk1i * x0i; + y0i = wk1r * x0i + wk1i * x0r; + y2r = wk1i * x2r - wk1r * x2i; + y2i = wk1i * x2i + wk1r * x2r; + a[j0] = y0r + y2r; + a[j0 + 1] = y0i + y2i; + a[j1] = y0r - y2r; + a[j1 + 1] = y0i - y2i; + y0r = wk1i * x1r - wk1r * x1i; + y0i = wk1i * x1i + wk1r * x1r; + y2r = wk1r * x3r - wk1i * x3i; + y2i = wk1r * x3i + wk1i * x3r; + a[j2] = y0r - y2r; + a[j2 + 1] = y0i - y2i; + a[j3] = y0r + y2r; + a[j3 + 1] = y0i + y2i; +} + + +void cftfx41(int n, double *a, int nw, double *w) +{ + void cftf161(double *a, double *w); + void cftf162(double *a, double *w); + void cftf081(double *a, double *w); + void cftf082(double *a, double *w); + + if (n == 128) { + cftf161(a, &w[nw - 8]); + cftf162(&a[32], &w[nw - 32]); + cftf161(&a[64], &w[nw - 8]); + cftf161(&a[96], &w[nw - 8]); + } else { + cftf081(a, &w[nw - 8]); + cftf082(&a[16], &w[nw - 8]); + cftf081(&a[32], &w[nw - 8]); + cftf081(&a[48], &w[nw - 8]); + } +} + + +void cftf161(double *a, double *w) +{ + double wn4r, wk1r, wk1i, + x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, + y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i, + y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i, + y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i; + + wn4r = w[1]; + wk1r = w[2]; + wk1i = w[3]; + x0r = a[0] + a[16]; + x0i = a[1] + a[17]; + x1r = a[0] - a[16]; + x1i = a[1] - a[17]; + x2r = a[8] + a[24]; + x2i = a[9] + a[25]; + x3r = a[8] - a[24]; + x3i = a[9] - a[25]; + y0r = x0r + x2r; + y0i = x0i + x2i; + y4r = x0r - x2r; + y4i = x0i - x2i; + y8r = x1r - x3i; + y8i = x1i + x3r; + y12r = x1r + x3i; + y12i = x1i - x3r; + x0r = a[2] + a[18]; + x0i = a[3] + a[19]; + x1r = a[2] - a[18]; + x1i = a[3] - a[19]; + x2r = a[10] + a[26]; + x2i = a[11] + a[27]; + x3r = a[10] - a[26]; + x3i = a[11] - a[27]; + y1r = x0r + x2r; + y1i = x0i + x2i; + y5r = x0r - x2r; + y5i = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + y9r = wk1r * x0r - wk1i * x0i; + y9i = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + y13r = wk1i * x0r - wk1r * x0i; + y13i = wk1i * x0i + wk1r * x0r; + x0r = a[4] + a[20]; + x0i = a[5] + a[21]; + x1r = a[4] - a[20]; + x1i = a[5] - a[21]; + x2r = a[12] + a[28]; + x2i = a[13] + a[29]; + x3r = a[12] - a[28]; + x3i = a[13] - a[29]; + y2r = x0r + x2r; + y2i = x0i + x2i; + y6r = x0r - x2r; + y6i = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + y10r = wn4r * (x0r - x0i); + y10i = wn4r * (x0i + x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + y14r = wn4r * (x0r + x0i); + y14i = wn4r * (x0i - x0r); + x0r = a[6] + a[22]; + x0i = a[7] + a[23]; + x1r = a[6] - a[22]; + x1i = a[7] - a[23]; + x2r = a[14] + a[30]; + x2i = a[15] + a[31]; + x3r = a[14] - a[30]; + x3i = a[15] - a[31]; + y3r = x0r + x2r; + y3i = x0i + x2i; + y7r = x0r - x2r; + y7i = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + y11r = wk1i * x0r - wk1r * x0i; + y11i = wk1i * x0i + wk1r * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + y15r = wk1r * x0r - wk1i * x0i; + y15i = wk1r * x0i + wk1i * x0r; + x0r = y12r - y14r; + x0i = y12i - y14i; + x1r = y12r + y14r; + x1i = y12i + y14i; + x2r = y13r - y15r; + x2i = y13i - y15i; + x3r = y13r + y15r; + x3i = y13i + y15i; + a[24] = x0r + x2r; + a[25] = x0i + x2i; + a[26] = x0r - x2r; + a[27] = x0i - x2i; + a[28] = x1r - x3i; + a[29] = x1i + x3r; + a[30] = x1r + x3i; + a[31] = x1i - x3r; + x0r = y8r + y10r; + x0i = y8i + y10i; + x1r = y8r - y10r; + x1i = y8i - y10i; + x2r = y9r + y11r; + x2i = y9i + y11i; + x3r = y9r - y11r; + x3i = y9i - y11i; + a[16] = x0r + x2r; + a[17] = x0i + x2i; + a[18] = x0r - x2r; + a[19] = x0i - x2i; + a[20] = x1r - x3i; + a[21] = x1i + x3r; + a[22] = x1r + x3i; + a[23] = x1i - x3r; + x0r = y5r - y7i; + x0i = y5i + y7r; + x2r = wn4r * (x0r - x0i); + x2i = wn4r * (x0i + x0r); + x0r = y5r + y7i; + x0i = y5i - y7r; + x3r = wn4r * (x0r - x0i); + x3i = wn4r * (x0i + x0r); + x0r = y4r - y6i; + x0i = y4i + y6r; + x1r = y4r + y6i; + x1i = y4i - y6r; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[10] = x0r - x2r; + a[11] = x0i - x2i; + a[12] = x1r - x3i; + a[13] = x1i + x3r; + a[14] = x1r + x3i; + a[15] = x1i - x3r; + x0r = y0r + y2r; + x0i = y0i + y2i; + x1r = y0r - y2r; + x1i = y0i - y2i; + x2r = y1r + y3r; + x2i = y1i + y3i; + x3r = y1r - y3r; + x3i = y1i - y3i; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[2] = x0r - x2r; + a[3] = x0i - x2i; + a[4] = x1r - x3i; + a[5] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; +} + + +void cftf162(double *a, double *w) +{ + double wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i, + x0r, x0i, x1r, x1i, x2r, x2i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, + y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i, + y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i, + y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i; + + wn4r = w[1]; + wk1r = w[4]; + wk1i = w[5]; + wk3r = w[6]; + wk3i = -w[7]; + wk2r = w[8]; + wk2i = w[9]; + x1r = a[0] - a[17]; + x1i = a[1] + a[16]; + x0r = a[8] - a[25]; + x0i = a[9] + a[24]; + x2r = wn4r * (x0r - x0i); + x2i = wn4r * (x0i + x0r); + y0r = x1r + x2r; + y0i = x1i + x2i; + y4r = x1r - x2r; + y4i = x1i - x2i; + x1r = a[0] + a[17]; + x1i = a[1] - a[16]; + x0r = a[8] + a[25]; + x0i = a[9] - a[24]; + x2r = wn4r * (x0r - x0i); + x2i = wn4r * (x0i + x0r); + y8r = x1r - x2i; + y8i = x1i + x2r; + y12r = x1r + x2i; + y12i = x1i - x2r; + x0r = a[2] - a[19]; + x0i = a[3] + a[18]; + x1r = wk1r * x0r - wk1i * x0i; + x1i = wk1r * x0i + wk1i * x0r; + x0r = a[10] - a[27]; + x0i = a[11] + a[26]; + x2r = wk3i * x0r - wk3r * x0i; + x2i = wk3i * x0i + wk3r * x0r; + y1r = x1r + x2r; + y1i = x1i + x2i; + y5r = x1r - x2r; + y5i = x1i - x2i; + x0r = a[2] + a[19]; + x0i = a[3] - a[18]; + x1r = wk3r * x0r - wk3i * x0i; + x1i = wk3r * x0i + wk3i * x0r; + x0r = a[10] + a[27]; + x0i = a[11] - a[26]; + x2r = wk1r * x0r + wk1i * x0i; + x2i = wk1r * x0i - wk1i * x0r; + y9r = x1r - x2r; + y9i = x1i - x2i; + y13r = x1r + x2r; + y13i = x1i + x2i; + x0r = a[4] - a[21]; + x0i = a[5] + a[20]; + x1r = wk2r * x0r - wk2i * x0i; + x1i = wk2r * x0i + wk2i * x0r; + x0r = a[12] - a[29]; + x0i = a[13] + a[28]; + x2r = wk2i * x0r - wk2r * x0i; + x2i = wk2i * x0i + wk2r * x0r; + y2r = x1r + x2r; + y2i = x1i + x2i; + y6r = x1r - x2r; + y6i = x1i - x2i; + x0r = a[4] + a[21]; + x0i = a[5] - a[20]; + x1r = wk2i * x0r - wk2r * x0i; + x1i = wk2i * x0i + wk2r * x0r; + x0r = a[12] + a[29]; + x0i = a[13] - a[28]; + x2r = wk2r * x0r - wk2i * x0i; + x2i = wk2r * x0i + wk2i * x0r; + y10r = x1r - x2r; + y10i = x1i - x2i; + y14r = x1r + x2r; + y14i = x1i + x2i; + x0r = a[6] - a[23]; + x0i = a[7] + a[22]; + x1r = wk3r * x0r - wk3i * x0i; + x1i = wk3r * x0i + wk3i * x0r; + x0r = a[14] - a[31]; + x0i = a[15] + a[30]; + x2r = wk1i * x0r - wk1r * x0i; + x2i = wk1i * x0i + wk1r * x0r; + y3r = x1r + x2r; + y3i = x1i + x2i; + y7r = x1r - x2r; + y7i = x1i - x2i; + x0r = a[6] + a[23]; + x0i = a[7] - a[22]; + x1r = wk1i * x0r + wk1r * x0i; + x1i = wk1i * x0i - wk1r * x0r; + x0r = a[14] + a[31]; + x0i = a[15] - a[30]; + x2r = wk3i * x0r - wk3r * x0i; + x2i = wk3i * x0i + wk3r * x0r; + y11r = x1r + x2r; + y11i = x1i + x2i; + y15r = x1r - x2r; + y15i = x1i - x2i; + x1r = y0r + y2r; + x1i = y0i + y2i; + x2r = y1r + y3r; + x2i = y1i + y3i; + a[0] = x1r + x2r; + a[1] = x1i + x2i; + a[2] = x1r - x2r; + a[3] = x1i - x2i; + x1r = y0r - y2r; + x1i = y0i - y2i; + x2r = y1r - y3r; + x2i = y1i - y3i; + a[4] = x1r - x2i; + a[5] = x1i + x2r; + a[6] = x1r + x2i; + a[7] = x1i - x2r; + x1r = y4r - y6i; + x1i = y4i + y6r; + x0r = y5r - y7i; + x0i = y5i + y7r; + x2r = wn4r * (x0r - x0i); + x2i = wn4r * (x0i + x0r); + a[8] = x1r + x2r; + a[9] = x1i + x2i; + a[10] = x1r - x2r; + a[11] = x1i - x2i; + x1r = y4r + y6i; + x1i = y4i - y6r; + x0r = y5r + y7i; + x0i = y5i - y7r; + x2r = wn4r * (x0r - x0i); + x2i = wn4r * (x0i + x0r); + a[12] = x1r - x2i; + a[13] = x1i + x2r; + a[14] = x1r + x2i; + a[15] = x1i - x2r; + x1r = y8r + y10r; + x1i = y8i + y10i; + x2r = y9r - y11r; + x2i = y9i - y11i; + a[16] = x1r + x2r; + a[17] = x1i + x2i; + a[18] = x1r - x2r; + a[19] = x1i - x2i; + x1r = y8r - y10r; + x1i = y8i - y10i; + x2r = y9r + y11r; + x2i = y9i + y11i; + a[20] = x1r - x2i; + a[21] = x1i + x2r; + a[22] = x1r + x2i; + a[23] = x1i - x2r; + x1r = y12r - y14i; + x1i = y12i + y14r; + x0r = y13r + y15i; + x0i = y13i - y15r; + x2r = wn4r * (x0r - x0i); + x2i = wn4r * (x0i + x0r); + a[24] = x1r + x2r; + a[25] = x1i + x2i; + a[26] = x1r - x2r; + a[27] = x1i - x2i; + x1r = y12r + y14i; + x1i = y12i - y14r; + x0r = y13r - y15i; + x0i = y13i + y15r; + x2r = wn4r * (x0r - x0i); + x2i = wn4r * (x0i + x0r); + a[28] = x1r - x2i; + a[29] = x1i + x2r; + a[30] = x1r + x2i; + a[31] = x1i - x2r; +} + + +void cftf081(double *a, double *w) +{ + double wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, + y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i; + + wn4r = w[1]; + x0r = a[0] + a[8]; + x0i = a[1] + a[9]; + x1r = a[0] - a[8]; + x1i = a[1] - a[9]; + x2r = a[4] + a[12]; + x2i = a[5] + a[13]; + x3r = a[4] - a[12]; + x3i = a[5] - a[13]; + y0r = x0r + x2r; + y0i = x0i + x2i; + y2r = x0r - x2r; + y2i = x0i - x2i; + y1r = x1r - x3i; + y1i = x1i + x3r; + y3r = x1r + x3i; + y3i = x1i - x3r; + x0r = a[2] + a[10]; + x0i = a[3] + a[11]; + x1r = a[2] - a[10]; + x1i = a[3] - a[11]; + x2r = a[6] + a[14]; + x2i = a[7] + a[15]; + x3r = a[6] - a[14]; + x3i = a[7] - a[15]; + y4r = x0r + x2r; + y4i = x0i + x2i; + y6r = x0r - x2r; + y6i = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + x2r = x1r + x3i; + x2i = x1i - x3r; + y5r = wn4r * (x0r - x0i); + y5i = wn4r * (x0r + x0i); + y7r = wn4r * (x2r - x2i); + y7i = wn4r * (x2r + x2i); + a[8] = y1r + y5r; + a[9] = y1i + y5i; + a[10] = y1r - y5r; + a[11] = y1i - y5i; + a[12] = y3r - y7i; + a[13] = y3i + y7r; + a[14] = y3r + y7i; + a[15] = y3i - y7r; + a[0] = y0r + y4r; + a[1] = y0i + y4i; + a[2] = y0r - y4r; + a[3] = y0i - y4i; + a[4] = y2r - y6i; + a[5] = y2i + y6r; + a[6] = y2r + y6i; + a[7] = y2i - y6r; +} + + +void cftf082(double *a, double *w) +{ + double wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, + y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i; + + wn4r = w[1]; + wk1r = w[2]; + wk1i = w[3]; + y0r = a[0] - a[9]; + y0i = a[1] + a[8]; + y1r = a[0] + a[9]; + y1i = a[1] - a[8]; + x0r = a[4] - a[13]; + x0i = a[5] + a[12]; + y2r = wn4r * (x0r - x0i); + y2i = wn4r * (x0i + x0r); + x0r = a[4] + a[13]; + x0i = a[5] - a[12]; + y3r = wn4r * (x0r - x0i); + y3i = wn4r * (x0i + x0r); + x0r = a[2] - a[11]; + x0i = a[3] + a[10]; + y4r = wk1r * x0r - wk1i * x0i; + y4i = wk1r * x0i + wk1i * x0r; + x0r = a[2] + a[11]; + x0i = a[3] - a[10]; + y5r = wk1i * x0r - wk1r * x0i; + y5i = wk1i * x0i + wk1r * x0r; + x0r = a[6] - a[15]; + x0i = a[7] + a[14]; + y6r = wk1i * x0r - wk1r * x0i; + y6i = wk1i * x0i + wk1r * x0r; + x0r = a[6] + a[15]; + x0i = a[7] - a[14]; + y7r = wk1r * x0r - wk1i * x0i; + y7i = wk1r * x0i + wk1i * x0r; + x0r = y0r + y2r; + x0i = y0i + y2i; + x1r = y4r + y6r; + x1i = y4i + y6i; + a[0] = x0r + x1r; + a[1] = x0i + x1i; + a[2] = x0r - x1r; + a[3] = x0i - x1i; + x0r = y0r - y2r; + x0i = y0i - y2i; + x1r = y4r - y6r; + x1i = y4i - y6i; + a[4] = x0r - x1i; + a[5] = x0i + x1r; + a[6] = x0r + x1i; + a[7] = x0i - x1r; + x0r = y1r - y3i; + x0i = y1i + y3r; + x1r = y5r - y7r; + x1i = y5i - y7i; + a[8] = x0r + x1r; + a[9] = x0i + x1i; + a[10] = x0r - x1r; + a[11] = x0i - x1i; + x0r = y1r + y3i; + x0i = y1i - y3r; + x1r = y5r + y7r; + x1i = y5i + y7i; + a[12] = x0r - x1i; + a[13] = x0i + x1r; + a[14] = x0r + x1i; + a[15] = x0i - x1r; +} + + +void cftf040(double *a) +{ + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[4]; + x0i = a[1] + a[5]; + x1r = a[0] - a[4]; + x1i = a[1] - a[5]; + x2r = a[2] + a[6]; + x2i = a[3] + a[7]; + x3r = a[2] - a[6]; + x3i = a[3] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[6] = x1r + x3i; + a[7] = x1i - x3r; +} + + +void cftb040(double *a) +{ + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[4]; + x0i = a[1] + a[5]; + x1r = a[0] - a[4]; + x1i = a[1] - a[5]; + x2r = a[2] + a[6]; + x2i = a[3] + a[7]; + x3r = a[2] - a[6]; + x3i = a[3] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[2] = x1r + x3i; + a[3] = x1i - x3r; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[6] = x1r - x3i; + a[7] = x1i + x3r; +} + + +void cftx020(double *a) +{ + double x0r, x0i; + + x0r = a[0] - a[2]; + x0i = a[1] - a[3]; + a[0] += a[2]; + a[1] += a[3]; + a[2] = x0r; + a[3] = x0i; +} + + +void rftfsub(int n, double *a, int nc, double *c) +{ + int j, k, kk, ks, m; + double wkr, wki, xr, xi, yr, yi; + + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5 - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + } +} + + +void rftbsub(int n, double *a, int nc, double *c) +{ + int j, k, kk, ks, m; + double wkr, wki, xr, xi, yr, yi; + + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5 - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + } +} + + +void dctsub(int n, double *a, int nc, double *c) +{ + int j, k, kk, ks, m; + double wkr, wki, xr; + + m = n >> 1; + ks = nc / n; + kk = 0; + for (j = 1; j < m; j++) { + k = n - j; + kk += ks; + wkr = c[kk] - c[nc - kk]; + wki = c[kk] + c[nc - kk]; + xr = wki * a[j] - wkr * a[k]; + a[j] = wkr * a[j] + wki * a[k]; + a[k] = xr; + } + a[m] *= c[0]; +} + + +void dstsub(int n, double *a, int nc, double *c) +{ + int j, k, kk, ks, m; + double wkr, wki, xr; + + m = n >> 1; + ks = nc / n; + kk = 0; + for (j = 1; j < m; j++) { + k = n - j; + kk += ks; + wkr = c[kk] - c[nc - kk]; + wki = c[kk] + c[nc - kk]; + xr = wki * a[k] - wkr * a[j]; + a[k] = wkr * a[k] + wki * a[j]; + a[j] = xr; + } + a[m] *= c[0]; +} +
diff --git a/third_party/tensorflow_dependencies/fft2d/fftsg.f b/third_party/tensorflow_dependencies/fft2d/fftsg.f new file mode 100644 index 0000000..6fb26c4 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/fftsg.f
@@ -0,0 +1,2967 @@ +! Fast Fourier/Cosine/Sine Transform +! dimension :one +! data length :power of 2 +! decimation :frequency +! radix :split-radix +! data :inplace +! table :use +! subroutines +! cdft: Complex Discrete Fourier Transform +! rdft: Real Discrete Fourier Transform +! ddct: Discrete Cosine Transform +! ddst: Discrete Sine Transform +! dfct: Cosine Transform of RDFT (Real Symmetric DFT) +! dfst: Sine Transform of RDFT (Real Anti-symmetric DFT) +! +! +! -------- Complex DFT (Discrete Fourier Transform) -------- +! [definition] +! <case1> +! X(k) = sum_j=0^n-1 x(j)*exp(2*pi*i*j*k/n), 0<=k<n +! <case2> +! X(k) = sum_j=0^n-1 x(j)*exp(-2*pi*i*j*k/n), 0<=k<n +! (notes: sum_j=0^n-1 is a summation from j=0 to n-1) +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call cdft(2*n, 1, a, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call cdft(2*n, -1, a, ip, w) +! [parameters] +! 2*n :data length (integer) +! n >= 1, n = power of 2 +! a(0:2*n-1) :input/output data (real*8) +! input data +! a(2*j) = Re(x(j)), +! a(2*j+1) = Im(x(j)), 0<=j<n +! output data +! a(2*k) = Re(X(k)), +! a(2*k+1) = Im(X(k)), 0<=k<n +! ip(0:*) :work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! strictly, +! length of ip >= +! 2+2**(int(log(n+0.5)/log(2.0))/2). +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:n/2-1) :cos/sin table (real*8) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call cdft(2*n, -1, a, ip, w) +! is +! call cdft(2*n, 1, a, ip, w) +! do j = 0, 2 * n - 1 +! a(j) = a(j) / n +! end do +! . +! +! +! -------- Real DFT / Inverse of Real DFT -------- +! [definition] +! <case1> RDFT +! R(k) = sum_j=0^n-1 a(j)*cos(2*pi*j*k/n), 0<=k<=n/2 +! I(k) = sum_j=0^n-1 a(j)*sin(2*pi*j*k/n), 0<k<n/2 +! <case2> IRDFT (excluding scale) +! a(k) = (R(0) + R(n/2)*cos(pi*k))/2 + +! sum_j=1^n/2-1 R(j)*cos(2*pi*j*k/n) + +! sum_j=1^n/2-1 I(j)*sin(2*pi*j*k/n), 0<=k<n +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call rdft(n, 1, a, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call rdft(n, -1, a, ip, w) +! [parameters] +! n :data length (integer) +! n >= 2, n = power of 2 +! a(0:n-1) :input/output data (real*8) +! <case1> +! output data +! a(2*k) = R(k), 0<=k<n/2 +! a(2*k+1) = I(k), 0<k<n/2 +! a(1) = R(n/2) +! <case2> +! input data +! a(2*j) = R(j), 0<=j<n/2 +! a(2*j+1) = I(j), 0<j<n/2 +! a(1) = R(n/2) +! ip(0:*) :work area for bit reversal (integer) +! length of ip >= 2+sqrt(n/2) +! strictly, +! length of ip >= +! 2+2**(int(log(n/2+0.5)/log(2.0))/2). +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:n/2-1) :cos/sin table (real*8) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call rdft(n, 1, a, ip, w) +! is +! call rdft(n, -1, a, ip, w) +! do j = 0, n - 1 +! a(j) = a(j) * 2 / n +! end do +! . +! +! +! -------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- +! [definition] +! <case1> IDCT (excluding scale) +! C(k) = sum_j=0^n-1 a(j)*cos(pi*j*(k+1/2)/n), 0<=k<n +! <case2> DCT +! C(k) = sum_j=0^n-1 a(j)*cos(pi*(j+1/2)*k/n), 0<=k<n +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call ddct(n, 1, a, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call ddct(n, -1, a, ip, w) +! [parameters] +! n :data length (integer) +! n >= 2, n = power of 2 +! a(0:n-1) :input/output data (real*8) +! output data +! a(k) = C(k), 0<=k<n +! ip(0:*) :work area for bit reversal (integer) +! length of ip >= 2+sqrt(n/2) +! strictly, +! length of ip >= +! 2+2**(int(log(n/2+0.5)/log(2.0))/2). +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:n*5/4-1) :cos/sin table (real*8) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call ddct(n, -1, a, ip, w) +! is +! a(0) = a(0) / 2 +! call ddct(n, 1, a, ip, w) +! do j = 0, n - 1 +! a(j) = a(j) * 2 / n +! end do +! . +! +! +! -------- DST (Discrete Sine Transform) / Inverse of DST -------- +! [definition] +! <case1> IDST (excluding scale) +! S(k) = sum_j=1^n A(j)*sin(pi*j*(k+1/2)/n), 0<=k<n +! <case2> DST +! S(k) = sum_j=0^n-1 a(j)*sin(pi*(j+1/2)*k/n), 0<k<=n +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call ddst(n, 1, a, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call ddst(n, -1, a, ip, w) +! [parameters] +! n :data length (integer) +! n >= 2, n = power of 2 +! a(0:n-1) :input/output data (real*8) +! <case1> +! input data +! a(j) = A(j), 0<j<n +! a(0) = A(n) +! output data +! a(k) = S(k), 0<=k<n +! <case2> +! output data +! a(k) = S(k), 0<k<n +! a(0) = S(n) +! ip(0:*) :work area for bit reversal (integer) +! length of ip >= 2+sqrt(n/2) +! strictly, +! length of ip >= +! 2+2**(int(log(n/2+0.5)/log(2.0))/2). +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:n*5/4-1) :cos/sin table (real*8) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call ddst(n, -1, a, ip, w) +! is +! a(0) = a(0) / 2 +! call ddst(n, 1, a, ip, w) +! do j = 0, n - 1 +! a(j) = a(j) * 2 / n +! end do +! . +! +! +! -------- Cosine Transform of RDFT (Real Symmetric DFT) -------- +! [definition] +! C(k) = sum_j=0^n a(j)*cos(pi*j*k/n), 0<=k<=n +! [usage] +! ip(0) = 0 ! first time only +! call dfct(n, a, t, ip, w) +! [parameters] +! n :data length - 1 (integer) +! n >= 2, n = power of 2 +! a(0:n) :input/output data (real*8) +! output data +! a(k) = C(k), 0<=k<=n +! t(0:n/2) :work area (real*8) +! ip(0:*) :work area for bit reversal (integer) +! length of ip >= 2+sqrt(n/4) +! strictly, +! length of ip >= +! 2+2**(int(log(n/4+0.5)/log(2.0))/2). +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:n*5/8-1) :cos/sin table (real*8) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! a(0) = a(0) / 2 +! a(n) = a(n) / 2 +! call dfct(n, a, t, ip, w) +! is +! a(0) = a(0) / 2 +! a(n) = a(n) / 2 +! call dfct(n, a, t, ip, w) +! do j = 0, n +! a(j) = a(j) * 2 / n +! end do +! . +! +! +! -------- Sine Transform of RDFT (Real Anti-symmetric DFT) -------- +! [definition] +! S(k) = sum_j=1^n-1 a(j)*sin(pi*j*k/n), 0<k<n +! [usage] +! ip(0) = 0 ! first time only +! call dfst(n, a, t, ip, w) +! [parameters] +! n :data length + 1 (integer) +! n >= 2, n = power of 2 +! a(0:n-1) :input/output data (real*8) +! output data +! a(k) = S(k), 0<k<n +! (a(0) is used for work area) +! t(0:n/2-1) :work area (real*8) +! ip(0:*) :work area for bit reversal (integer) +! length of ip >= 2+sqrt(n/4) +! strictly, +! length of ip >= +! 2+2**(int(log(n/4+0.5)/log(2.0))/2). +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:n*5/8-1) :cos/sin table (real*8) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call dfst(n, a, t, ip, w) +! is +! call dfst(n, a, t, ip, w) +! do j = 1, n - 1 +! a(j) = a(j) * 2 / n +! end do +! . +! +! +! Appendix : +! The cos/sin table is recalculated when the larger table required. +! w() and ip() are compatible with all routines. +! +! + subroutine cdft(n, isgn, a, ip, w) + integer n, isgn, ip(0 : *), nw + real*8 a(0 : n - 1), w(0 : *) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + if (isgn .ge. 0) then + call cftfsub(n, a, ip, nw, w) + else + call cftbsub(n, a, ip, nw, w) + end if + end +! + subroutine rdft(n, isgn, a, ip, w) + integer n, isgn, ip(0 : *), nw, nc + real*8 a(0 : n - 1), w(0 : *), xi + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. 4 * nc) then + nc = n / 4 + call makect(nc, ip, w(nw)) + end if + if (isgn .ge. 0) then + if (n .gt. 4) then + call cftfsub(n, a, ip, nw, w) + call rftfsub(n, a, nc, w(nw)) + else if (n .eq. 4) then + call cftfsub(n, a, ip, nw, w) + end if + xi = a(0) - a(1) + a(0) = a(0) + a(1) + a(1) = xi + else + a(1) = 0.5d0 * (a(0) - a(1)) + a(0) = a(0) - a(1) + if (n .gt. 4) then + call rftbsub(n, a, nc, w(nw)) + call cftbsub(n, a, ip, nw, w) + else if (n .eq. 4) then + call cftbsub(n, a, ip, nw, w) + end if + end if + end +! + subroutine ddct(n, isgn, a, ip, w) + integer n, isgn, ip(0 : *), j, nw, nc + real*8 a(0 : n - 1), w(0 : *), xr + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. nc) then + nc = n + call makect(nc, ip, w(nw)) + end if + if (isgn .lt. 0) then + xr = a(n - 1) + do j = n - 2, 2, -2 + a(j + 1) = a(j) - a(j - 1) + a(j) = a(j) + a(j - 1) + end do + a(1) = a(0) - xr + a(0) = a(0) + xr + if (n .gt. 4) then + call rftbsub(n, a, nc, w(nw)) + call cftbsub(n, a, ip, nw, w) + else if (n .eq. 4) then + call cftbsub(n, a, ip, nw, w) + end if + end if + call dctsub(n, a, nc, w(nw)) + if (isgn .ge. 0) then + if (n .gt. 4) then + call cftfsub(n, a, ip, nw, w) + call rftfsub(n, a, nc, w(nw)) + else if (n .eq. 4) then + call cftfsub(n, a, ip, nw, w) + end if + xr = a(0) - a(1) + a(0) = a(0) + a(1) + do j = 2, n - 2, 2 + a(j - 1) = a(j) - a(j + 1) + a(j) = a(j) + a(j + 1) + end do + a(n - 1) = xr + end if + end +! + subroutine ddst(n, isgn, a, ip, w) + integer n, isgn, ip(0 : *), j, nw, nc + real*8 a(0 : n - 1), w(0 : *), xr + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. nc) then + nc = n + call makect(nc, ip, w(nw)) + end if + if (isgn .lt. 0) then + xr = a(n - 1) + do j = n - 2, 2, -2 + a(j + 1) = -a(j) - a(j - 1) + a(j) = a(j) - a(j - 1) + end do + a(1) = a(0) + xr + a(0) = a(0) - xr + if (n .gt. 4) then + call rftbsub(n, a, nc, w(nw)) + call cftbsub(n, a, ip, nw, w) + else if (n .eq. 4) then + call cftbsub(n, a, ip, nw, w) + end if + end if + call dstsub(n, a, nc, w(nw)) + if (isgn .ge. 0) then + if (n .gt. 4) then + call cftfsub(n, a, ip, nw, w) + call rftfsub(n, a, nc, w(nw)) + else if (n .eq. 4) then + call cftfsub(n, a, ip, nw, w) + end if + xr = a(0) - a(1) + a(0) = a(0) + a(1) + do j = 2, n - 2, 2 + a(j - 1) = -a(j) - a(j + 1) + a(j) = a(j) - a(j + 1) + end do + a(n - 1) = -xr + end if + end +! + subroutine dfct(n, a, t, ip, w) + integer n, ip(0 : *), j, k, l, m, mh, nw, nc + real*8 a(0 : n), t(0 : n / 2), w(0 : *), xr, xi, yr, yi + nw = ip(0) + if (n .gt. 8 * nw) then + nw = n / 8 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. 2 * nc) then + nc = n / 2 + call makect(nc, ip, w(nw)) + end if + m = n / 2 + yi = a(m) + xi = a(0) + a(n) + a(0) = a(0) - a(n) + t(0) = xi - yi + t(m) = xi + yi + if (n .gt. 2) then + mh = m / 2 + do j = 1, mh - 1 + k = m - j + xr = a(j) - a(n - j) + xi = a(j) + a(n - j) + yr = a(k) - a(n - k) + yi = a(k) + a(n - k) + a(j) = xr + a(k) = yr + t(j) = xi - yi + t(k) = xi + yi + end do + t(mh) = a(mh) + a(n - mh) + a(mh) = a(mh) - a(n - mh) + call dctsub(m, a, nc, w(nw)) + if (m .gt. 4) then + call cftfsub(m, a, ip, nw, w) + call rftfsub(m, a, nc, w(nw)) + else if (m .eq. 4) then + call cftfsub(m, a, ip, nw, w) + end if + a(n - 1) = a(0) - a(1) + a(1) = a(0) + a(1) + do j = m - 2, 2, -2 + a(2 * j + 1) = a(j) + a(j + 1) + a(2 * j - 1) = a(j) - a(j + 1) + end do + l = 2 + m = mh + do while (m .ge. 2) + call dctsub(m, t, nc, w(nw)) + if (m .gt. 4) then + call cftfsub(m, t, ip, nw, w) + call rftfsub(m, t, nc, w(nw)) + else if (m .eq. 4) then + call cftfsub(m, t, ip, nw, w) + end if + a(n - l) = t(0) - t(1) + a(l) = t(0) + t(1) + k = 0 + do j = 2, m - 2, 2 + k = k + 4 * l + a(k - l) = t(j) - t(j + 1) + a(k + l) = t(j) + t(j + 1) + end do + l = 2 * l + mh = m / 2 + do j = 0, mh - 1 + k = m - j + t(j) = t(m + k) - t(m + j) + t(k) = t(m + k) + t(m + j) + end do + t(mh) = t(m + mh) + m = mh + end do + a(l) = t(0) + a(n) = t(2) - t(1) + a(0) = t(2) + t(1) + else + a(1) = a(0) + a(2) = t(0) + a(0) = t(1) + end if + end +! + subroutine dfst(n, a, t, ip, w) + integer n, ip(0 : *), j, k, l, m, mh, nw, nc + real*8 a(0 : n - 1), t(0 : n / 2 - 1), w(0 : *), xr, xi, yr, yi + nw = ip(0) + if (n .gt. 8 * nw) then + nw = n / 8 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. 2 * nc) then + nc = n / 2 + call makect(nc, ip, w(nw)) + end if + if (n .gt. 2) then + m = n / 2 + mh = m / 2 + do j = 1, mh - 1 + k = m - j + xr = a(j) + a(n - j) + xi = a(j) - a(n - j) + yr = a(k) + a(n - k) + yi = a(k) - a(n - k) + a(j) = xr + a(k) = yr + t(j) = xi + yi + t(k) = xi - yi + end do + t(0) = a(mh) - a(n - mh) + a(mh) = a(mh) + a(n - mh) + a(0) = a(m) + call dstsub(m, a, nc, w(nw)) + if (m .gt. 4) then + call cftfsub(m, a, ip, nw, w) + call rftfsub(m, a, nc, w(nw)) + else if (m .eq. 4) then + call cftfsub(m, a, ip, nw, w) + end if + a(n - 1) = a(1) - a(0) + a(1) = a(0) + a(1) + do j = m - 2, 2, -2 + a(2 * j + 1) = a(j) - a(j + 1) + a(2 * j - 1) = -a(j) - a(j + 1) + end do + l = 2 + m = mh + do while (m .ge. 2) + call dstsub(m, t, nc, w(nw)) + if (m .gt. 4) then + call cftfsub(m, t, ip, nw, w) + call rftfsub(m, t, nc, w(nw)) + else if (m .eq. 4) then + call cftfsub(m, t, ip, nw, w) + end if + a(n - l) = t(1) - t(0) + a(l) = t(0) + t(1) + k = 0 + do j = 2, m - 2, 2 + k = k + 4 * l + a(k - l) = -t(j) - t(j + 1) + a(k + l) = t(j) - t(j + 1) + end do + l = 2 * l + mh = m / 2 + do j = 1, mh - 1 + k = m - j + t(j) = t(m + k) + t(m + j) + t(k) = t(m + k) - t(m + j) + end do + t(0) = t(m + mh) + m = mh + end do + a(l) = t(0) + end if + a(0) = 0 + end +! +! -------- initializing routines -------- +! + subroutine makewt(nw, ip, w) + integer nw, ip(0 : *), j, nwh, nw0, nw1 + real*8 w(0 : nw - 1), delta, wn4r, wk1r, wk1i, wk3r, wk3i + ip(0) = nw + ip(1) = 1 + if (nw .gt. 2) then + nwh = nw / 2 + delta = atan(1.0d0) / nwh + wn4r = cos(delta * nwh) + w(0) = 1 + w(1) = wn4r + if (nwh .eq. 4) then + w(2) = cos(delta * 2) + w(3) = sin(delta * 2) + else if (nwh .gt. 4) then + call makeipt(nw, ip) + w(2) = 0.5d0 / cos(delta * 2) + w(3) = 0.5d0 / cos(delta * 6) + do j = 4, nwh - 4, 4 + w(j) = cos(delta * j) + w(j + 1) = sin(delta * j) + w(j + 2) = cos(3 * delta * j) + w(j + 3) = -sin(3 * delta * j) + end do + end if + nw0 = 0 + do while (nwh .gt. 2) + nw1 = nw0 + nwh + nwh = nwh / 2 + w(nw1) = 1 + w(nw1 + 1) = wn4r + if (nwh .eq. 4) then + wk1r = w(nw0 + 4) + wk1i = w(nw0 + 5) + w(nw1 + 2) = wk1r + w(nw1 + 3) = wk1i + else if (nwh .gt. 4) then + wk1r = w(nw0 + 4) + wk3r = w(nw0 + 6) + w(nw1 + 2) = 0.5d0 / wk1r + w(nw1 + 3) = 0.5d0 / wk3r + do j = 4, nwh - 4, 4 + wk1r = w(nw0 + 2 * j) + wk1i = w(nw0 + 2 * j + 1) + wk3r = w(nw0 + 2 * j + 2) + wk3i = w(nw0 + 2 * j + 3) + w(nw1 + j) = wk1r + w(nw1 + j + 1) = wk1i + w(nw1 + j + 2) = wk3r + w(nw1 + j + 3) = wk3i + end do + end if + nw0 = nw1 + end do + end if + end +! + subroutine makeipt(nw, ip) + integer nw, ip(0 : *), j, l, m, m2, p, q + ip(2) = 0 + ip(3) = 16 + m = 2 + l = nw + do while (l .gt. 32) + m2 = 2 * m + q = 8 * m2 + do j = m, m2 - 1 + p = 4 * ip(j) + ip(m + j) = p + ip(m2 + j) = p + q + end do + m = m2 + l = l / 4 + end do + end +! + subroutine makect(nc, ip, c) + integer nc, ip(0 : *), j, nch + real*8 c(0 : nc - 1), delta + ip(1) = nc + if (nc .gt. 1) then + nch = nc / 2 + delta = atan(1.0d0) / nch + c(0) = cos(delta * nch) + c(nch) = 0.5d0 * c(0) + do j = 1, nch - 1 + c(j) = 0.5d0 * cos(delta * j) + c(nc - j) = 0.5d0 * sin(delta * j) + end do + end if + end +! +! -------- child routines -------- +! + subroutine cftfsub(n, a, ip, nw, w) + integer n, ip(0 : *), nw + real*8 a(0 : n - 1), w(0 : nw - 1) + if (n .gt. 8) then + if (n .gt. 32) then + call cftf1st(n, a, w(nw - n / 4)) + if (n .gt. 512) then + call cftrec4(n, a, nw, w) + else if (n .gt. 128) then + call cftleaf(n, 1, a, nw, w) + else + call cftfx41(n, a, nw, w) + end if + call bitrv2(n, ip, a) + else if (n .eq. 32) then + call cftf161(a, w(nw - 8)) + call bitrv216(a) + else + call cftf081(a, w) + call bitrv208(a) + end if + else if (n .eq. 8) then + call cftf040(a) + else if (n .eq. 4) then + call cftx020(a) + end if + end +! + subroutine cftbsub(n, a, ip, nw, w) + integer n, ip(0 : *), nw + real*8 a(0 : n - 1), w(0 : nw - 1) + if (n .gt. 8) then + if (n .gt. 32) then + call cftb1st(n, a, w(nw - n / 4)) + if (n .gt. 512) then + call cftrec4(n, a, nw, w) + else if (n .gt. 128) then + call cftleaf(n, 1, a, nw, w) + else + call cftfx41(n, a, nw, w) + end if + call bitrv2conj(n, ip, a) + else if (n .eq. 32) then + call cftf161(a, w(nw - 8)) + call bitrv216neg(a) + else + call cftf081(a, w) + call bitrv208neg(a) + end if + else if (n .eq. 8) then + call cftb040(a) + else if (n .eq. 4) then + call cftx020(a) + end if + end +! + subroutine bitrv2(n, ip, a) + integer n, ip(0 : *), j, j1, k, k1, l, m, nh, nm + real*8 a(0 : n - 1), xr, xi, yr, yi + m = 1 + l = n / 4 + do while (l .gt. 8) + m = m * 2 + l = l / 4 + end do + nh = n / 2 + nm = 4 * m + if (l .eq. 8) then + do k = 0, m - 1 + do j = 0, k - 1 + j1 = 4 * j + 2 * ip(m + k) + k1 = 4 * k + 2 * ip(m + j) + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 - nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nh + k1 = k1 + 2 + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 + nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + 2 + k1 = k1 + nh + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 - nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nh + k1 = k1 - 2 + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 + nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + end do + k1 = 4 * k + 2 * ip(m + k) + j1 = k1 + 2 + k1 = k1 + nh + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 - nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - 2 + k1 = k1 - nh + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nh + 2 + k1 = k1 + nh + 2 + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nh + nm + k1 = k1 + 2 * nm - 2 + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + end do + else + do k = 0, m - 1 + do j = 0, k - 1 + j1 = 4 * j + ip(m + k) + k1 = 4 * k + ip(m + j) + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nh + k1 = k1 + 2 + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + 2 + k1 = k1 + nh + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nh + k1 = k1 - 2 + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + end do + k1 = 4 * k + ip(m + k) + j1 = k1 + 2 + k1 = k1 + nh + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + nm + xr = a(j1) + xi = a(j1 + 1) + yr = a(k1) + yi = a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + end do + end if + end +! + subroutine bitrv2conj(n, ip, a) + integer n, ip(0 : *), j, j1, k, k1, l, m, nh, nm + real*8 a(0 : n - 1), xr, xi, yr, yi + m = 1 + l = n / 4 + do while (l .gt. 8) + m = m * 2 + l = l / 4 + end do + nh = n / 2 + nm = 4 * m + if (l .eq. 8) then + do k = 0, m - 1 + do j = 0, k - 1 + j1 = 4 * j + 2 * ip(m + k) + k1 = 4 * k + 2 * ip(m + j) + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 - nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nh + k1 = k1 + 2 + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 + nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + 2 + k1 = k1 + nh + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 - nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nh + k1 = k1 - 2 + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 + nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + end do + k1 = 4 * k + 2 * ip(m + k) + j1 = k1 + 2 + k1 = k1 + nh + a(j1 - 1) = -a(j1 - 1) + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + a(k1 + 3) = -a(k1 + 3) + j1 = j1 + nm + k1 = k1 + 2 * nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 - nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - 2 + k1 = k1 - nh + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nh + 2 + k1 = k1 + nh + 2 + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nh + nm + k1 = k1 + 2 * nm - 2 + a(j1 - 1) = -a(j1 - 1) + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + a(k1 + 3) = -a(k1 + 3) + end do + else + do k = 0, m - 1 + do j = 0, k - 1 + j1 = 4 * j + ip(m + k) + k1 = 4 * k + ip(m + j) + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nh + k1 = k1 + 2 + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + 2 + k1 = k1 + nh + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 + nm + k1 = k1 + nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nh + k1 = k1 - 2 + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + j1 = j1 - nm + k1 = k1 - nm + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + end do + k1 = 4 * k + ip(m + k) + j1 = k1 + 2 + k1 = k1 + nh + a(j1 - 1) = -a(j1 - 1) + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + a(k1 + 3) = -a(k1 + 3) + j1 = j1 + nm + k1 = k1 + nm + a(j1 - 1) = -a(j1 - 1) + xr = a(j1) + xi = -a(j1 + 1) + yr = a(k1) + yi = -a(k1 + 1) + a(j1) = yr + a(j1 + 1) = yi + a(k1) = xr + a(k1 + 1) = xi + a(k1 + 3) = -a(k1 + 3) + end do + end if + end +! + subroutine bitrv216(a) + real*8 a(0 : 31), x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i + real*8 x5r, x5i, x7r, x7i, x8r, x8i, x10r, x10i + real*8 x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i + x1r = a(2) + x1i = a(3) + x2r = a(4) + x2i = a(5) + x3r = a(6) + x3i = a(7) + x4r = a(8) + x4i = a(9) + x5r = a(10) + x5i = a(11) + x7r = a(14) + x7i = a(15) + x8r = a(16) + x8i = a(17) + x10r = a(20) + x10i = a(21) + x11r = a(22) + x11i = a(23) + x12r = a(24) + x12i = a(25) + x13r = a(26) + x13i = a(27) + x14r = a(28) + x14i = a(29) + a(2) = x8r + a(3) = x8i + a(4) = x4r + a(5) = x4i + a(6) = x12r + a(7) = x12i + a(8) = x2r + a(9) = x2i + a(10) = x10r + a(11) = x10i + a(14) = x14r + a(15) = x14i + a(16) = x1r + a(17) = x1i + a(20) = x5r + a(21) = x5i + a(22) = x13r + a(23) = x13i + a(24) = x3r + a(25) = x3i + a(26) = x11r + a(27) = x11i + a(28) = x7r + a(29) = x7i + end +! + subroutine bitrv216neg(a) + real*8 a(0 : 31), x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i + real*8 x5r, x5i, x6r, x6i, x7r, x7i, x8r, x8i + real*8 x9r, x9i, x10r, x10i, x11r, x11i, x12r, x12i + real*8 x13r, x13i, x14r, x14i, x15r, x15i + x1r = a(2) + x1i = a(3) + x2r = a(4) + x2i = a(5) + x3r = a(6) + x3i = a(7) + x4r = a(8) + x4i = a(9) + x5r = a(10) + x5i = a(11) + x6r = a(12) + x6i = a(13) + x7r = a(14) + x7i = a(15) + x8r = a(16) + x8i = a(17) + x9r = a(18) + x9i = a(19) + x10r = a(20) + x10i = a(21) + x11r = a(22) + x11i = a(23) + x12r = a(24) + x12i = a(25) + x13r = a(26) + x13i = a(27) + x14r = a(28) + x14i = a(29) + x15r = a(30) + x15i = a(31) + a(2) = x15r + a(3) = x15i + a(4) = x7r + a(5) = x7i + a(6) = x11r + a(7) = x11i + a(8) = x3r + a(9) = x3i + a(10) = x13r + a(11) = x13i + a(12) = x5r + a(13) = x5i + a(14) = x9r + a(15) = x9i + a(16) = x1r + a(17) = x1i + a(18) = x14r + a(19) = x14i + a(20) = x6r + a(21) = x6i + a(22) = x10r + a(23) = x10i + a(24) = x2r + a(25) = x2i + a(26) = x12r + a(27) = x12i + a(28) = x4r + a(29) = x4i + a(30) = x8r + a(31) = x8i + end +! + subroutine bitrv208(a) + real*8 a(0 : 15), x1r, x1i, x3r, x3i, x4r, x4i, x6r, x6i + x1r = a(2) + x1i = a(3) + x3r = a(6) + x3i = a(7) + x4r = a(8) + x4i = a(9) + x6r = a(12) + x6i = a(13) + a(2) = x4r + a(3) = x4i + a(6) = x6r + a(7) = x6i + a(8) = x1r + a(9) = x1i + a(12) = x3r + a(13) = x3i + end +! + subroutine bitrv208neg(a) + real*8 a(0 : 15), x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i + real*8 x5r, x5i, x6r, x6i, x7r, x7i + x1r = a(2) + x1i = a(3) + x2r = a(4) + x2i = a(5) + x3r = a(6) + x3i = a(7) + x4r = a(8) + x4i = a(9) + x5r = a(10) + x5i = a(11) + x6r = a(12) + x6i = a(13) + x7r = a(14) + x7i = a(15) + a(2) = x7r + a(3) = x7i + a(4) = x3r + a(5) = x3i + a(6) = x5r + a(7) = x5i + a(8) = x1r + a(9) = x1i + a(10) = x6r + a(11) = x6i + a(12) = x2r + a(13) = x2i + a(14) = x4r + a(15) = x4i + end +! + subroutine cftf1st(n, a, w) + integer n, j, j0, j1, j2, j3, k, m, mh + real*8 a(0 : n - 1), w(0 : *) + real*8 wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i + real*8 wd1r, wd1i, wd3r, wd3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + real*8 y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i + mh = n / 8 + m = 2 * mh + j1 = m + j2 = j1 + m + j3 = j2 + m + x0r = a(0) + a(j2) + x0i = a(1) + a(j2 + 1) + x1r = a(0) - a(j2) + x1i = a(1) - a(j2 + 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + a(0) = x0r + x2r + a(1) = x0i + x2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i - x2i + a(j2) = x1r - x3i + a(j2 + 1) = x1i + x3r + a(j3) = x1r + x3i + a(j3 + 1) = x1i - x3r + wn4r = w(1) + csc1 = w(2) + csc3 = w(3) + wd1r = 1 + wd1i = 0 + wd3r = 1 + wd3i = 0 + k = 0 + do j = 2, mh - 6, 4 + k = k + 4 + wk1r = csc1 * (wd1r + w(k)) + wk1i = csc1 * (wd1i + w(k + 1)) + wk3r = csc3 * (wd3r + w(k + 2)) + wk3i = csc3 * (wd3i + w(k + 3)) + wd1r = w(k) + wd1i = w(k + 1) + wd3r = w(k + 2) + wd3i = w(k + 3) + j1 = j + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j) + a(j2) + x0i = a(j + 1) + a(j2 + 1) + x1r = a(j) - a(j2) + x1i = a(j + 1) - a(j2 + 1) + y0r = a(j + 2) + a(j2 + 2) + y0i = a(j + 3) + a(j2 + 3) + y1r = a(j + 2) - a(j2 + 2) + y1i = a(j + 3) - a(j2 + 3) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + y2r = a(j1 + 2) + a(j3 + 2) + y2i = a(j1 + 3) + a(j3 + 3) + y3r = a(j1 + 2) - a(j3 + 2) + y3i = a(j1 + 3) - a(j3 + 3) + a(j) = x0r + x2r + a(j + 1) = x0i + x2i + a(j + 2) = y0r + y2r + a(j + 3) = y0i + y2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i - x2i + a(j1 + 2) = y0r - y2r + a(j1 + 3) = y0i - y2i + x0r = x1r - x3i + x0i = x1i + x3r + a(j2) = wk1r * x0r - wk1i * x0i + a(j2 + 1) = wk1r * x0i + wk1i * x0r + x0r = y1r - y3i + x0i = y1i + y3r + a(j2 + 2) = wd1r * x0r - wd1i * x0i + a(j2 + 3) = wd1r * x0i + wd1i * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j3) = wk3r * x0r + wk3i * x0i + a(j3 + 1) = wk3r * x0i - wk3i * x0r + x0r = y1r + y3i + x0i = y1i - y3r + a(j3 + 2) = wd3r * x0r + wd3i * x0i + a(j3 + 3) = wd3r * x0i - wd3i * x0r + j0 = m - j + j1 = j0 + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j0) + a(j2) + x0i = a(j0 + 1) + a(j2 + 1) + x1r = a(j0) - a(j2) + x1i = a(j0 + 1) - a(j2 + 1) + y0r = a(j0 - 2) + a(j2 - 2) + y0i = a(j0 - 1) + a(j2 - 1) + y1r = a(j0 - 2) - a(j2 - 2) + y1i = a(j0 - 1) - a(j2 - 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + y2r = a(j1 - 2) + a(j3 - 2) + y2i = a(j1 - 1) + a(j3 - 1) + y3r = a(j1 - 2) - a(j3 - 2) + y3i = a(j1 - 1) - a(j3 - 1) + a(j0) = x0r + x2r + a(j0 + 1) = x0i + x2i + a(j0 - 2) = y0r + y2r + a(j0 - 1) = y0i + y2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i - x2i + a(j1 - 2) = y0r - y2r + a(j1 - 1) = y0i - y2i + x0r = x1r - x3i + x0i = x1i + x3r + a(j2) = wk1i * x0r - wk1r * x0i + a(j2 + 1) = wk1i * x0i + wk1r * x0r + x0r = y1r - y3i + x0i = y1i + y3r + a(j2 - 2) = wd1i * x0r - wd1r * x0i + a(j2 - 1) = wd1i * x0i + wd1r * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j3) = wk3i * x0r + wk3r * x0i + a(j3 + 1) = wk3i * x0i - wk3r * x0r + x0r = y1r + y3i + x0i = y1i - y3r + a(j3 - 2) = wd3i * x0r + wd3r * x0i + a(j3 - 1) = wd3i * x0i - wd3r * x0r + end do + wk1r = csc1 * (wd1r + wn4r) + wk1i = csc1 * (wd1i + wn4r) + wk3r = csc3 * (wd3r - wn4r) + wk3i = csc3 * (wd3i - wn4r) + j0 = mh + j1 = j0 + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j0 - 2) + a(j2 - 2) + x0i = a(j0 - 1) + a(j2 - 1) + x1r = a(j0 - 2) - a(j2 - 2) + x1i = a(j0 - 1) - a(j2 - 1) + x2r = a(j1 - 2) + a(j3 - 2) + x2i = a(j1 - 1) + a(j3 - 1) + x3r = a(j1 - 2) - a(j3 - 2) + x3i = a(j1 - 1) - a(j3 - 1) + a(j0 - 2) = x0r + x2r + a(j0 - 1) = x0i + x2i + a(j1 - 2) = x0r - x2r + a(j1 - 1) = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + a(j2 - 2) = wk1r * x0r - wk1i * x0i + a(j2 - 1) = wk1r * x0i + wk1i * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j3 - 2) = wk3r * x0r + wk3i * x0i + a(j3 - 1) = wk3r * x0i - wk3i * x0r + x0r = a(j0) + a(j2) + x0i = a(j0 + 1) + a(j2 + 1) + x1r = a(j0) - a(j2) + x1i = a(j0 + 1) - a(j2 + 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + a(j0) = x0r + x2r + a(j0 + 1) = x0i + x2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + a(j2) = wn4r * (x0r - x0i) + a(j2 + 1) = wn4r * (x0i + x0r) + x0r = x1r + x3i + x0i = x1i - x3r + a(j3) = -wn4r * (x0r + x0i) + a(j3 + 1) = -wn4r * (x0i - x0r) + x0r = a(j0 + 2) + a(j2 + 2) + x0i = a(j0 + 3) + a(j2 + 3) + x1r = a(j0 + 2) - a(j2 + 2) + x1i = a(j0 + 3) - a(j2 + 3) + x2r = a(j1 + 2) + a(j3 + 2) + x2i = a(j1 + 3) + a(j3 + 3) + x3r = a(j1 + 2) - a(j3 + 2) + x3i = a(j1 + 3) - a(j3 + 3) + a(j0 + 2) = x0r + x2r + a(j0 + 3) = x0i + x2i + a(j1 + 2) = x0r - x2r + a(j1 + 3) = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + a(j2 + 2) = wk1i * x0r - wk1r * x0i + a(j2 + 3) = wk1i * x0i + wk1r * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j3 + 2) = wk3i * x0r + wk3r * x0i + a(j3 + 3) = wk3i * x0i - wk3r * x0r + end +! + subroutine cftb1st(n, a, w) + integer n, j, j0, j1, j2, j3, k, m, mh + real*8 a(0 : n - 1), w(0 : *) + real*8 wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i + real*8 wd1r, wd1i, wd3r, wd3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + real*8 y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i + mh = n / 8 + m = 2 * mh + j1 = m + j2 = j1 + m + j3 = j2 + m + x0r = a(0) + a(j2) + x0i = -a(1) - a(j2 + 1) + x1r = a(0) - a(j2) + x1i = -a(1) + a(j2 + 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + a(0) = x0r + x2r + a(1) = x0i - x2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i + x2i + a(j2) = x1r + x3i + a(j2 + 1) = x1i + x3r + a(j3) = x1r - x3i + a(j3 + 1) = x1i - x3r + wn4r = w(1) + csc1 = w(2) + csc3 = w(3) + wd1r = 1 + wd1i = 0 + wd3r = 1 + wd3i = 0 + k = 0 + do j = 2, mh - 6, 4 + k = k + 4 + wk1r = csc1 * (wd1r + w(k)) + wk1i = csc1 * (wd1i + w(k + 1)) + wk3r = csc3 * (wd3r + w(k + 2)) + wk3i = csc3 * (wd3i + w(k + 3)) + wd1r = w(k) + wd1i = w(k + 1) + wd3r = w(k + 2) + wd3i = w(k + 3) + j1 = j + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j) + a(j2) + x0i = -a(j + 1) - a(j2 + 1) + x1r = a(j) - a(j2) + x1i = -a(j + 1) + a(j2 + 1) + y0r = a(j + 2) + a(j2 + 2) + y0i = -a(j + 3) - a(j2 + 3) + y1r = a(j + 2) - a(j2 + 2) + y1i = -a(j + 3) + a(j2 + 3) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + y2r = a(j1 + 2) + a(j3 + 2) + y2i = a(j1 + 3) + a(j3 + 3) + y3r = a(j1 + 2) - a(j3 + 2) + y3i = a(j1 + 3) - a(j3 + 3) + a(j) = x0r + x2r + a(j + 1) = x0i - x2i + a(j + 2) = y0r + y2r + a(j + 3) = y0i - y2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i + x2i + a(j1 + 2) = y0r - y2r + a(j1 + 3) = y0i + y2i + x0r = x1r + x3i + x0i = x1i + x3r + a(j2) = wk1r * x0r - wk1i * x0i + a(j2 + 1) = wk1r * x0i + wk1i * x0r + x0r = y1r + y3i + x0i = y1i + y3r + a(j2 + 2) = wd1r * x0r - wd1i * x0i + a(j2 + 3) = wd1r * x0i + wd1i * x0r + x0r = x1r - x3i + x0i = x1i - x3r + a(j3) = wk3r * x0r + wk3i * x0i + a(j3 + 1) = wk3r * x0i - wk3i * x0r + x0r = y1r - y3i + x0i = y1i - y3r + a(j3 + 2) = wd3r * x0r + wd3i * x0i + a(j3 + 3) = wd3r * x0i - wd3i * x0r + j0 = m - j + j1 = j0 + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j0) + a(j2) + x0i = -a(j0 + 1) - a(j2 + 1) + x1r = a(j0) - a(j2) + x1i = -a(j0 + 1) + a(j2 + 1) + y0r = a(j0 - 2) + a(j2 - 2) + y0i = -a(j0 - 1) - a(j2 - 1) + y1r = a(j0 - 2) - a(j2 - 2) + y1i = -a(j0 - 1) + a(j2 - 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + y2r = a(j1 - 2) + a(j3 - 2) + y2i = a(j1 - 1) + a(j3 - 1) + y3r = a(j1 - 2) - a(j3 - 2) + y3i = a(j1 - 1) - a(j3 - 1) + a(j0) = x0r + x2r + a(j0 + 1) = x0i - x2i + a(j0 - 2) = y0r + y2r + a(j0 - 1) = y0i - y2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i + x2i + a(j1 - 2) = y0r - y2r + a(j1 - 1) = y0i + y2i + x0r = x1r + x3i + x0i = x1i + x3r + a(j2) = wk1i * x0r - wk1r * x0i + a(j2 + 1) = wk1i * x0i + wk1r * x0r + x0r = y1r + y3i + x0i = y1i + y3r + a(j2 - 2) = wd1i * x0r - wd1r * x0i + a(j2 - 1) = wd1i * x0i + wd1r * x0r + x0r = x1r - x3i + x0i = x1i - x3r + a(j3) = wk3i * x0r + wk3r * x0i + a(j3 + 1) = wk3i * x0i - wk3r * x0r + x0r = y1r - y3i + x0i = y1i - y3r + a(j3 - 2) = wd3i * x0r + wd3r * x0i + a(j3 - 1) = wd3i * x0i - wd3r * x0r + end do + wk1r = csc1 * (wd1r + wn4r) + wk1i = csc1 * (wd1i + wn4r) + wk3r = csc3 * (wd3r - wn4r) + wk3i = csc3 * (wd3i - wn4r) + j0 = mh + j1 = j0 + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j0 - 2) + a(j2 - 2) + x0i = -a(j0 - 1) - a(j2 - 1) + x1r = a(j0 - 2) - a(j2 - 2) + x1i = -a(j0 - 1) + a(j2 - 1) + x2r = a(j1 - 2) + a(j3 - 2) + x2i = a(j1 - 1) + a(j3 - 1) + x3r = a(j1 - 2) - a(j3 - 2) + x3i = a(j1 - 1) - a(j3 - 1) + a(j0 - 2) = x0r + x2r + a(j0 - 1) = x0i - x2i + a(j1 - 2) = x0r - x2r + a(j1 - 1) = x0i + x2i + x0r = x1r + x3i + x0i = x1i + x3r + a(j2 - 2) = wk1r * x0r - wk1i * x0i + a(j2 - 1) = wk1r * x0i + wk1i * x0r + x0r = x1r - x3i + x0i = x1i - x3r + a(j3 - 2) = wk3r * x0r + wk3i * x0i + a(j3 - 1) = wk3r * x0i - wk3i * x0r + x0r = a(j0) + a(j2) + x0i = -a(j0 + 1) - a(j2 + 1) + x1r = a(j0) - a(j2) + x1i = -a(j0 + 1) + a(j2 + 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + a(j0) = x0r + x2r + a(j0 + 1) = x0i - x2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i + x2i + x0r = x1r + x3i + x0i = x1i + x3r + a(j2) = wn4r * (x0r - x0i) + a(j2 + 1) = wn4r * (x0i + x0r) + x0r = x1r - x3i + x0i = x1i - x3r + a(j3) = -wn4r * (x0r + x0i) + a(j3 + 1) = -wn4r * (x0i - x0r) + x0r = a(j0 + 2) + a(j2 + 2) + x0i = -a(j0 + 3) - a(j2 + 3) + x1r = a(j0 + 2) - a(j2 + 2) + x1i = -a(j0 + 3) + a(j2 + 3) + x2r = a(j1 + 2) + a(j3 + 2) + x2i = a(j1 + 3) + a(j3 + 3) + x3r = a(j1 + 2) - a(j3 + 2) + x3i = a(j1 + 3) - a(j3 + 3) + a(j0 + 2) = x0r + x2r + a(j0 + 3) = x0i - x2i + a(j1 + 2) = x0r - x2r + a(j1 + 3) = x0i + x2i + x0r = x1r + x3i + x0i = x1i + x3r + a(j2 + 2) = wk1i * x0r - wk1r * x0i + a(j2 + 3) = wk1i * x0i + wk1r * x0r + x0r = x1r - x3i + x0i = x1i - x3r + a(j3 + 2) = wk3i * x0r + wk3r * x0i + a(j3 + 3) = wk3i * x0i - wk3r * x0r + end +! + subroutine cftrec4(n, a, nw, w) + integer n, nw, cfttree, isplt, j, k, m + real*8 a(0 : n - 1), w(0 : nw - 1) + m = n + do while (m .gt. 512) + m = m / 4 + call cftmdl1(m, a(n - m), w(nw - m / 2)) + end do + call cftleaf(m, 1, a(n - m), nw, w) + k = 0 + do j = n - m, m, -m + k = k + 1 + isplt = cfttree(m, j, k, a, nw, w) + call cftleaf(m, isplt, a(j - m), nw, w) + end do + end +! + integer function cfttree(n, j, k, a, nw, w) + integer n, j, k, nw, i, isplt, m + real*8 a(0 : j - 1), w(0 : nw - 1) + if (mod(k, 4) .ne. 0) then + isplt = mod(k, 2) + if (isplt .ne. 0) then + call cftmdl1(n, a(j - n), w(nw - n / 2)) + else + call cftmdl2(n, a(j - n), w(nw - n)) + end if + else + m = n + i = k + do while (mod(i, 4) .eq. 0) + m = m * 4 + i = i / 4 + end do + isplt = mod(i, 2) + if (isplt .ne. 0) then + do while (m .gt. 128) + call cftmdl1(m, a(j - m), w(nw - m / 2)) + m = m / 4 + end do + else + do while (m .gt. 128) + call cftmdl2(m, a(j - m), w(nw - m)) + m = m / 4 + end do + end if + end if + cfttree = isplt + end +! + subroutine cftleaf(n, isplt, a, nw, w) + integer n, isplt, nw + real*8 a(0 : n - 1), w(0 : nw - 1) + if (n .eq. 512) then + call cftmdl1(128, a, w(nw - 64)) + call cftf161(a, w(nw - 8)) + call cftf162(a(32), w(nw - 32)) + call cftf161(a(64), w(nw - 8)) + call cftf161(a(96), w(nw - 8)) + call cftmdl2(128, a(128), w(nw - 128)) + call cftf161(a(128), w(nw - 8)) + call cftf162(a(160), w(nw - 32)) + call cftf161(a(192), w(nw - 8)) + call cftf162(a(224), w(nw - 32)) + call cftmdl1(128, a(256), w(nw - 64)) + call cftf161(a(256), w(nw - 8)) + call cftf162(a(288), w(nw - 32)) + call cftf161(a(320), w(nw - 8)) + call cftf161(a(352), w(nw - 8)) + if (isplt .ne. 0) then + call cftmdl1(128, a(384), w(nw - 64)) + call cftf161(a(480), w(nw - 8)) + else + call cftmdl2(128, a(384), w(nw - 128)) + call cftf162(a(480), w(nw - 32)) + end if + call cftf161(a(384), w(nw - 8)) + call cftf162(a(416), w(nw - 32)) + call cftf161(a(448), w(nw - 8)) + else + call cftmdl1(64, a, w(nw - 32)) + call cftf081(a, w(nw - 8)) + call cftf082(a(16), w(nw - 8)) + call cftf081(a(32), w(nw - 8)) + call cftf081(a(48), w(nw - 8)) + call cftmdl2(64, a(64), w(nw - 64)) + call cftf081(a(64), w(nw - 8)) + call cftf082(a(80), w(nw - 8)) + call cftf081(a(96), w(nw - 8)) + call cftf082(a(112), w(nw - 8)) + call cftmdl1(64, a(128), w(nw - 32)) + call cftf081(a(128), w(nw - 8)) + call cftf082(a(144), w(nw - 8)) + call cftf081(a(160), w(nw - 8)) + call cftf081(a(176), w(nw - 8)) + if (isplt .ne. 0) then + call cftmdl1(64, a(192), w(nw - 32)) + call cftf081(a(240), w(nw - 8)) + else + call cftmdl2(64, a(192), w(nw - 64)) + call cftf082(a(240), w(nw - 8)) + end if + call cftf081(a(192), w(nw - 8)) + call cftf082(a(208), w(nw - 8)) + call cftf081(a(224), w(nw - 8)) + end if + end +! + subroutine cftmdl1(n, a, w) + integer n, j, j0, j1, j2, j3, k, m, mh + real*8 a(0 : n - 1), w(0 : *) + real*8 wn4r, wk1r, wk1i, wk3r, wk3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + mh = n / 8 + m = 2 * mh + j1 = m + j2 = j1 + m + j3 = j2 + m + x0r = a(0) + a(j2) + x0i = a(1) + a(j2 + 1) + x1r = a(0) - a(j2) + x1i = a(1) - a(j2 + 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + a(0) = x0r + x2r + a(1) = x0i + x2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i - x2i + a(j2) = x1r - x3i + a(j2 + 1) = x1i + x3r + a(j3) = x1r + x3i + a(j3 + 1) = x1i - x3r + wn4r = w(1) + k = 0 + do j = 2, mh - 2, 2 + k = k + 4 + wk1r = w(k) + wk1i = w(k + 1) + wk3r = w(k + 2) + wk3i = w(k + 3) + j1 = j + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j) + a(j2) + x0i = a(j + 1) + a(j2 + 1) + x1r = a(j) - a(j2) + x1i = a(j + 1) - a(j2 + 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + a(j) = x0r + x2r + a(j + 1) = x0i + x2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + a(j2) = wk1r * x0r - wk1i * x0i + a(j2 + 1) = wk1r * x0i + wk1i * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j3) = wk3r * x0r + wk3i * x0i + a(j3 + 1) = wk3r * x0i - wk3i * x0r + j0 = m - j + j1 = j0 + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j0) + a(j2) + x0i = a(j0 + 1) + a(j2 + 1) + x1r = a(j0) - a(j2) + x1i = a(j0 + 1) - a(j2 + 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + a(j0) = x0r + x2r + a(j0 + 1) = x0i + x2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + a(j2) = wk1i * x0r - wk1r * x0i + a(j2 + 1) = wk1i * x0i + wk1r * x0r + x0r = x1r + x3i + x0i = x1i - x3r + a(j3) = wk3i * x0r + wk3r * x0i + a(j3 + 1) = wk3i * x0i - wk3r * x0r + end do + j0 = mh + j1 = j0 + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j0) + a(j2) + x0i = a(j0 + 1) + a(j2 + 1) + x1r = a(j0) - a(j2) + x1i = a(j0 + 1) - a(j2 + 1) + x2r = a(j1) + a(j3) + x2i = a(j1 + 1) + a(j3 + 1) + x3r = a(j1) - a(j3) + x3i = a(j1 + 1) - a(j3 + 1) + a(j0) = x0r + x2r + a(j0 + 1) = x0i + x2i + a(j1) = x0r - x2r + a(j1 + 1) = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + a(j2) = wn4r * (x0r - x0i) + a(j2 + 1) = wn4r * (x0i + x0r) + x0r = x1r + x3i + x0i = x1i - x3r + a(j3) = -wn4r * (x0r + x0i) + a(j3 + 1) = -wn4r * (x0i - x0r) + end +! + subroutine cftmdl2(n, a, w) + integer n, j, j0, j1, j2, j3, k, kr, m, mh + real*8 a(0 : n - 1), w(0 : *) + real*8 wn4r, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + real*8 y0r, y0i, y2r, y2i + mh = n / 8 + m = 2 * mh + wn4r = w(1) + j1 = m + j2 = j1 + m + j3 = j2 + m + x0r = a(0) - a(j2 + 1) + x0i = a(1) + a(j2) + x1r = a(0) + a(j2 + 1) + x1i = a(1) - a(j2) + x2r = a(j1) - a(j3 + 1) + x2i = a(j1 + 1) + a(j3) + x3r = a(j1) + a(j3 + 1) + x3i = a(j1 + 1) - a(j3) + y0r = wn4r * (x2r - x2i) + y0i = wn4r * (x2i + x2r) + a(0) = x0r + y0r + a(1) = x0i + y0i + a(j1) = x0r - y0r + a(j1 + 1) = x0i - y0i + y0r = wn4r * (x3r - x3i) + y0i = wn4r * (x3i + x3r) + a(j2) = x1r - y0i + a(j2 + 1) = x1i + y0r + a(j3) = x1r + y0i + a(j3 + 1) = x1i - y0r + k = 0 + kr = 2 * m + do j = 2, mh - 2, 2 + k = k + 4 + wk1r = w(k) + wk1i = w(k + 1) + wk3r = w(k + 2) + wk3i = w(k + 3) + kr = kr - 4 + wd1i = w(kr) + wd1r = w(kr + 1) + wd3i = w(kr + 2) + wd3r = w(kr + 3) + j1 = j + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j) - a(j2 + 1) + x0i = a(j + 1) + a(j2) + x1r = a(j) + a(j2 + 1) + x1i = a(j + 1) - a(j2) + x2r = a(j1) - a(j3 + 1) + x2i = a(j1 + 1) + a(j3) + x3r = a(j1) + a(j3 + 1) + x3i = a(j1 + 1) - a(j3) + y0r = wk1r * x0r - wk1i * x0i + y0i = wk1r * x0i + wk1i * x0r + y2r = wd1r * x2r - wd1i * x2i + y2i = wd1r * x2i + wd1i * x2r + a(j) = y0r + y2r + a(j + 1) = y0i + y2i + a(j1) = y0r - y2r + a(j1 + 1) = y0i - y2i + y0r = wk3r * x1r + wk3i * x1i + y0i = wk3r * x1i - wk3i * x1r + y2r = wd3r * x3r + wd3i * x3i + y2i = wd3r * x3i - wd3i * x3r + a(j2) = y0r + y2r + a(j2 + 1) = y0i + y2i + a(j3) = y0r - y2r + a(j3 + 1) = y0i - y2i + j0 = m - j + j1 = j0 + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j0) - a(j2 + 1) + x0i = a(j0 + 1) + a(j2) + x1r = a(j0) + a(j2 + 1) + x1i = a(j0 + 1) - a(j2) + x2r = a(j1) - a(j3 + 1) + x2i = a(j1 + 1) + a(j3) + x3r = a(j1) + a(j3 + 1) + x3i = a(j1 + 1) - a(j3) + y0r = wd1i * x0r - wd1r * x0i + y0i = wd1i * x0i + wd1r * x0r + y2r = wk1i * x2r - wk1r * x2i + y2i = wk1i * x2i + wk1r * x2r + a(j0) = y0r + y2r + a(j0 + 1) = y0i + y2i + a(j1) = y0r - y2r + a(j1 + 1) = y0i - y2i + y0r = wd3i * x1r + wd3r * x1i + y0i = wd3i * x1i - wd3r * x1r + y2r = wk3i * x3r + wk3r * x3i + y2i = wk3i * x3i - wk3r * x3r + a(j2) = y0r + y2r + a(j2 + 1) = y0i + y2i + a(j3) = y0r - y2r + a(j3 + 1) = y0i - y2i + end do + wk1r = w(m) + wk1i = w(m + 1) + j0 = mh + j1 = j0 + m + j2 = j1 + m + j3 = j2 + m + x0r = a(j0) - a(j2 + 1) + x0i = a(j0 + 1) + a(j2) + x1r = a(j0) + a(j2 + 1) + x1i = a(j0 + 1) - a(j2) + x2r = a(j1) - a(j3 + 1) + x2i = a(j1 + 1) + a(j3) + x3r = a(j1) + a(j3 + 1) + x3i = a(j1 + 1) - a(j3) + y0r = wk1r * x0r - wk1i * x0i + y0i = wk1r * x0i + wk1i * x0r + y2r = wk1i * x2r - wk1r * x2i + y2i = wk1i * x2i + wk1r * x2r + a(j0) = y0r + y2r + a(j0 + 1) = y0i + y2i + a(j1) = y0r - y2r + a(j1 + 1) = y0i - y2i + y0r = wk1i * x1r - wk1r * x1i + y0i = wk1i * x1i + wk1r * x1r + y2r = wk1r * x3r - wk1i * x3i + y2i = wk1r * x3i + wk1i * x3r + a(j2) = y0r - y2r + a(j2 + 1) = y0i - y2i + a(j3) = y0r + y2r + a(j3 + 1) = y0i + y2i + end +! + subroutine cftfx41(n, a, nw, w) + integer n, nw + real*8 a(0 : n - 1), w(0 : nw - 1) + if (n .eq. 128) then + call cftf161(a, w(nw - 8)) + call cftf162(a(32), w(nw - 32)) + call cftf161(a(64), w(nw - 8)) + call cftf161(a(96), w(nw - 8)) + else + call cftf081(a, w(nw - 8)) + call cftf082(a(16), w(nw - 8)) + call cftf081(a(32), w(nw - 8)) + call cftf081(a(48), w(nw - 8)) + end if + end +! + subroutine cftf161(a, w) + real*8 a(0 : 31), w(0 : *), wn4r, wk1r, wk1i + real*8 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + real*8 y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i + real*8 y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i + real*8 y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i + real*8 y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i + wn4r = w(1) + wk1r = w(2) + wk1i = w(3) + x0r = a(0) + a(16) + x0i = a(1) + a(17) + x1r = a(0) - a(16) + x1i = a(1) - a(17) + x2r = a(8) + a(24) + x2i = a(9) + a(25) + x3r = a(8) - a(24) + x3i = a(9) - a(25) + y0r = x0r + x2r + y0i = x0i + x2i + y4r = x0r - x2r + y4i = x0i - x2i + y8r = x1r - x3i + y8i = x1i + x3r + y12r = x1r + x3i + y12i = x1i - x3r + x0r = a(2) + a(18) + x0i = a(3) + a(19) + x1r = a(2) - a(18) + x1i = a(3) - a(19) + x2r = a(10) + a(26) + x2i = a(11) + a(27) + x3r = a(10) - a(26) + x3i = a(11) - a(27) + y1r = x0r + x2r + y1i = x0i + x2i + y5r = x0r - x2r + y5i = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + y9r = wk1r * x0r - wk1i * x0i + y9i = wk1r * x0i + wk1i * x0r + x0r = x1r + x3i + x0i = x1i - x3r + y13r = wk1i * x0r - wk1r * x0i + y13i = wk1i * x0i + wk1r * x0r + x0r = a(4) + a(20) + x0i = a(5) + a(21) + x1r = a(4) - a(20) + x1i = a(5) - a(21) + x2r = a(12) + a(28) + x2i = a(13) + a(29) + x3r = a(12) - a(28) + x3i = a(13) - a(29) + y2r = x0r + x2r + y2i = x0i + x2i + y6r = x0r - x2r + y6i = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + y10r = wn4r * (x0r - x0i) + y10i = wn4r * (x0i + x0r) + x0r = x1r + x3i + x0i = x1i - x3r + y14r = wn4r * (x0r + x0i) + y14i = wn4r * (x0i - x0r) + x0r = a(6) + a(22) + x0i = a(7) + a(23) + x1r = a(6) - a(22) + x1i = a(7) - a(23) + x2r = a(14) + a(30) + x2i = a(15) + a(31) + x3r = a(14) - a(30) + x3i = a(15) - a(31) + y3r = x0r + x2r + y3i = x0i + x2i + y7r = x0r - x2r + y7i = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + y11r = wk1i * x0r - wk1r * x0i + y11i = wk1i * x0i + wk1r * x0r + x0r = x1r + x3i + x0i = x1i - x3r + y15r = wk1r * x0r - wk1i * x0i + y15i = wk1r * x0i + wk1i * x0r + x0r = y12r - y14r + x0i = y12i - y14i + x1r = y12r + y14r + x1i = y12i + y14i + x2r = y13r - y15r + x2i = y13i - y15i + x3r = y13r + y15r + x3i = y13i + y15i + a(24) = x0r + x2r + a(25) = x0i + x2i + a(26) = x0r - x2r + a(27) = x0i - x2i + a(28) = x1r - x3i + a(29) = x1i + x3r + a(30) = x1r + x3i + a(31) = x1i - x3r + x0r = y8r + y10r + x0i = y8i + y10i + x1r = y8r - y10r + x1i = y8i - y10i + x2r = y9r + y11r + x2i = y9i + y11i + x3r = y9r - y11r + x3i = y9i - y11i + a(16) = x0r + x2r + a(17) = x0i + x2i + a(18) = x0r - x2r + a(19) = x0i - x2i + a(20) = x1r - x3i + a(21) = x1i + x3r + a(22) = x1r + x3i + a(23) = x1i - x3r + x0r = y5r - y7i + x0i = y5i + y7r + x2r = wn4r * (x0r - x0i) + x2i = wn4r * (x0i + x0r) + x0r = y5r + y7i + x0i = y5i - y7r + x3r = wn4r * (x0r - x0i) + x3i = wn4r * (x0i + x0r) + x0r = y4r - y6i + x0i = y4i + y6r + x1r = y4r + y6i + x1i = y4i - y6r + a(8) = x0r + x2r + a(9) = x0i + x2i + a(10) = x0r - x2r + a(11) = x0i - x2i + a(12) = x1r - x3i + a(13) = x1i + x3r + a(14) = x1r + x3i + a(15) = x1i - x3r + x0r = y0r + y2r + x0i = y0i + y2i + x1r = y0r - y2r + x1i = y0i - y2i + x2r = y1r + y3r + x2i = y1i + y3i + x3r = y1r - y3r + x3i = y1i - y3i + a(0) = x0r + x2r + a(1) = x0i + x2i + a(2) = x0r - x2r + a(3) = x0i - x2i + a(4) = x1r - x3i + a(5) = x1i + x3r + a(6) = x1r + x3i + a(7) = x1i - x3r + end +! + subroutine cftf162(a, w) + real*8 a(0 : 31), w(0 : *) + real*8 wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i + real*8 x0r, x0i, x1r, x1i, x2r, x2i + real*8 y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i + real*8 y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i + real*8 y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i + real*8 y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i + wn4r = w(1) + wk1r = w(4) + wk1i = w(5) + wk3r = w(6) + wk3i = -w(7) + wk2r = w(8) + wk2i = w(9) + x1r = a(0) - a(17) + x1i = a(1) + a(16) + x0r = a(8) - a(25) + x0i = a(9) + a(24) + x2r = wn4r * (x0r - x0i) + x2i = wn4r * (x0i + x0r) + y0r = x1r + x2r + y0i = x1i + x2i + y4r = x1r - x2r + y4i = x1i - x2i + x1r = a(0) + a(17) + x1i = a(1) - a(16) + x0r = a(8) + a(25) + x0i = a(9) - a(24) + x2r = wn4r * (x0r - x0i) + x2i = wn4r * (x0i + x0r) + y8r = x1r - x2i + y8i = x1i + x2r + y12r = x1r + x2i + y12i = x1i - x2r + x0r = a(2) - a(19) + x0i = a(3) + a(18) + x1r = wk1r * x0r - wk1i * x0i + x1i = wk1r * x0i + wk1i * x0r + x0r = a(10) - a(27) + x0i = a(11) + a(26) + x2r = wk3i * x0r - wk3r * x0i + x2i = wk3i * x0i + wk3r * x0r + y1r = x1r + x2r + y1i = x1i + x2i + y5r = x1r - x2r + y5i = x1i - x2i + x0r = a(2) + a(19) + x0i = a(3) - a(18) + x1r = wk3r * x0r - wk3i * x0i + x1i = wk3r * x0i + wk3i * x0r + x0r = a(10) + a(27) + x0i = a(11) - a(26) + x2r = wk1r * x0r + wk1i * x0i + x2i = wk1r * x0i - wk1i * x0r + y9r = x1r - x2r + y9i = x1i - x2i + y13r = x1r + x2r + y13i = x1i + x2i + x0r = a(4) - a(21) + x0i = a(5) + a(20) + x1r = wk2r * x0r - wk2i * x0i + x1i = wk2r * x0i + wk2i * x0r + x0r = a(12) - a(29) + x0i = a(13) + a(28) + x2r = wk2i * x0r - wk2r * x0i + x2i = wk2i * x0i + wk2r * x0r + y2r = x1r + x2r + y2i = x1i + x2i + y6r = x1r - x2r + y6i = x1i - x2i + x0r = a(4) + a(21) + x0i = a(5) - a(20) + x1r = wk2i * x0r - wk2r * x0i + x1i = wk2i * x0i + wk2r * x0r + x0r = a(12) + a(29) + x0i = a(13) - a(28) + x2r = wk2r * x0r - wk2i * x0i + x2i = wk2r * x0i + wk2i * x0r + y10r = x1r - x2r + y10i = x1i - x2i + y14r = x1r + x2r + y14i = x1i + x2i + x0r = a(6) - a(23) + x0i = a(7) + a(22) + x1r = wk3r * x0r - wk3i * x0i + x1i = wk3r * x0i + wk3i * x0r + x0r = a(14) - a(31) + x0i = a(15) + a(30) + x2r = wk1i * x0r - wk1r * x0i + x2i = wk1i * x0i + wk1r * x0r + y3r = x1r + x2r + y3i = x1i + x2i + y7r = x1r - x2r + y7i = x1i - x2i + x0r = a(6) + a(23) + x0i = a(7) - a(22) + x1r = wk1i * x0r + wk1r * x0i + x1i = wk1i * x0i - wk1r * x0r + x0r = a(14) + a(31) + x0i = a(15) - a(30) + x2r = wk3i * x0r - wk3r * x0i + x2i = wk3i * x0i + wk3r * x0r + y11r = x1r + x2r + y11i = x1i + x2i + y15r = x1r - x2r + y15i = x1i - x2i + x1r = y0r + y2r + x1i = y0i + y2i + x2r = y1r + y3r + x2i = y1i + y3i + a(0) = x1r + x2r + a(1) = x1i + x2i + a(2) = x1r - x2r + a(3) = x1i - x2i + x1r = y0r - y2r + x1i = y0i - y2i + x2r = y1r - y3r + x2i = y1i - y3i + a(4) = x1r - x2i + a(5) = x1i + x2r + a(6) = x1r + x2i + a(7) = x1i - x2r + x1r = y4r - y6i + x1i = y4i + y6r + x0r = y5r - y7i + x0i = y5i + y7r + x2r = wn4r * (x0r - x0i) + x2i = wn4r * (x0i + x0r) + a(8) = x1r + x2r + a(9) = x1i + x2i + a(10) = x1r - x2r + a(11) = x1i - x2i + x1r = y4r + y6i + x1i = y4i - y6r + x0r = y5r + y7i + x0i = y5i - y7r + x2r = wn4r * (x0r - x0i) + x2i = wn4r * (x0i + x0r) + a(12) = x1r - x2i + a(13) = x1i + x2r + a(14) = x1r + x2i + a(15) = x1i - x2r + x1r = y8r + y10r + x1i = y8i + y10i + x2r = y9r - y11r + x2i = y9i - y11i + a(16) = x1r + x2r + a(17) = x1i + x2i + a(18) = x1r - x2r + a(19) = x1i - x2i + x1r = y8r - y10r + x1i = y8i - y10i + x2r = y9r + y11r + x2i = y9i + y11i + a(20) = x1r - x2i + a(21) = x1i + x2r + a(22) = x1r + x2i + a(23) = x1i - x2r + x1r = y12r - y14i + x1i = y12i + y14r + x0r = y13r + y15i + x0i = y13i - y15r + x2r = wn4r * (x0r - x0i) + x2i = wn4r * (x0i + x0r) + a(24) = x1r + x2r + a(25) = x1i + x2i + a(26) = x1r - x2r + a(27) = x1i - x2i + x1r = y12r + y14i + x1i = y12i - y14r + x0r = y13r - y15i + x0i = y13i + y15r + x2r = wn4r * (x0r - x0i) + x2i = wn4r * (x0i + x0r) + a(28) = x1r - x2i + a(29) = x1i + x2r + a(30) = x1r + x2i + a(31) = x1i - x2r + end +! + subroutine cftf081(a, w) + real*8 a(0 : 15), w(0 : *) + real*8 wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + real*8 y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i + real*8 y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i + wn4r = w(1) + x0r = a(0) + a(8) + x0i = a(1) + a(9) + x1r = a(0) - a(8) + x1i = a(1) - a(9) + x2r = a(4) + a(12) + x2i = a(5) + a(13) + x3r = a(4) - a(12) + x3i = a(5) - a(13) + y0r = x0r + x2r + y0i = x0i + x2i + y2r = x0r - x2r + y2i = x0i - x2i + y1r = x1r - x3i + y1i = x1i + x3r + y3r = x1r + x3i + y3i = x1i - x3r + x0r = a(2) + a(10) + x0i = a(3) + a(11) + x1r = a(2) - a(10) + x1i = a(3) - a(11) + x2r = a(6) + a(14) + x2i = a(7) + a(15) + x3r = a(6) - a(14) + x3i = a(7) - a(15) + y4r = x0r + x2r + y4i = x0i + x2i + y6r = x0r - x2r + y6i = x0i - x2i + x0r = x1r - x3i + x0i = x1i + x3r + x2r = x1r + x3i + x2i = x1i - x3r + y5r = wn4r * (x0r - x0i) + y5i = wn4r * (x0r + x0i) + y7r = wn4r * (x2r - x2i) + y7i = wn4r * (x2r + x2i) + a(8) = y1r + y5r + a(9) = y1i + y5i + a(10) = y1r - y5r + a(11) = y1i - y5i + a(12) = y3r - y7i + a(13) = y3i + y7r + a(14) = y3r + y7i + a(15) = y3i - y7r + a(0) = y0r + y4r + a(1) = y0i + y4i + a(2) = y0r - y4r + a(3) = y0i - y4i + a(4) = y2r - y6i + a(5) = y2i + y6r + a(6) = y2r + y6i + a(7) = y2i - y6r + end +! + subroutine cftf082(a, w) + real*8 a(0 : 15), w(0 : *) + real*8 wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i + real*8 y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i + real*8 y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i + wn4r = w(1) + wk1r = w(2) + wk1i = w(3) + y0r = a(0) - a(9) + y0i = a(1) + a(8) + y1r = a(0) + a(9) + y1i = a(1) - a(8) + x0r = a(4) - a(13) + x0i = a(5) + a(12) + y2r = wn4r * (x0r - x0i) + y2i = wn4r * (x0i + x0r) + x0r = a(4) + a(13) + x0i = a(5) - a(12) + y3r = wn4r * (x0r - x0i) + y3i = wn4r * (x0i + x0r) + x0r = a(2) - a(11) + x0i = a(3) + a(10) + y4r = wk1r * x0r - wk1i * x0i + y4i = wk1r * x0i + wk1i * x0r + x0r = a(2) + a(11) + x0i = a(3) - a(10) + y5r = wk1i * x0r - wk1r * x0i + y5i = wk1i * x0i + wk1r * x0r + x0r = a(6) - a(15) + x0i = a(7) + a(14) + y6r = wk1i * x0r - wk1r * x0i + y6i = wk1i * x0i + wk1r * x0r + x0r = a(6) + a(15) + x0i = a(7) - a(14) + y7r = wk1r * x0r - wk1i * x0i + y7i = wk1r * x0i + wk1i * x0r + x0r = y0r + y2r + x0i = y0i + y2i + x1r = y4r + y6r + x1i = y4i + y6i + a(0) = x0r + x1r + a(1) = x0i + x1i + a(2) = x0r - x1r + a(3) = x0i - x1i + x0r = y0r - y2r + x0i = y0i - y2i + x1r = y4r - y6r + x1i = y4i - y6i + a(4) = x0r - x1i + a(5) = x0i + x1r + a(6) = x0r + x1i + a(7) = x0i - x1r + x0r = y1r - y3i + x0i = y1i + y3r + x1r = y5r - y7r + x1i = y5i - y7i + a(8) = x0r + x1r + a(9) = x0i + x1i + a(10) = x0r - x1r + a(11) = x0i - x1i + x0r = y1r + y3i + x0i = y1i - y3r + x1r = y5r + y7r + x1i = y5i + y7i + a(12) = x0r - x1i + a(13) = x0i + x1r + a(14) = x0r + x1i + a(15) = x0i - x1r + end +! + subroutine cftf040(a) + real*8 a(0 : 7), x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + x0r = a(0) + a(4) + x0i = a(1) + a(5) + x1r = a(0) - a(4) + x1i = a(1) - a(5) + x2r = a(2) + a(6) + x2i = a(3) + a(7) + x3r = a(2) - a(6) + x3i = a(3) - a(7) + a(0) = x0r + x2r + a(1) = x0i + x2i + a(2) = x1r - x3i + a(3) = x1i + x3r + a(4) = x0r - x2r + a(5) = x0i - x2i + a(6) = x1r + x3i + a(7) = x1i - x3r + end +! + subroutine cftb040(a) + real*8 a(0 : 7), x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i + x0r = a(0) + a(4) + x0i = a(1) + a(5) + x1r = a(0) - a(4) + x1i = a(1) - a(5) + x2r = a(2) + a(6) + x2i = a(3) + a(7) + x3r = a(2) - a(6) + x3i = a(3) - a(7) + a(0) = x0r + x2r + a(1) = x0i + x2i + a(2) = x1r + x3i + a(3) = x1i - x3r + a(4) = x0r - x2r + a(5) = x0i - x2i + a(6) = x1r - x3i + a(7) = x1i + x3r + end +! + subroutine cftx020(a) + real*8 a(0 : 3), x0r, x0i + x0r = a(0) - a(2) + x0i = a(1) - a(3) + a(0) = a(0) + a(2) + a(1) = a(1) + a(3) + a(2) = x0r + a(3) = x0i + end +! + subroutine rftfsub(n, a, nc, c) + integer n, nc, j, k, kk, ks, m + real*8 a(0 : n - 1), c(0 : nc - 1), wkr, wki, xr, xi, yr, yi + m = n / 2 + ks = 2 * nc / m + kk = 0 + do j = 2, m - 2, 2 + k = n - j + kk = kk + ks + wkr = 0.5d0 - c(nc - kk) + wki = c(kk) + xr = a(j) - a(k) + xi = a(j + 1) + a(k + 1) + yr = wkr * xr - wki * xi + yi = wkr * xi + wki * xr + a(j) = a(j) - yr + a(j + 1) = a(j + 1) - yi + a(k) = a(k) + yr + a(k + 1) = a(k + 1) - yi + end do + end +! + subroutine rftbsub(n, a, nc, c) + integer n, nc, j, k, kk, ks, m + real*8 a(0 : n - 1), c(0 : nc - 1), wkr, wki, xr, xi, yr, yi + m = n / 2 + ks = 2 * nc / m + kk = 0 + do j = 2, m - 2, 2 + k = n - j + kk = kk + ks + wkr = 0.5d0 - c(nc - kk) + wki = c(kk) + xr = a(j) - a(k) + xi = a(j + 1) + a(k + 1) + yr = wkr * xr + wki * xi + yi = wkr * xi - wki * xr + a(j) = a(j) - yr + a(j + 1) = a(j + 1) - yi + a(k) = a(k) + yr + a(k + 1) = a(k + 1) - yi + end do + end +! + subroutine dctsub(n, a, nc, c) + integer n, nc, j, k, kk, ks, m + real*8 a(0 : n - 1), c(0 : nc - 1), wkr, wki, xr + m = n / 2 + ks = nc / n + kk = 0 + do j = 1, m - 1 + k = n - j + kk = kk + ks + wkr = c(kk) - c(nc - kk) + wki = c(kk) + c(nc - kk) + xr = wki * a(j) - wkr * a(k) + a(j) = wkr * a(j) + wki * a(k) + a(k) = xr + end do + a(m) = c(0) * a(m) + end +! + subroutine dstsub(n, a, nc, c) + integer n, nc, j, k, kk, ks, m + real*8 a(0 : n - 1), c(0 : nc - 1), wkr, wki, xr + m = n / 2 + ks = nc / n + kk = 0 + do j = 1, m - 1 + k = n - j + kk = kk + ks + wkr = c(kk) - c(nc - kk) + wki = c(kk) + c(nc - kk) + xr = wki * a(k) - wkr * a(j) + a(k) = wkr * a(k) + wki * a(j) + a(j) = xr + end do + a(m) = c(0) * a(m) + end +!
diff --git a/third_party/tensorflow_dependencies/fft2d/fftsg2d.c b/third_party/tensorflow_dependencies/fft2d/fftsg2d.c new file mode 100644 index 0000000..2ebfa93 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/fftsg2d.c
@@ -0,0 +1,1190 @@ +/* +Fast Fourier/Cosine/Sine Transform + dimension :two + data length :power of 2 + decimation :frequency + radix :split-radix, row-column + data :inplace + table :use +functions + cdft2d: Complex Discrete Fourier Transform + rdft2d: Real Discrete Fourier Transform + ddct2d: Discrete Cosine Transform + ddst2d: Discrete Sine Transform +function prototypes + void cdft2d(int, int, int, double **, double *, int *, double *); + void rdft2d(int, int, int, double **, double *, int *, double *); + void rdft2dsort(int, int, int, double **); + void ddct2d(int, int, int, double **, double *, int *, double *); + void ddst2d(int, int, int, double **, double *, int *, double *); +necessary package + fftsg.c : 1D-FFT package +macro definitions + USE_FFT2D_PTHREADS : default=not defined + FFT2D_MAX_THREADS : must be 2^N, default=4 + FFT2D_THREADS_BEGIN_N : default=65536 + USE_FFT2D_WINTHREADS : default=not defined + FFT2D_MAX_THREADS : must be 2^N, default=4 + FFT2D_THREADS_BEGIN_N : default=131072 + + +-------- Complex DFT (Discrete Fourier Transform) -------- + [definition] + <case1> + X[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 x[j1][j2] * + exp(2*pi*i*j1*k1/n1) * + exp(2*pi*i*j2*k2/n2), 0<=k1<n1, 0<=k2<n2 + <case2> + X[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 x[j1][j2] * + exp(-2*pi*i*j1*k1/n1) * + exp(-2*pi*i*j2*k2/n2), 0<=k1<n1, 0<=k2<n2 + (notes: sum_j=0^n-1 is a summation from j=0 to n-1) + [usage] + <case1> + ip[0] = 0; // first time only + cdft2d(n1, 2*n2, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + cdft2d(n1, 2*n2, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 1, n1 = power of 2 + 2*n2 :data length (int) + n2 >= 1, n2 = power of 2 + a[0...n1-1][0...2*n2-1] + :input/output data (double **) + input data + a[j1][2*j2] = Re(x[j1][j2]), + a[j1][2*j2+1] = Im(x[j1][j2]), + 0<=j1<n1, 0<=j2<n2 + output data + a[k1][2*k2] = Re(X[k1][k2]), + a[k1][2*k2+1] = Im(X[k1][k2]), + 0<=k1<n1, 0<=k2<n2 + t[0...*] + :work area (double *) + length of t >= 8*n1, if single thread, + length of t >= 8*n1*FFT2D_MAX_THREADS, if multi threads, + t is dynamically allocated, if t == NULL. + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1, n2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1/2, n2/2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + cdft2d(n1, 2*n2, -1, a, t, ip, w); + is + cdft2d(n1, 2*n2, 1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= 2 * n2 - 1; j2++) { + a[j1][j2] *= 1.0 / n1 / n2; + } + } + . + + +-------- Real DFT / Inverse of Real DFT -------- + [definition] + <case1> RDFT + R[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2), + 0<=k1<n1, 0<=k2<n2 + I[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2), + 0<=k1<n1, 0<=k2<n2 + <case2> IRDFT (excluding scale) + a[k1][k2] = (1/2) * sum_j1=0^n1-1 sum_j2=0^n2-1 + (R[j1][j2] * + cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2) + + I[j1][j2] * + sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2)), + 0<=k1<n1, 0<=k2<n2 + (notes: R[n1-k1][n2-k2] = R[k1][k2], + I[n1-k1][n2-k2] = -I[k1][k2], + R[n1-k1][0] = R[k1][0], + I[n1-k1][0] = -I[k1][0], + R[0][n2-k2] = R[0][k2], + I[0][n2-k2] = -I[0][k2], + 0<k1<n1, 0<k2<n2) + [usage] + <case1> + ip[0] = 0; // first time only + rdft2d(n1, n2, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + rdft2d(n1, n2, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + a[0...n1-1][0...n2-1] + :input/output data (double **) + <case1> + output data + a[k1][2*k2] = R[k1][k2] = R[n1-k1][n2-k2], + a[k1][2*k2+1] = I[k1][k2] = -I[n1-k1][n2-k2], + 0<k1<n1, 0<k2<n2/2, + a[0][2*k2] = R[0][k2] = R[0][n2-k2], + a[0][2*k2+1] = I[0][k2] = -I[0][n2-k2], + 0<k2<n2/2, + a[k1][0] = R[k1][0] = R[n1-k1][0], + a[k1][1] = I[k1][0] = -I[n1-k1][0], + a[n1-k1][1] = R[k1][n2/2] = R[n1-k1][n2/2], + a[n1-k1][0] = -I[k1][n2/2] = I[n1-k1][n2/2], + 0<k1<n1/2, + a[0][0] = R[0][0], + a[0][1] = R[0][n2/2], + a[n1/2][0] = R[n1/2][0], + a[n1/2][1] = R[n1/2][n2/2] + <case2> + input data + a[j1][2*j2] = R[j1][j2] = R[n1-j1][n2-j2], + a[j1][2*j2+1] = I[j1][j2] = -I[n1-j1][n2-j2], + 0<j1<n1, 0<j2<n2/2, + a[0][2*j2] = R[0][j2] = R[0][n2-j2], + a[0][2*j2+1] = I[0][j2] = -I[0][n2-j2], + 0<j2<n2/2, + a[j1][0] = R[j1][0] = R[n1-j1][0], + a[j1][1] = I[j1][0] = -I[n1-j1][0], + a[n1-j1][1] = R[j1][n2/2] = R[n1-j1][n2/2], + a[n1-j1][0] = -I[j1][n2/2] = I[n1-j1][n2/2], + 0<j1<n1/2, + a[0][0] = R[0][0], + a[0][1] = R[0][n2/2], + a[n1/2][0] = R[n1/2][0], + a[n1/2][1] = R[n1/2][n2/2] + ---- output ordering ---- + rdft2d(n1, n2, 1, a, t, ip, w); + rdft2dsort(n1, n2, 1, a); + // stored data is a[0...n1-1][0...n2+1]: + // a[k1][2*k2] = R[k1][k2], + // a[k1][2*k2+1] = I[k1][k2], + // 0<=k1<n1, 0<=k2<=n2/2. + // the stored data is larger than the input data! + ---- input ordering ---- + rdft2dsort(n1, n2, -1, a); + rdft2d(n1, n2, -1, a, t, ip, w); + t[0...*] + :work area (double *) + length of t >= 8*n1, if single thread, + length of t >= 8*n1*FFT2D_MAX_THREADS, if multi threads, + t is dynamically allocated, if t == NULL. + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1, n2/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1/2, n2/4) + n2/4 + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + rdft2d(n1, n2, 1, a, t, ip, w); + is + rdft2d(n1, n2, -1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] *= 2.0 / n1 / n2; + } + } + . + + +-------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + <case1> IDCT (excluding scale) + C[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + cos(pi*j1*(k1+1/2)/n1) * + cos(pi*j2*(k2+1/2)/n2), + 0<=k1<n1, 0<=k2<n2 + <case2> DCT + C[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + cos(pi*(j1+1/2)*k1/n1) * + cos(pi*(j2+1/2)*k2/n2), + 0<=k1<n1, 0<=k2<n2 + [usage] + <case1> + ip[0] = 0; // first time only + ddct2d(n1, n2, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + ddct2d(n1, n2, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + a[0...n1-1][0...n2-1] + :input/output data (double **) + output data + a[k1][k2] = C[k1][k2], 0<=k1<n1, 0<=k2<n2 + t[0...*] + :work area (double *) + length of t >= 4*n1, if single thread, + length of t >= 4*n1*FFT2D_MAX_THREADS, if multi threads, + t is dynamically allocated, if t == NULL. + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1/2, n2/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1*3/2, n2*3/2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddct2d(n1, n2, -1, a, t, ip, w); + is + for (j1 = 0; j1 <= n1 - 1; j1++) { + a[j1][0] *= 0.5; + } + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[0][j2] *= 0.5; + } + ddct2d(n1, n2, 1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] *= 4.0 / n1 / n2; + } + } + . + + +-------- DST (Discrete Sine Transform) / Inverse of DST -------- + [definition] + <case1> IDST (excluding scale) + S[k1][k2] = sum_j1=1^n1 sum_j2=1^n2 A[j1][j2] * + sin(pi*j1*(k1+1/2)/n1) * + sin(pi*j2*(k2+1/2)/n2), + 0<=k1<n1, 0<=k2<n2 + <case2> DST + S[k1][k2] = sum_j1=0^n1-1 sum_j2=0^n2-1 a[j1][j2] * + sin(pi*(j1+1/2)*k1/n1) * + sin(pi*(j2+1/2)*k2/n2), + 0<k1<=n1, 0<k2<=n2 + [usage] + <case1> + ip[0] = 0; // first time only + ddst2d(n1, n2, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + ddst2d(n1, n2, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + a[0...n1-1][0...n2-1] + :input/output data (double **) + <case1> + input data + a[j1][j2] = A[j1][j2], 0<j1<n1, 0<j2<n2, + a[j1][0] = A[j1][n2], 0<j1<n1, + a[0][j2] = A[n1][j2], 0<j2<n2, + a[0][0] = A[n1][n2] + (i.e. A[j1][j2] = a[j1 % n1][j2 % n2]) + output data + a[k1][k2] = S[k1][k2], 0<=k1<n1, 0<=k2<n2 + <case2> + output data + a[k1][k2] = S[k1][k2], 0<k1<n1, 0<k2<n2, + a[k1][0] = S[k1][n2], 0<k1<n1, + a[0][k2] = S[n1][k2], 0<k2<n2, + a[0][0] = S[n1][n2] + (i.e. S[k1][k2] = a[k1 % n1][k2 % n2]) + t[0...*] + :work area (double *) + length of t >= 4*n1, if single thread, + length of t >= 4*n1*FFT2D_MAX_THREADS, if multi threads, + t is dynamically allocated, if t == NULL. + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1/2, n2/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1*3/2, n2*3/2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddst2d(n1, n2, -1, a, t, ip, w); + is + for (j1 = 0; j1 <= n1 - 1; j1++) { + a[j1][0] *= 0.5; + } + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[0][j2] *= 0.5; + } + ddst2d(n1, n2, 1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] *= 4.0 / n1 / n2; + } + } + . +*/ + + +#include <stdio.h> +#include <stdlib.h> +#define fft2d_alloc_error_check(p) { \ + if ((p) == NULL) { \ + fprintf(stderr, "fft2d memory allocation error\n"); \ + exit(1); \ + } \ +} + + +#ifdef USE_FFT2D_PTHREADS +#define USE_FFT2D_THREADS +#ifndef FFT2D_MAX_THREADS +#define FFT2D_MAX_THREADS 4 +#endif +#ifndef FFT2D_THREADS_BEGIN_N +#define FFT2D_THREADS_BEGIN_N 65536 +#endif +#include <pthread.h> +#define fft2d_thread_t pthread_t +#define fft2d_thread_create(thp,func,argp) { \ + if (pthread_create(thp, NULL, func, (void *) (argp)) != 0) { \ + fprintf(stderr, "fft2d thread error\n"); \ + exit(1); \ + } \ +} +#define fft2d_thread_wait(th) { \ + if (pthread_join(th, NULL) != 0) { \ + fprintf(stderr, "fft2d thread error\n"); \ + exit(1); \ + } \ +} +#endif /* USE_FFT2D_PTHREADS */ + + +#ifdef USE_FFT2D_WINTHREADS +#define USE_FFT2D_THREADS +#ifndef FFT2D_MAX_THREADS +#define FFT2D_MAX_THREADS 4 +#endif +#ifndef FFT2D_THREADS_BEGIN_N +#define FFT2D_THREADS_BEGIN_N 131072 +#endif +#include <windows.h> +#define fft2d_thread_t HANDLE +#define fft2d_thread_create(thp,func,argp) { \ + DWORD thid; \ + *(thp) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (func), (LPVOID) (argp), 0, &thid); \ + if (*(thp) == 0) { \ + fprintf(stderr, "fft2d thread error\n"); \ + exit(1); \ + } \ +} +#define fft2d_thread_wait(th) { \ + WaitForSingleObject(th, INFINITE); \ + CloseHandle(th); \ +} +#endif /* USE_FFT2D_WINTHREADS */ + + +void cdft2d(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void cdft(int n, int isgn, double *a, int *ip, double *w); + void cdft2d_sub(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w); +#ifdef USE_FFT2D_THREADS + void xdft2d0_subth(int n1, int n2, int icr, int isgn, double **a, + int *ip, double *w); + void cdft2d_subth(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w); +#endif /* USE_FFT2D_THREADS */ + int n, itnull, nthread, nt, i; + + n = n1 << 1; + if (n < n2) { + n = n2; + } + if (n > (ip[0] << 2)) { + makewt(n >> 2, ip, w); + } + itnull = 0; + if (t == NULL) { + itnull = 1; + nthread = 1; +#ifdef USE_FFT2D_THREADS + nthread = FFT2D_MAX_THREADS; +#endif /* USE_FFT2D_THREADS */ + nt = 8 * nthread * n1; + if (n2 == 4 * nthread) { + nt >>= 1; + } else if (n2 < 4 * nthread) { + nt >>= 2; + } + t = (double *) malloc(sizeof(double) * nt); + fft2d_alloc_error_check(t); + } +#ifdef USE_FFT2D_THREADS + if ((double) n1 * n2 >= (double) FFT2D_THREADS_BEGIN_N) { + xdft2d0_subth(n1, n2, 0, isgn, a, ip, w); + cdft2d_subth(n1, n2, isgn, a, t, ip, w); + } else +#endif /* USE_FFT2D_THREADS */ + { + for (i = 0; i < n1; i++) { + cdft(n2, isgn, a[i], ip, w); + } + cdft2d_sub(n1, n2, isgn, a, t, ip, w); + } + if (itnull != 0) { + free(t); + } +} + + +void rdft2d(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void rdft(int n, int isgn, double *a, int *ip, double *w); + void cdft2d_sub(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w); + void rdft2d_sub(int n1, int n2, int isgn, double **a); +#ifdef USE_FFT2D_THREADS + void xdft2d0_subth(int n1, int n2, int icr, int isgn, double **a, + int *ip, double *w); + void cdft2d_subth(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w); +#endif /* USE_FFT2D_THREADS */ + int n, nw, nc, itnull, nthread, nt, i; + + n = n1 << 1; + if (n < n2) { + n = n2; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n2 > (nc << 2)) { + nc = n2 >> 2; + makect(nc, ip, w + nw); + } + itnull = 0; + if (t == NULL) { + itnull = 1; + nthread = 1; +#ifdef USE_FFT2D_THREADS + nthread = FFT2D_MAX_THREADS; +#endif /* USE_FFT2D_THREADS */ + nt = 8 * nthread * n1; + if (n2 == 4 * nthread) { + nt >>= 1; + } else if (n2 < 4 * nthread) { + nt >>= 2; + } + t = (double *) malloc(sizeof(double) * nt); + fft2d_alloc_error_check(t); + } +#ifdef USE_FFT2D_THREADS + if ((double) n1 * n2 >= (double) FFT2D_THREADS_BEGIN_N) { + if (isgn < 0) { + rdft2d_sub(n1, n2, isgn, a); + cdft2d_subth(n1, n2, isgn, a, t, ip, w); + } + xdft2d0_subth(n1, n2, 1, isgn, a, ip, w); + if (isgn >= 0) { + cdft2d_subth(n1, n2, isgn, a, t, ip, w); + rdft2d_sub(n1, n2, isgn, a); + } + } else +#endif /* USE_FFT2D_THREADS */ + { + if (isgn < 0) { + rdft2d_sub(n1, n2, isgn, a); + cdft2d_sub(n1, n2, isgn, a, t, ip, w); + } + for (i = 0; i < n1; i++) { + rdft(n2, isgn, a[i], ip, w); + } + if (isgn >= 0) { + cdft2d_sub(n1, n2, isgn, a, t, ip, w); + rdft2d_sub(n1, n2, isgn, a); + } + } + if (itnull != 0) { + free(t); + } +} + + +void rdft2dsort(int n1, int n2, int isgn, double **a) +{ + int n1h, i; + double x, y; + + n1h = n1 >> 1; + if (isgn < 0) { + for (i = n1h + 1; i < n1; i++) { + a[i][0] = a[i][n2 + 1]; + a[i][1] = a[i][n2]; + } + a[0][1] = a[0][n2]; + a[n1h][1] = a[n1h][n2]; + } else { + for (i = n1h + 1; i < n1; i++) { + y = a[i][0]; + x = a[i][1]; + a[i][n2] = x; + a[i][n2 + 1] = y; + a[n1 - i][n2] = x; + a[n1 - i][n2 + 1] = -y; + a[i][0] = a[n1 - i][0]; + a[i][1] = -a[n1 - i][1]; + } + a[0][n2] = a[0][1]; + a[0][n2 + 1] = 0; + a[0][1] = 0; + a[n1h][n2] = a[n1h][1]; + a[n1h][n2 + 1] = 0; + a[n1h][1] = 0; + } +} + + +void ddct2d(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void ddct(int n, int isgn, double *a, int *ip, double *w); + void ddxt2d_sub(int n1, int n2, int ics, int isgn, double **a, + double *t, int *ip, double *w); +#ifdef USE_FFT2D_THREADS + void ddxt2d0_subth(int n1, int n2, int ics, int isgn, double **a, + int *ip, double *w); + void ddxt2d_subth(int n1, int n2, int ics, int isgn, double **a, + double *t, int *ip, double *w); +#endif /* USE_FFT2D_THREADS */ + int n, nw, nc, itnull, nthread, nt, i; + + n = n1; + if (n < n2) { + n = n2; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + itnull = 0; + if (t == NULL) { + itnull = 1; + nthread = 1; +#ifdef USE_FFT2D_THREADS + nthread = FFT2D_MAX_THREADS; +#endif /* USE_FFT2D_THREADS */ + nt = 4 * nthread * n1; + if (n2 == 2 * nthread) { + nt >>= 1; + } else if (n2 < 2 * nthread) { + nt >>= 2; + } + t = (double *) malloc(sizeof(double) * nt); + fft2d_alloc_error_check(t); + } +#ifdef USE_FFT2D_THREADS + if ((double) n1 * n2 >= (double) FFT2D_THREADS_BEGIN_N) { + ddxt2d0_subth(n1, n2, 0, isgn, a, ip, w); + ddxt2d_subth(n1, n2, 0, isgn, a, t, ip, w); + } else +#endif /* USE_FFT2D_THREADS */ + { + for (i = 0; i < n1; i++) { + ddct(n2, isgn, a[i], ip, w); + } + ddxt2d_sub(n1, n2, 0, isgn, a, t, ip, w); + } + if (itnull != 0) { + free(t); + } +} + + +void ddst2d(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void ddst(int n, int isgn, double *a, int *ip, double *w); + void ddxt2d_sub(int n1, int n2, int ics, int isgn, double **a, + double *t, int *ip, double *w); +#ifdef USE_FFT2D_THREADS + void ddxt2d0_subth(int n1, int n2, int ics, int isgn, double **a, + int *ip, double *w); + void ddxt2d_subth(int n1, int n2, int ics, int isgn, double **a, + double *t, int *ip, double *w); +#endif /* USE_FFT2D_THREADS */ + int n, nw, nc, itnull, nthread, nt, i; + + n = n1; + if (n < n2) { + n = n2; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + itnull = 0; + if (t == NULL) { + itnull = 1; + nthread = 1; +#ifdef USE_FFT2D_THREADS + nthread = FFT2D_MAX_THREADS; +#endif /* USE_FFT2D_THREADS */ + nt = 4 * nthread * n1; + if (n2 == 2 * nthread) { + nt >>= 1; + } else if (n2 < 2 * nthread) { + nt >>= 2; + } + t = (double *) malloc(sizeof(double) * nt); + fft2d_alloc_error_check(t); + } +#ifdef USE_FFT2D_THREADS + if ((double) n1 * n2 >= (double) FFT2D_THREADS_BEGIN_N) { + ddxt2d0_subth(n1, n2, 1, isgn, a, ip, w); + ddxt2d_subth(n1, n2, 1, isgn, a, t, ip, w); + } else +#endif /* USE_FFT2D_THREADS */ + { + for (i = 0; i < n1; i++) { + ddst(n2, isgn, a[i], ip, w); + } + ddxt2d_sub(n1, n2, 1, isgn, a, t, ip, w); + } + if (itnull != 0) { + free(t); + } +} + + +/* -------- child routines -------- */ + + +void cdft2d_sub(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w) +{ + void cdft(int n, int isgn, double *a, int *ip, double *w); + int i, j; + + if (n2 > 4) { + for (j = 0; j < n2; j += 8) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][j]; + t[2 * i + 1] = a[i][j + 1]; + t[2 * n1 + 2 * i] = a[i][j + 2]; + t[2 * n1 + 2 * i + 1] = a[i][j + 3]; + t[4 * n1 + 2 * i] = a[i][j + 4]; + t[4 * n1 + 2 * i + 1] = a[i][j + 5]; + t[6 * n1 + 2 * i] = a[i][j + 6]; + t[6 * n1 + 2 * i + 1] = a[i][j + 7]; + } + cdft(2 * n1, isgn, t, ip, w); + cdft(2 * n1, isgn, &t[2 * n1], ip, w); + cdft(2 * n1, isgn, &t[4 * n1], ip, w); + cdft(2 * n1, isgn, &t[6 * n1], ip, w); + for (i = 0; i < n1; i++) { + a[i][j] = t[2 * i]; + a[i][j + 1] = t[2 * i + 1]; + a[i][j + 2] = t[2 * n1 + 2 * i]; + a[i][j + 3] = t[2 * n1 + 2 * i + 1]; + a[i][j + 4] = t[4 * n1 + 2 * i]; + a[i][j + 5] = t[4 * n1 + 2 * i + 1]; + a[i][j + 6] = t[6 * n1 + 2 * i]; + a[i][j + 7] = t[6 * n1 + 2 * i + 1]; + } + } + } else if (n2 == 4) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][0]; + t[2 * i + 1] = a[i][1]; + t[2 * n1 + 2 * i] = a[i][2]; + t[2 * n1 + 2 * i + 1] = a[i][3]; + } + cdft(2 * n1, isgn, t, ip, w); + cdft(2 * n1, isgn, &t[2 * n1], ip, w); + for (i = 0; i < n1; i++) { + a[i][0] = t[2 * i]; + a[i][1] = t[2 * i + 1]; + a[i][2] = t[2 * n1 + 2 * i]; + a[i][3] = t[2 * n1 + 2 * i + 1]; + } + } else if (n2 == 2) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][0]; + t[2 * i + 1] = a[i][1]; + } + cdft(2 * n1, isgn, t, ip, w); + for (i = 0; i < n1; i++) { + a[i][0] = t[2 * i]; + a[i][1] = t[2 * i + 1]; + } + } +} + + +void rdft2d_sub(int n1, int n2, int isgn, double **a) +{ + int n1h, i, j; + double xi; + + n1h = n1 >> 1; + if (isgn < 0) { + for (i = 1; i < n1h; i++) { + j = n1 - i; + xi = a[i][0] - a[j][0]; + a[i][0] += a[j][0]; + a[j][0] = xi; + xi = a[j][1] - a[i][1]; + a[i][1] += a[j][1]; + a[j][1] = xi; + } + } else { + for (i = 1; i < n1h; i++) { + j = n1 - i; + a[j][0] = 0.5 * (a[i][0] - a[j][0]); + a[i][0] -= a[j][0]; + a[j][1] = 0.5 * (a[i][1] + a[j][1]); + a[i][1] -= a[j][1]; + } + } +} + + +void ddxt2d_sub(int n1, int n2, int ics, int isgn, double **a, + double *t, int *ip, double *w) +{ + void ddct(int n, int isgn, double *a, int *ip, double *w); + void ddst(int n, int isgn, double *a, int *ip, double *w); + int i, j; + + if (n2 > 2) { + for (j = 0; j < n2; j += 4) { + for (i = 0; i < n1; i++) { + t[i] = a[i][j]; + t[n1 + i] = a[i][j + 1]; + t[2 * n1 + i] = a[i][j + 2]; + t[3 * n1 + i] = a[i][j + 3]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + ddct(n1, isgn, &t[n1], ip, w); + ddct(n1, isgn, &t[2 * n1], ip, w); + ddct(n1, isgn, &t[3 * n1], ip, w); + } else { + ddst(n1, isgn, t, ip, w); + ddst(n1, isgn, &t[n1], ip, w); + ddst(n1, isgn, &t[2 * n1], ip, w); + ddst(n1, isgn, &t[3 * n1], ip, w); + } + for (i = 0; i < n1; i++) { + a[i][j] = t[i]; + a[i][j + 1] = t[n1 + i]; + a[i][j + 2] = t[2 * n1 + i]; + a[i][j + 3] = t[3 * n1 + i]; + } + } + } else if (n2 == 2) { + for (i = 0; i < n1; i++) { + t[i] = a[i][0]; + t[n1 + i] = a[i][1]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + ddct(n1, isgn, &t[n1], ip, w); + } else { + ddst(n1, isgn, t, ip, w); + ddst(n1, isgn, &t[n1], ip, w); + } + for (i = 0; i < n1; i++) { + a[i][0] = t[i]; + a[i][1] = t[n1 + i]; + } + } +} + + +#ifdef USE_FFT2D_THREADS +struct fft2d_arg_st { + int nthread; + int n0; + int n1; + int n2; + int ic; + int isgn; + double **a; + double *t; + int *ip; + double *w; +}; +typedef struct fft2d_arg_st fft2d_arg_t; + + +void xdft2d0_subth(int n1, int n2, int icr, int isgn, double **a, + int *ip, double *w) +{ + void *xdft2d0_th(void *p); + fft2d_thread_t th[FFT2D_MAX_THREADS]; + fft2d_arg_t ag[FFT2D_MAX_THREADS]; + int nthread, i; + + nthread = FFT2D_MAX_THREADS; + if (nthread > n1) { + nthread = n1; + } + for (i = 0; i < nthread; i++) { + ag[i].nthread = nthread; + ag[i].n0 = i; + ag[i].n1 = n1; + ag[i].n2 = n2; + ag[i].ic = icr; + ag[i].isgn = isgn; + ag[i].a = a; + ag[i].ip = ip; + ag[i].w = w; + fft2d_thread_create(&th[i], xdft2d0_th, &ag[i]); + } + for (i = 0; i < nthread; i++) { + fft2d_thread_wait(th[i]); + } +} + + +void cdft2d_subth(int n1, int n2, int isgn, double **a, double *t, + int *ip, double *w) +{ + void *cdft2d_th(void *p); + fft2d_thread_t th[FFT2D_MAX_THREADS]; + fft2d_arg_t ag[FFT2D_MAX_THREADS]; + int nthread, nt, i; + + nthread = FFT2D_MAX_THREADS; + nt = 8 * n1; + if (n2 == 4 * FFT2D_MAX_THREADS) { + nt >>= 1; + } else if (n2 < 4 * FFT2D_MAX_THREADS) { + nthread = n2 >> 1; + nt >>= 2; + } + for (i = 0; i < nthread; i++) { + ag[i].nthread = nthread; + ag[i].n0 = i; + ag[i].n1 = n1; + ag[i].n2 = n2; + ag[i].isgn = isgn; + ag[i].a = a; + ag[i].t = &t[nt * i]; + ag[i].ip = ip; + ag[i].w = w; + fft2d_thread_create(&th[i], cdft2d_th, &ag[i]); + } + for (i = 0; i < nthread; i++) { + fft2d_thread_wait(th[i]); + } +} + + +void ddxt2d0_subth(int n1, int n2, int ics, int isgn, double **a, + int *ip, double *w) +{ + void *ddxt2d0_th(void *p); + fft2d_thread_t th[FFT2D_MAX_THREADS]; + fft2d_arg_t ag[FFT2D_MAX_THREADS]; + int nthread, i; + + nthread = FFT2D_MAX_THREADS; + if (nthread > n1) { + nthread = n1; + } + for (i = 0; i < nthread; i++) { + ag[i].nthread = nthread; + ag[i].n0 = i; + ag[i].n1 = n1; + ag[i].n2 = n2; + ag[i].ic = ics; + ag[i].isgn = isgn; + ag[i].a = a; + ag[i].ip = ip; + ag[i].w = w; + fft2d_thread_create(&th[i], ddxt2d0_th, &ag[i]); + } + for (i = 0; i < nthread; i++) { + fft2d_thread_wait(th[i]); + } +} + + +void ddxt2d_subth(int n1, int n2, int ics, int isgn, double **a, + double *t, int *ip, double *w) +{ + void *ddxt2d_th(void *p); + fft2d_thread_t th[FFT2D_MAX_THREADS]; + fft2d_arg_t ag[FFT2D_MAX_THREADS]; + int nthread, nt, i; + + nthread = FFT2D_MAX_THREADS; + nt = 4 * n1; + if (n2 == 2 * FFT2D_MAX_THREADS) { + nt >>= 1; + } else if (n2 < 2 * FFT2D_MAX_THREADS) { + nthread = n2; + nt >>= 2; + } + for (i = 0; i < nthread; i++) { + ag[i].nthread = nthread; + ag[i].n0 = i; + ag[i].n1 = n1; + ag[i].n2 = n2; + ag[i].ic = ics; + ag[i].isgn = isgn; + ag[i].a = a; + ag[i].t = &t[nt * i]; + ag[i].ip = ip; + ag[i].w = w; + fft2d_thread_create(&th[i], ddxt2d_th, &ag[i]); + } + for (i = 0; i < nthread; i++) { + fft2d_thread_wait(th[i]); + } +} + + +void *xdft2d0_th(void *p) +{ + void cdft(int n, int isgn, double *a, int *ip, double *w); + void rdft(int n, int isgn, double *a, int *ip, double *w); + int nthread, n0, n1, n2, icr, isgn, *ip, i; + double **a, *w; + + nthread = ((fft2d_arg_t *) p)->nthread; + n0 = ((fft2d_arg_t *) p)->n0; + n1 = ((fft2d_arg_t *) p)->n1; + n2 = ((fft2d_arg_t *) p)->n2; + icr = ((fft2d_arg_t *) p)->ic; + isgn = ((fft2d_arg_t *) p)->isgn; + a = ((fft2d_arg_t *) p)->a; + ip = ((fft2d_arg_t *) p)->ip; + w = ((fft2d_arg_t *) p)->w; + if (icr == 0) { + for (i = n0; i < n1; i += nthread) { + cdft(n2, isgn, a[i], ip, w); + } + } else { + for (i = n0; i < n1; i += nthread) { + rdft(n2, isgn, a[i], ip, w); + } + } + return (void *) 0; +} + + +void *cdft2d_th(void *p) +{ + void cdft(int n, int isgn, double *a, int *ip, double *w); + int nthread, n0, n1, n2, isgn, *ip, i, j; + double **a, *t, *w; + + nthread = ((fft2d_arg_t *) p)->nthread; + n0 = ((fft2d_arg_t *) p)->n0; + n1 = ((fft2d_arg_t *) p)->n1; + n2 = ((fft2d_arg_t *) p)->n2; + isgn = ((fft2d_arg_t *) p)->isgn; + a = ((fft2d_arg_t *) p)->a; + t = ((fft2d_arg_t *) p)->t; + ip = ((fft2d_arg_t *) p)->ip; + w = ((fft2d_arg_t *) p)->w; + if (n2 > 4 * nthread) { + for (j = 8 * n0; j < n2; j += 8 * nthread) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][j]; + t[2 * i + 1] = a[i][j + 1]; + t[2 * n1 + 2 * i] = a[i][j + 2]; + t[2 * n1 + 2 * i + 1] = a[i][j + 3]; + t[4 * n1 + 2 * i] = a[i][j + 4]; + t[4 * n1 + 2 * i + 1] = a[i][j + 5]; + t[6 * n1 + 2 * i] = a[i][j + 6]; + t[6 * n1 + 2 * i + 1] = a[i][j + 7]; + } + cdft(2 * n1, isgn, t, ip, w); + cdft(2 * n1, isgn, &t[2 * n1], ip, w); + cdft(2 * n1, isgn, &t[4 * n1], ip, w); + cdft(2 * n1, isgn, &t[6 * n1], ip, w); + for (i = 0; i < n1; i++) { + a[i][j] = t[2 * i]; + a[i][j + 1] = t[2 * i + 1]; + a[i][j + 2] = t[2 * n1 + 2 * i]; + a[i][j + 3] = t[2 * n1 + 2 * i + 1]; + a[i][j + 4] = t[4 * n1 + 2 * i]; + a[i][j + 5] = t[4 * n1 + 2 * i + 1]; + a[i][j + 6] = t[6 * n1 + 2 * i]; + a[i][j + 7] = t[6 * n1 + 2 * i + 1]; + } + } + } else if (n2 == 4 * nthread) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][4 * n0]; + t[2 * i + 1] = a[i][4 * n0 + 1]; + t[2 * n1 + 2 * i] = a[i][4 * n0 + 2]; + t[2 * n1 + 2 * i + 1] = a[i][4 * n0 + 3]; + } + cdft(2 * n1, isgn, t, ip, w); + cdft(2 * n1, isgn, &t[2 * n1], ip, w); + for (i = 0; i < n1; i++) { + a[i][4 * n0] = t[2 * i]; + a[i][4 * n0 + 1] = t[2 * i + 1]; + a[i][4 * n0 + 2] = t[2 * n1 + 2 * i]; + a[i][4 * n0 + 3] = t[2 * n1 + 2 * i + 1]; + } + } else if (n2 == 2 * nthread) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][2 * n0]; + t[2 * i + 1] = a[i][2 * n0 + 1]; + } + cdft(2 * n1, isgn, t, ip, w); + for (i = 0; i < n1; i++) { + a[i][2 * n0] = t[2 * i]; + a[i][2 * n0 + 1] = t[2 * i + 1]; + } + } + return (void *) 0; +} + + +void *ddxt2d0_th(void *p) +{ + void ddct(int n, int isgn, double *a, int *ip, double *w); + void ddst(int n, int isgn, double *a, int *ip, double *w); + int nthread, n0, n1, n2, ics, isgn, *ip, i; + double **a, *w; + + nthread = ((fft2d_arg_t *) p)->nthread; + n0 = ((fft2d_arg_t *) p)->n0; + n1 = ((fft2d_arg_t *) p)->n1; + n2 = ((fft2d_arg_t *) p)->n2; + ics = ((fft2d_arg_t *) p)->ic; + isgn = ((fft2d_arg_t *) p)->isgn; + a = ((fft2d_arg_t *) p)->a; + ip = ((fft2d_arg_t *) p)->ip; + w = ((fft2d_arg_t *) p)->w; + if (ics == 0) { + for (i = n0; i < n1; i += nthread) { + ddct(n2, isgn, a[i], ip, w); + } + } else { + for (i = n0; i < n1; i += nthread) { + ddst(n2, isgn, a[i], ip, w); + } + } + return (void *) 0; +} + + +void *ddxt2d_th(void *p) +{ + void ddct(int n, int isgn, double *a, int *ip, double *w); + void ddst(int n, int isgn, double *a, int *ip, double *w); + int nthread, n0, n1, n2, ics, isgn, *ip, i, j; + double **a, *t, *w; + + nthread = ((fft2d_arg_t *) p)->nthread; + n0 = ((fft2d_arg_t *) p)->n0; + n1 = ((fft2d_arg_t *) p)->n1; + n2 = ((fft2d_arg_t *) p)->n2; + ics = ((fft2d_arg_t *) p)->ic; + isgn = ((fft2d_arg_t *) p)->isgn; + a = ((fft2d_arg_t *) p)->a; + t = ((fft2d_arg_t *) p)->t; + ip = ((fft2d_arg_t *) p)->ip; + w = ((fft2d_arg_t *) p)->w; + if (n2 > 2 * nthread) { + for (j = 4 * n0; j < n2; j += 4 * nthread) { + for (i = 0; i < n1; i++) { + t[i] = a[i][j]; + t[n1 + i] = a[i][j + 1]; + t[2 * n1 + i] = a[i][j + 2]; + t[3 * n1 + i] = a[i][j + 3]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + ddct(n1, isgn, &t[n1], ip, w); + ddct(n1, isgn, &t[2 * n1], ip, w); + ddct(n1, isgn, &t[3 * n1], ip, w); + } else { + ddst(n1, isgn, t, ip, w); + ddst(n1, isgn, &t[n1], ip, w); + ddst(n1, isgn, &t[2 * n1], ip, w); + ddst(n1, isgn, &t[3 * n1], ip, w); + } + for (i = 0; i < n1; i++) { + a[i][j] = t[i]; + a[i][j + 1] = t[n1 + i]; + a[i][j + 2] = t[2 * n1 + i]; + a[i][j + 3] = t[3 * n1 + i]; + } + } + } else if (n2 == 2 * nthread) { + for (i = 0; i < n1; i++) { + t[i] = a[i][2 * n0]; + t[n1 + i] = a[i][2 * n0 + 1]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + ddct(n1, isgn, &t[n1], ip, w); + } else { + ddst(n1, isgn, t, ip, w); + ddst(n1, isgn, &t[n1], ip, w); + } + for (i = 0; i < n1; i++) { + a[i][2 * n0] = t[i]; + a[i][2 * n0 + 1] = t[n1 + i]; + } + } else if (n2 == nthread) { + for (i = 0; i < n1; i++) { + t[i] = a[i][n0]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + } else { + ddst(n1, isgn, t, ip, w); + } + for (i = 0; i < n1; i++) { + a[i][n0] = t[i]; + } + } + return (void *) 0; +} +#endif /* USE_FFT2D_THREADS */ +
diff --git a/third_party/tensorflow_dependencies/fft2d/fftsg2d.f b/third_party/tensorflow_dependencies/fft2d/fftsg2d.f new file mode 100644 index 0000000..49a9d6c --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/fftsg2d.f
@@ -0,0 +1,562 @@ +! Fast Fourier/Cosine/Sine Transform +! dimension :two +! data length :power of 2 +! decimation :frequency +! radix :split-radix, row-column +! data :inplace +! table :use +! subroutines +! cdft2d: Complex Discrete Fourier Transform +! rdft2d: Real Discrete Fourier Transform +! ddct2d: Discrete Cosine Transform +! ddst2d: Discrete Sine Transform +! necessary package +! fftsg.f : 1D-FFT package +! +! +! -------- Complex DFT (Discrete Fourier Transform) -------- +! [definition] +! <case1> +! X(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 x(j1,j2) * +! exp(2*pi*i*j1*k1/n1) * +! exp(2*pi*i*j2*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! <case2> +! X(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 x(j1,j2) * +! exp(-2*pi*i*j1*k1/n1) * +! exp(-2*pi*i*j2*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! (notes: sum_j=0^n-1 is a summation from j=0 to n-1) +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call cdft2d(n1max, 2*n1, n2, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call cdft2d(n1max, 2*n1, n2, -1, a, t, ip, w) +! [parameters] +! n1max :row size of the 2D array (integer) +! 2*n1 :data length (integer) +! n1 >= 1, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 1, n2 = power of 2 +! a(0:2*n1-1,0:n2-1) +! :input/output data (real*8) +! input data +! a(2*j1,j2) = Re(x(j1,j2)), +! a(2*j1+1,j2) = Im(x(j1,j2)), +! 0<=j1<n1, 0<=j2<n2 +! output data +! a(2*k1,k2) = Re(X(k1,k2)), +! a(2*k1+1,k2) = Im(X(k1,k2)), +! 0<=k1<n1, 0<=k2<n2 +! t(0:8*n2-1) +! :work area (real*8) +! length of t >= 8*n2 +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1, n2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1/2, n2/2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call cdft2d(n1max, 2*n1, n2, -1, a, t, ip, w) +! is +! call cdft2d(n1max, 2*n1, n2, 1, a, t, ip, w) +! do j2 = 0, n2 - 1 +! do j1 = 0, 2 * n1 - 1 +! a(j1, j2) = a(j1, j2) * (1.0d0 / n1 / n2) +! end do +! end do +! . +! +! +! -------- Real DFT / Inverse of Real DFT -------- +! [definition] +! <case1> RDFT +! R(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! I(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! <case2> IRDFT (excluding scale) +! a(k1,k2) = (1/2) * sum_j1=0^n1-1 sum_j2=0^n2-1 +! (R(j1,j2) * +! cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2) + +! I(j1,j2) * +! sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2)), +! 0<=k1<n1, 0<=k2<n2 +! (notes: R(n1-k1,n2-k2) = R(k1,k2), +! I(n1-k1,n2-k2) = -I(k1,k2), +! R(n1-k1,0) = R(k1,0), +! I(n1-k1,0) = -I(k1,0), +! R(0,n2-k2) = R(0,k2), +! I(0,n2-k2) = -I(0,k2), +! 0<k1<n1, 0<k2<n2) +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call rdft2d(n1max, n1, n2, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call rdft2d(n1max, n1, n2, -1, a, t, ip, w) +! [parameters] +! n1max :row size of the 2D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! a(0:n1-1,0:n2-1) +! :input/output data (real*8) +! <case1> +! output data +! a(2*k1,k2) = R(k1,k2) = R(n1-k1,n2-k2), +! a(2*k1+1,k2) = I(k1,k2) = -I(n1-k1,n2-k2), +! 0<k1<n1/2, 0<k2<n2, +! a(2*k1,0) = R(k1,0) = R(n1-k1,0), +! a(2*k1+1,0) = I(k1,0) = -I(n1-k1,0), +! 0<k1<n1/2, +! a(0,k2) = R(0,k2) = R(0,n2-k2), +! a(1,k2) = I(0,k2) = -I(0,n2-k2), +! a(1,n2-k2) = R(n1/2,k2) = R(n1/2,n2-k2), +! a(0,n2-k2) = -I(n1/2,k2) = I(n1/2,n2-k2), +! 0<k2<n2/2, +! a(0,0) = R(0,0), +! a(1,0) = R(n1/2,0), +! a(0,n2/2) = R(0,n2/2), +! a(1,n2/2) = R(n1/2,n2/2) +! <case2> +! input data +! a(2*j1,j2) = R(j1,j2) = R(n1-j1,n2-j2), +! a(2*j1+1,j2) = I(j1,j2) = -I(n1-j1,n2-j2), +! 0<j1<n1/2, 0<j2<n2, +! a(2*j1,0) = R(j1,0) = R(n1-j1,0), +! a(2*j1+1,0) = I(j1,0) = -I(n1-j1,0), +! 0<j1<n1/2, +! a(0,j2) = R(0,j2) = R(0,n2-j2), +! a(1,j2) = I(0,j2) = -I(0,n2-j2), +! a(1,n2-j2) = R(n1/2,j2) = R(n1/2,n2-j2), +! a(0,n2-j2) = -I(n1/2,j2) = I(n1/2,n2-j2), +! 0<j2<n2/2, +! a(0,0) = R(0,0), +! a(1,0) = R(n1/2,0), +! a(0,n2/2) = R(0,n2/2), +! a(1,n2/2) = R(n1/2,n2/2) +! ---- output ordering ---- +! call rdft2d(n1max, n1, n2, 1, a, t, ip, w) +! call rdft2dsort(n1max, n1, n2, 1, a) +! ! stored data is a(0:n1-1,0:n2+1): +! ! a(2*k1,k2) = R(k1,k2), +! ! a(2*k1+1,k2) = I(k1,k2), +! ! 0<=k1<=n1/2, 0<=k2<n2. +! ! the stored data is larger than the input data! +! ---- input ordering ---- +! call rdft2dsort(n1max, n1, n2, -1, a) +! call rdft2d(n1max, n1, n2, -1, a, t, ip, w) +! t(0:8*n2-1) +! :work area (real*8) +! length of t >= 8*n2 +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1/4, n2/2) + n1/4 +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call rdft2d(n1max, n1, n2, 1, a, t, ip, w) +! is +! call rdft2d(n1max, n1, n2, -1, a, t, ip, w) +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1, j2) = a(j1, j2) * (2.0d0 / n1 / n2) +! end do +! end do +! . +! +! +! -------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- +! [definition] +! <case1> IDCT (excluding scale) +! C(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! cos(pi*j1*(k1+1/2)/n1) * +! cos(pi*j2*(k2+1/2)/n2), +! 0<=k1<n1, 0<=k2<n2 +! <case2> DCT +! C(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! cos(pi*(j1+1/2)*k1/n1) * +! cos(pi*(j2+1/2)*k2/n2), +! 0<=k1<n1, 0<=k2<n2 +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call ddct2d(n1max, n1, n2, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call ddct2d(n1max, n1, n2, -1, a, t, ip, w) +! [parameters] +! n1max :row size of the 2D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! a(0:n1-1,0:n2-1) +! :input/output data (real*8) +! output data +! a(k1,k2) = C(k1,k2), 0<=k1<n1, 0<=k2<n2 +! t(0:4*n2-1) +! :work area (real*8) +! length of t >= 4*n2 +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2/2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1*3/2, n2*3/2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call ddct2d(n1max, n1, n2, -1, a, t, ip, w) +! is +! do j1 = 0, n1 - 1 +! a(j1, 0) = a(j1, 0) * 0.5d0 +! end do +! do j2 = 0, n2 - 1 +! a(0, j2) = a(0, j2) * 0.5d0 +! end do +! call ddct2d(n1max, n1, n2, 1, a, t, ip, w) +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1, j2) = a(j1, j2) * (4.0d0 / n1 / n2) +! end do +! end do +! . +! +! +! -------- DST (Discrete Sine Transform) / Inverse of DST -------- +! [definition] +! <case1> IDST (excluding scale) +! S(k1,k2) = sum_j1=1^n1 sum_j2=1^n2 A(j1,j2) * +! sin(pi*j1*(k1+1/2)/n1) * +! sin(pi*j2*(k2+1/2)/n2), +! 0<=k1<n1, 0<=k2<n2 +! <case2> DST +! S(k1,k2) = sum_j1=0^n1-1 sum_j2=0^n2-1 a(j1,j2) * +! sin(pi*(j1+1/2)*k1/n1) * +! sin(pi*(j2+1/2)*k2/n2), +! 0<k1<=n1, 0<k2<=n2 +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call ddst2d(n1max, n1, n2, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call ddst2d(n1max, n1, n2, -1, a, t, ip, w) +! [parameters] +! n1max :row size of the 2D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! a(0:n1-1,0:n2-1) +! :input/output data (real*8) +! <case1> +! input data +! a(j1,j2) = A(j1,j2), 0<j1<n1, 0<j2<n2, +! a(j1,0) = A(j1,n2), 0<j1<n1, +! a(0,j2) = A(n1,j2), 0<j2<n2, +! a(0,0) = A(n1,n2) +! (i.e. A(j1,j2) = a(mod(j1,n1),mod(j2,n2))) +! output data +! a(k1,k2) = S(k1,k2), 0<=k1<n1, 0<=k2<n2 +! <case2> +! output data +! a(k1,k2) = S(k1,k2), 0<k1<n1, 0<k2<n2, +! a(k1,0) = S(k1,n2), 0<k1<n1, +! a(0,k2) = S(n1,k2), 0<k2<n2, +! a(0,0) = S(n1,n2) +! (i.e. S(k1,k2) = a(mod(k1,n1),mod(k2,n2))) +! t(0:4*n2-1) +! :work area (real*8) +! length of t >= 4*n2 +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2/2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1*3/2, n2*3/2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call ddst2d(n1max, n1, n2, -1, a, t, ip, w) +! is +! do j1 = 0, n1 - 1 +! a(j1, 0) = a(j1, 0) * 0.5d0 +! end do +! do j2 = 0, n2 - 1 +! a(0, j2) = a(0, j2) * 0.5d0 +! end do +! call ddst2d(n1max, n1, n2, 1, a, t, ip, w) +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1, j2) = a(j1, j2) * (4.0d0 / n1 / n2) +! end do +! end do +! . +! +! + subroutine cdft2d(n1max, n1, n2, isgn, a, t, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), n, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), t(0 : 8 * n2 - 1), + & w(0 : *) + n = max(n1, 2 * n2) + if (n .gt. 4 * ip(0)) then + call makewt(n / 4, ip, w) + end if + do j = 0, n2 - 1 + call cdft(n1, isgn, a(0, j), ip, w) + end do + call cdft2d_sub(n1max, n1, n2, isgn, a, t, ip, w) + end +! + subroutine rdft2d(n1max, n1, n2, isgn, a, t, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), n, nw, nc, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), t(0 : 8 * n2 - 1), + & w(0 : *) + n = max(n1, 2 * n2) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n1 .gt. 4 * nc) then + nc = n1 / 4 + call makect(nc, ip, w(nw)) + end if + if (isgn .lt. 0) then + call rdft2d_sub(n1max, n1, n2, isgn, a) + call cdft2d_sub(n1max, n1, n2, isgn, a, t, ip, w) + end if + do j = 0, n2 - 1 + call rdft(n1, isgn, a(0, j), ip, w) + end do + if (isgn .ge. 0) then + call cdft2d_sub(n1max, n1, n2, isgn, a, t, ip, w) + call rdft2d_sub(n1max, n1, n2, isgn, a) + end if + end +! + subroutine rdft2dsort(n1max, n1, n2, isgn, a) + integer n1max, n1, n2, isgn, n2h, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), x, y + n2h = n2 / 2 + if (isgn .lt. 0) then + do j = n2h + 1, n2 - 1 + a(0, j) = a(n1 + 1, j) + a(1, j) = a(n1, j) + end do + a(1, 0) = a(n1, 0) + a(1, n2h) = a(n1, n2h) + else + do j = n2h + 1, n2 - 1 + y = a(0, j) + x = a(1, j) + a(n1, j) = x + a(n1 + 1, j) = y + a(n1, n2 - j) = x + a(n1 + 1, n2 - j) = -y + a(0, j) = a(0, n2 - j) + a(1, j) = -a(1, n2 - j) + end do + a(n1, 0) = a(1, 0) + a(n1 + 1, 0) = 0 + a(1, 0) = 0 + a(n1, n2h) = a(1, n2h) + a(n1 + 1, n2h) = 0 + a(1, n2h) = 0 + end if + end +! + subroutine ddct2d(n1max, n1, n2, isgn, a, t, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), n, nw, nc, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), t(0 : 4 * n2 - 1), + & w(0 : *) + n = max(n1, n2) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. nc) then + nc = n + call makect(nc, ip, w(nw)) + end if + do j = 0, n2 - 1 + call ddct(n1, isgn, a(0, j), ip, w) + end do + call ddxt2d_sub(n1max, n1, n2, 0, isgn, a, t, ip, w) + end +! + subroutine ddst2d(n1max, n1, n2, isgn, a, t, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), n, nw, nc, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), t(0 : 4 * n2 - 1), + & w(0 : *) + n = max(n1, n2) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. nc) then + nc = n + call makect(nc, ip, w(nw)) + end if + do j = 0, n2 - 1 + call ddst(n1, isgn, a(0, j), ip, w) + end do + call ddxt2d_sub(n1max, n1, n2, 1, isgn, a, t, ip, w) + end +! +! -------- child routines -------- +! + subroutine cdft2d_sub(n1max, n1, n2, isgn, a, t, ip, w) + integer n1max, n1, n2, isgn, ip(0 : *), i, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), t(0 : 8 * n2 - 1), + & w(0 : *) + if (n1 .gt. 4) then + do i = 0, n1 - 8, 8 + do j = 0, n2 - 1 + t(2 * j) = a(i, j) + t(2 * j + 1) = a(i + 1, j) + t(2 * n2 + 2 * j) = a(i + 2, j) + t(2 * n2 + 2 * j + 1) = a(i + 3, j) + t(4 * n2 + 2 * j) = a(i + 4, j) + t(4 * n2 + 2 * j + 1) = a(i + 5, j) + t(6 * n2 + 2 * j) = a(i + 6, j) + t(6 * n2 + 2 * j + 1) = a(i + 7, j) + end do + call cdft(2 * n2, isgn, t, ip, w) + call cdft(2 * n2, isgn, t(2 * n2), ip, w) + call cdft(2 * n2, isgn, t(4 * n2), ip, w) + call cdft(2 * n2, isgn, t(6 * n2), ip, w) + do j = 0, n2 - 1 + a(i, j) = t(2 * j) + a(i + 1, j) = t(2 * j + 1) + a(i + 2, j) = t(2 * n2 + 2 * j) + a(i + 3, j) = t(2 * n2 + 2 * j + 1) + a(i + 4, j) = t(4 * n2 + 2 * j) + a(i + 5, j) = t(4 * n2 + 2 * j + 1) + a(i + 6, j) = t(6 * n2 + 2 * j) + a(i + 7, j) = t(6 * n2 + 2 * j + 1) + end do + end do + else if (n1 .eq. 4) then + do j = 0, n2 - 1 + t(2 * j) = a(0, j) + t(2 * j + 1) = a(1, j) + t(2 * n2 + 2 * j) = a(2, j) + t(2 * n2 + 2 * j + 1) = a(3, j) + end do + call cdft(2 * n2, isgn, t, ip, w) + call cdft(2 * n2, isgn, t(2 * n2), ip, w) + do j = 0, n2 - 1 + a(0, j) = t(2 * j) + a(1, j) = t(2 * j + 1) + a(2, j) = t(2 * n2 + 2 * j) + a(3, j) = t(2 * n2 + 2 * j + 1) + end do + else if (n1 .eq. 2) then + do j = 0, n2 - 1 + t(2 * j) = a(0, j) + t(2 * j + 1) = a(1, j) + end do + call cdft(2 * n2, isgn, t, ip, w) + do j = 0, n2 - 1 + a(0, j) = t(2 * j) + a(1, j) = t(2 * j + 1) + end do + end if + end +! + subroutine rdft2d_sub(n1max, n1, n2, isgn, a) + integer n1max, n1, n2, isgn, n2h, i, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), xi + n2h = n2 / 2 + if (isgn .lt. 0) then + do i = 1, n2h - 1 + j = n2 - i + xi = a(0, i) - a(0, j) + a(0, i) = a(0, i) + a(0, j) + a(0, j) = xi + xi = a(1, j) - a(1, i) + a(1, i) = a(1, i) + a(1, j) + a(1, j) = xi + end do + else + do i = 1, n2h - 1 + j = n2 - i + a(0, j) = 0.5d0 * (a(0, i) - a(0, j)) + a(0, i) = a(0, i) - a(0, j) + a(1, j) = 0.5d0 * (a(1, i) + a(1, j)) + a(1, i) = a(1, i) - a(1, j) + end do + end if + end +! + subroutine ddxt2d_sub(n1max, n1, n2, ics, isgn, a, t, + & ip, w) + integer n1max, n1, n2, ics, isgn, ip(0 : *), i, j + real*8 a(0 : n1max - 1, 0 : n2 - 1), t(0 : 4 * n2 - 1), + & w(0 : *) + if (n1 .gt. 2) then + do i = 0, n1 - 4, 4 + do j = 0, n2 - 1 + t(j) = a(i, j) + t(n2 + j) = a(i + 1, j) + t(2 * n2 + j) = a(i + 2, j) + t(3 * n2 + j) = a(i + 3, j) + end do + if (ics .eq. 0) then + call ddct(n2, isgn, t, ip, w) + call ddct(n2, isgn, t(n2), ip, w) + call ddct(n2, isgn, t(2 * n2), ip, w) + call ddct(n2, isgn, t(3 * n2), ip, w) + else + call ddst(n2, isgn, t, ip, w) + call ddst(n2, isgn, t(n2), ip, w) + call ddst(n2, isgn, t(2 * n2), ip, w) + call ddst(n2, isgn, t(3 * n2), ip, w) + end if + do j = 0, n2 - 1 + a(i, j) = t(j) + a(i + 1, j) = t(n2 + j) + a(i + 2, j) = t(2 * n2 + j) + a(i + 3, j) = t(3 * n2 + j) + end do + end do + else if (n1 .eq. 2) then + do j = 0, n2 - 1 + t(j) = a(0, j) + t(n2 + j) = a(1, j) + end do + if (ics .eq. 0) then + call ddct(n2, isgn, t, ip, w) + call ddct(n2, isgn, t(n2), ip, w) + else + call ddst(n2, isgn, t, ip, w) + call ddst(n2, isgn, t(n2), ip, w) + end if + do j = 0, n2 - 1 + a(0, j) = t(j) + a(1, j) = t(n2 + j) + end do + end if + end +!
diff --git a/third_party/tensorflow_dependencies/fft2d/fftsg3d.c b/third_party/tensorflow_dependencies/fft2d/fftsg3d.c new file mode 100644 index 0000000..62f7daa --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/fftsg3d.c
@@ -0,0 +1,1695 @@ +/* +Fast Fourier/Cosine/Sine Transform + dimension :three + data length :power of 2 + decimation :frequency + radix :split-radix, row-column + data :inplace + table :use +functions + cdft3d: Complex Discrete Fourier Transform + rdft3d: Real Discrete Fourier Transform + ddct3d: Discrete Cosine Transform + ddst3d: Discrete Sine Transform +function prototypes + void cdft3d(int, int, int, int, double ***, double *, int *, double *); + void rdft3d(int, int, int, int, double ***, double *, int *, double *); + void rdft3dsort(int, int, int, int, double ***); + void ddct3d(int, int, int, int, double ***, double *, int *, double *); + void ddst3d(int, int, int, int, double ***, double *, int *, double *); +necessary package + fftsg.c : 1D-FFT package +macro definitions + USE_FFT3D_PTHREADS : default=not defined + FFT3D_MAX_THREADS : must be 2^N, default=4 + FFT3D_THREADS_BEGIN_N : default=65536 + USE_FFT3D_WINTHREADS : default=not defined + FFT3D_MAX_THREADS : must be 2^N, default=4 + FFT3D_THREADS_BEGIN_N : default=131072 + + +-------- Complex DFT (Discrete Fourier Transform) -------- + [definition] + <case1> + X[k1][k2][k3] = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 + x[j1][j2][j3] * + exp(2*pi*i*j1*k1/n1) * + exp(2*pi*i*j2*k2/n2) * + exp(2*pi*i*j3*k3/n3), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + <case2> + X[k1][k2][k3] = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 + x[j1][j2][j3] * + exp(-2*pi*i*j1*k1/n1) * + exp(-2*pi*i*j2*k2/n2) * + exp(-2*pi*i*j3*k3/n3), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + (notes: sum_j=0^n-1 is a summation from j=0 to n-1) + [usage] + <case1> + ip[0] = 0; // first time only + cdft3d(n1, n2, 2*n3, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + cdft3d(n1, n2, 2*n3, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 1, n1 = power of 2 + n2 :data length (int) + n2 >= 1, n2 = power of 2 + 2*n3 :data length (int) + n3 >= 1, n3 = power of 2 + a[0...n1-1][0...n2-1][0...2*n3-1] + :input/output data (double ***) + input data + a[j1][j2][2*j3] = Re(x[j1][j2][j3]), + a[j1][j2][2*j3+1] = Im(x[j1][j2][j3]), + 0<=j1<n1, 0<=j2<n2, 0<=j3<n3 + output data + a[k1][k2][2*k3] = Re(X[k1][k2][k3]), + a[k1][k2][2*k3+1] = Im(X[k1][k2][k3]), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + t[0...*] + :work area (double *) + length of t >= max(8*n1, 8*n2), if single thread, + length of t >= max(8*n1, 8*n2)*FFT3D_MAX_THREADS, + if multi threads, + t is dynamically allocated, if t == NULL. + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1, n2, n3)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1/2, n2/2, n3/2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + cdft3d(n1, n2, 2*n3, -1, a, t, ip, w); + is + cdft3d(n1, n2, 2*n3, 1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + for (j3 = 0; j3 <= 2 * n3 - 1; j3++) { + a[j1][j2][j3] *= 1.0 / n1 / n2 / n3; + } + } + } + . + + +-------- Real DFT / Inverse of Real DFT -------- + [definition] + <case1> RDFT + R[k1][k2][k3] = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 + a[j1][j2][j3] * + cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2 + + 2*pi*j3*k3/n3), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + I[k1][k2][k3] = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 + a[j1][j2][j3] * + sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2 + + 2*pi*j3*k3/n3), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + <case2> IRDFT (excluding scale) + a[k1][k2][k3] = (1/2) * sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 + (R[j1][j2][j3] * + cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2 + + 2*pi*j3*k3/n3) + + I[j1][j2][j3] * + sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2 + + 2*pi*j3*k3/n3)), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + (notes: R[(n1-k1)%n1][(n2-k2)%n2][(n3-k3)%n3] = R[k1][k2][k3], + I[(n1-k1)%n1][(n2-k2)%n2][(n3-k3)%n3] = -I[k1][k2][k3], + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3) + [usage] + <case1> + ip[0] = 0; // first time only + rdft3d(n1, n2, n3, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + rdft3d(n1, n2, n3, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + n3 :data length (int) + n3 >= 2, n3 = power of 2 + a[0...n1-1][0...n2-1][0...n3-1] + :input/output data (double ***) + <case1> + output data + a[k1][k2][2*k3] = R[k1][k2][k3] + = R[(n1-k1)%n1][(n2-k2)%n2][n3-k3], + a[k1][k2][2*k3+1] = I[k1][k2][k3] + = -I[(n1-k1)%n1][(n2-k2)%n2][n3-k3], + 0<=k1<n1, 0<=k2<n2, 0<k3<n3/2, + (n%m : n mod m), + a[k1][k2][0] = R[k1][k2][0] + = R[(n1-k1)%n1][n2-k2][0], + a[k1][k2][1] = I[k1][k2][0] + = -I[(n1-k1)%n1][n2-k2][0], + a[k1][n2-k2][1] = R[(n1-k1)%n1][k2][n3/2] + = R[k1][n2-k2][n3/2], + a[k1][n2-k2][0] = -I[(n1-k1)%n1][k2][n3/2] + = I[k1][n2-k2][n3/2], + 0<=k1<n1, 0<k2<n2/2, + a[k1][0][0] = R[k1][0][0] + = R[n1-k1][0][0], + a[k1][0][1] = I[k1][0][0] + = -I[n1-k1][0][0], + a[k1][n2/2][0] = R[k1][n2/2][0] + = R[n1-k1][n2/2][0], + a[k1][n2/2][1] = I[k1][n2/2][0] + = -I[n1-k1][n2/2][0], + a[n1-k1][0][1] = R[k1][0][n3/2] + = R[n1-k1][0][n3/2], + a[n1-k1][0][0] = -I[k1][0][n3/2] + = I[n1-k1][0][n3/2], + a[n1-k1][n2/2][1] = R[k1][n2/2][n3/2] + = R[n1-k1][n2/2][n3/2], + a[n1-k1][n2/2][0] = -I[k1][n2/2][n3/2] + = I[n1-k1][n2/2][n3/2], + 0<k1<n1/2, + a[0][0][0] = R[0][0][0], + a[0][0][1] = R[0][0][n3/2], + a[0][n2/2][0] = R[0][n2/2][0], + a[0][n2/2][1] = R[0][n2/2][n3/2], + a[n1/2][0][0] = R[n1/2][0][0], + a[n1/2][0][1] = R[n1/2][0][n3/2], + a[n1/2][n2/2][0] = R[n1/2][n2/2][0], + a[n1/2][n2/2][1] = R[n1/2][n2/2][n3/2] + <case2> + input data + a[j1][j2][2*j3] = R[j1][j2][j3] + = R[(n1-j1)%n1][(n2-j2)%n2][n3-j3], + a[j1][j2][2*j3+1] = I[j1][j2][j3] + = -I[(n1-j1)%n1][(n2-j2)%n2][n3-j3], + 0<=j1<n1, 0<=j2<n2, 0<j3<n3/2, + a[j1][j2][0] = R[j1][j2][0] + = R[(n1-j1)%n1][n2-j2][0], + a[j1][j2][1] = I[j1][j2][0] + = -I[(n1-j1)%n1][n2-j2][0], + a[j1][n2-j2][1] = R[(n1-j1)%n1][j2][n3/2] + = R[j1][n2-j2][n3/2], + a[j1][n2-j2][0] = -I[(n1-j1)%n1][j2][n3/2] + = I[j1][n2-j2][n3/2], + 0<=j1<n1, 0<j2<n2/2, + a[j1][0][0] = R[j1][0][0] + = R[n1-j1][0][0], + a[j1][0][1] = I[j1][0][0] + = -I[n1-j1][0][0], + a[j1][n2/2][0] = R[j1][n2/2][0] + = R[n1-j1][n2/2][0], + a[j1][n2/2][1] = I[j1][n2/2][0] + = -I[n1-j1][n2/2][0], + a[n1-j1][0][1] = R[j1][0][n3/2] + = R[n1-j1][0][n3/2], + a[n1-j1][0][0] = -I[j1][0][n3/2] + = I[n1-j1][0][n3/2], + a[n1-j1][n2/2][1] = R[j1][n2/2][n3/2] + = R[n1-j1][n2/2][n3/2], + a[n1-j1][n2/2][0] = -I[j1][n2/2][n3/2] + = I[n1-j1][n2/2][n3/2], + 0<j1<n1/2, + a[0][0][0] = R[0][0][0], + a[0][0][1] = R[0][0][n3/2], + a[0][n2/2][0] = R[0][n2/2][0], + a[0][n2/2][1] = R[0][n2/2][n3/2], + a[n1/2][0][0] = R[n1/2][0][0], + a[n1/2][0][1] = R[n1/2][0][n3/2], + a[n1/2][n2/2][0] = R[n1/2][n2/2][0], + a[n1/2][n2/2][1] = R[n1/2][n2/2][n3/2] + ---- output ordering ---- + rdft3d(n1, n2, n3, 1, a, t, ip, w); + rdft3dsort(n1, n2, n3, 1, a); + // stored data is a[0...n1-1][0...n2-1][0...n3+1]: + // a[k1][k2][2*k3] = R[k1][k2][k3], + // a[k1][k2][2*k3+1] = I[k1][k2][k3], + // 0<=k1<n1, 0<=k2<n2, 0<=k3<=n3/2. + // the stored data is larger than the input data! + ---- input ordering ---- + rdft3dsort(n1, n2, n3, -1, a); + rdft3d(n1, n2, n3, -1, a, t, ip, w); + t[0...*] + :work area (double *) + length of t >= max(8*n1, 8*n2), if single thread, + length of t >= max(8*n1, 8*n2)*FFT3D_MAX_THREADS, + if multi threads, + t is dynamically allocated, if t == NULL. + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1, n2, n3/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1/2, n2/2, n3/4) + n3/4 + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + rdft3d(n1, n2, n3, 1, a, t, ip, w); + is + rdft3d(n1, n2, n3, -1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + for (j3 = 0; j3 <= n3 - 1; j3++) { + a[j1][j2][j3] *= 2.0 / n1 / n2 / n3; + } + } + } + . + + +-------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + <case1> IDCT (excluding scale) + C[k1][k2][k3] = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 + a[j1][j2][j3] * + cos(pi*j1*(k1+1/2)/n1) * + cos(pi*j2*(k2+1/2)/n2) * + cos(pi*j3*(k3+1/2)/n3), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + <case2> DCT + C[k1][k2][k3] = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 + a[j1][j2][j3] * + cos(pi*(j1+1/2)*k1/n1) * + cos(pi*(j2+1/2)*k2/n2) * + cos(pi*(j3+1/2)*k3/n3), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + [usage] + <case1> + ip[0] = 0; // first time only + ddct3d(n1, n2, n3, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + ddct3d(n1, n2, n3, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + n3 :data length (int) + n3 >= 2, n3 = power of 2 + a[0...n1-1][0...n2-1][0...n3-1] + :input/output data (double ***) + output data + a[k1][k2][k3] = C[k1][k2][k3], + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + t[0...*] + :work area (double *) + length of t >= max(4*n1, 4*n2), if single thread, + length of t >= max(4*n1, 4*n2)*FFT3D_MAX_THREADS, + if multi threads, + t is dynamically allocated, if t == NULL. + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1/2, n2/2, n3/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1*3/2, n2*3/2, n3*3/2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddct3d(n1, n2, n3, -1, a, t, ip, w); + is + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2][0] *= 0.5; + } + for (j3 = 0; j3 <= n3 - 1; j3++) { + a[j1][0][j3] *= 0.5; + } + } + for (j2 = 0; j2 <= n2 - 1; j2++) { + for (j3 = 0; j3 <= n3 - 1; j3++) { + a[0][j2][j3] *= 0.5; + } + } + ddct3d(n1, n2, n3, 1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + for (j3 = 0; j3 <= n3 - 1; j3++) { + a[j1][j2][j3] *= 8.0 / n1 / n2 / n3; + } + } + } + . + + +-------- DST (Discrete Sine Transform) / Inverse of DST -------- + [definition] + <case1> IDST (excluding scale) + S[k1][k2][k3] = sum_j1=1^n1 sum_j2=1^n2 sum_j3=1^n3 + A[j1][j2][j3] * + sin(pi*j1*(k1+1/2)/n1) * + sin(pi*j2*(k2+1/2)/n2) * + sin(pi*j3*(k3+1/2)/n3), + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + <case2> DST + S[k1][k2][k3] = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 + a[j1][j2][j3] * + sin(pi*(j1+1/2)*k1/n1) * + sin(pi*(j2+1/2)*k2/n2) * + sin(pi*(j3+1/2)*k3/n3), + 0<k1<=n1, 0<k2<=n2, 0<k3<=n3 + [usage] + <case1> + ip[0] = 0; // first time only + ddst3d(n1, n2, n3, 1, a, t, ip, w); + <case2> + ip[0] = 0; // first time only + ddst3d(n1, n2, n3, -1, a, t, ip, w); + [parameters] + n1 :data length (int) + n1 >= 2, n1 = power of 2 + n2 :data length (int) + n2 >= 2, n2 = power of 2 + n3 :data length (int) + n3 >= 2, n3 = power of 2 + a[0...n1-1][0...n2-1][0...n3-1] + :input/output data (double ***) + <case1> + input data + a[j1%n1][j2%n2][j3%n3] = A[j1][j2][j3], + 0<j1<=n1, 0<j2<=n2, 0<j3<=n3, + (n%m : n mod m) + output data + a[k1][k2][k3] = S[k1][k2][k3], + 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 + <case2> + output data + a[k1%n1][k2%n2][k3%n3] = S[k1][k2][k3], + 0<k1<=n1, 0<k2<=n2, 0<k3<=n3 + t[0...*] + :work area (double *) + length of t >= max(4*n1, 4*n2), if single thread, + length of t >= max(4*n1, 4*n2)*FFT3D_MAX_THREADS, + if multi threads, + t is dynamically allocated, if t == NULL. + ip[0...*] + :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + (n = max(n1/2, n2/2, n3/2)) + ip[0],ip[1] are pointers of the cos/sin table. + w[0...*] + :cos/sin table (double *) + length of w >= max(n1*3/2, n2*3/2, n3*3/2) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddst3d(n1, n2, n3, -1, a, t, ip, w); + is + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2][0] *= 0.5; + } + for (j3 = 0; j3 <= n3 - 1; j3++) { + a[j1][0][j3] *= 0.5; + } + } + for (j2 = 0; j2 <= n2 - 1; j2++) { + for (j3 = 0; j3 <= n3 - 1; j3++) { + a[0][j2][j3] *= 0.5; + } + } + ddst3d(n1, n2, n3, 1, a, t, ip, w); + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + for (j3 = 0; j3 <= n3 - 1; j3++) { + a[j1][j2][j3] *= 8.0 / n1 / n2 / n3; + } + } + } + . +*/ + + +#include <stdio.h> +#include <stdlib.h> +#define fft3d_alloc_error_check(p) { \ + if ((p) == NULL) { \ + fprintf(stderr, "fft3d memory allocation error\n"); \ + exit(1); \ + } \ +} + + +#ifdef USE_FFT3D_PTHREADS +#define USE_FFT3D_THREADS +#ifndef FFT3D_MAX_THREADS +#define FFT3D_MAX_THREADS 4 +#endif +#ifndef FFT3D_THREADS_BEGIN_N +#define FFT3D_THREADS_BEGIN_N 65536 +#endif +#include <pthread.h> +#define fft3d_thread_t pthread_t +#define fft3d_thread_create(thp,func,argp) { \ + if (pthread_create(thp, NULL, func, (void *) (argp)) != 0) { \ + fprintf(stderr, "fft3d thread error\n"); \ + exit(1); \ + } \ +} +#define fft3d_thread_wait(th) { \ + if (pthread_join(th, NULL) != 0) { \ + fprintf(stderr, "fft3d thread error\n"); \ + exit(1); \ + } \ +} +#endif /* USE_FFT3D_PTHREADS */ + + +#ifdef USE_FFT3D_WINTHREADS +#define USE_FFT3D_THREADS +#ifndef FFT3D_MAX_THREADS +#define FFT3D_MAX_THREADS 4 +#endif +#ifndef FFT3D_THREADS_BEGIN_N +#define FFT3D_THREADS_BEGIN_N 131072 +#endif +#include <windows.h> +#define fft3d_thread_t HANDLE +#define fft3d_thread_create(thp,func,argp) { \ + DWORD thid; \ + *(thp) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (func), (LPVOID) (argp), 0, &thid); \ + if (*(thp) == 0) { \ + fprintf(stderr, "fft3d thread error\n"); \ + exit(1); \ + } \ +} +#define fft3d_thread_wait(th) { \ + WaitForSingleObject(th, INFINITE); \ + CloseHandle(th); \ +} +#endif /* USE_FFT3D_WINTHREADS */ + + +void cdft3d(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void xdft3da_sub(int n1, int n2, int n3, int icr, int isgn, + double ***a, double *t, int *ip, double *w); + void cdft3db_sub(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w); +#ifdef USE_FFT3D_THREADS + void xdft3da_subth(int n1, int n2, int n3, int icr, int isgn, + double ***a, double *t, int *ip, double *w); + void cdft3db_subth(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w); +#endif /* USE_FFT3D_THREADS */ + int n, itnull, nt; + + n = n1; + if (n < n2) { + n = n2; + } + n <<= 1; + if (n < n3) { + n = n3; + } + if (n > (ip[0] << 2)) { + makewt(n >> 2, ip, w); + } + itnull = 0; + if (t == NULL) { + itnull = 1; + nt = n1; + if (nt < n2) { + nt = n2; + } + nt *= 8; +#ifdef USE_FFT3D_THREADS + nt *= FFT3D_MAX_THREADS; +#endif /* USE_FFT3D_THREADS */ + if (n3 == 4) { + nt >>= 1; + } else if (n3 < 4) { + nt >>= 2; + } + t = (double *) malloc(sizeof(double) * nt); + fft3d_alloc_error_check(t); + } +#ifdef USE_FFT3D_THREADS + if ((double) n1 * n2 * n3 >= (double) FFT3D_THREADS_BEGIN_N) { + xdft3da_subth(n1, n2, n3, 0, isgn, a, t, ip, w); + cdft3db_subth(n1, n2, n3, isgn, a, t, ip, w); + } else +#endif /* USE_FFT3D_THREADS */ + { + xdft3da_sub(n1, n2, n3, 0, isgn, a, t, ip, w); + cdft3db_sub(n1, n2, n3, isgn, a, t, ip, w); + } + if (itnull != 0) { + free(t); + } +} + + +void rdft3d(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void xdft3da_sub(int n1, int n2, int n3, int icr, int isgn, + double ***a, double *t, int *ip, double *w); + void cdft3db_sub(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w); + void rdft3d_sub(int n1, int n2, int n3, int isgn, double ***a); +#ifdef USE_FFT3D_THREADS + void xdft3da_subth(int n1, int n2, int n3, int icr, int isgn, + double ***a, double *t, int *ip, double *w); + void cdft3db_subth(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w); +#endif /* USE_FFT3D_THREADS */ + int n, nw, nc, itnull, nt; + + n = n1; + if (n < n2) { + n = n2; + } + n <<= 1; + if (n < n3) { + n = n3; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n3 > (nc << 2)) { + nc = n3 >> 2; + makect(nc, ip, w + nw); + } + itnull = 0; + if (t == NULL) { + itnull = 1; + nt = n1; + if (nt < n2) { + nt = n2; + } + nt *= 8; +#ifdef USE_FFT3D_THREADS + nt *= FFT3D_MAX_THREADS; +#endif /* USE_FFT3D_THREADS */ + if (n3 == 4) { + nt >>= 1; + } else if (n3 < 4) { + nt >>= 2; + } + t = (double *) malloc(sizeof(double) * nt); + fft3d_alloc_error_check(t); + } +#ifdef USE_FFT3D_THREADS + if ((double) n1 * n2 * n3 >= (double) FFT3D_THREADS_BEGIN_N) { + if (isgn < 0) { + rdft3d_sub(n1, n2, n3, isgn, a); + cdft3db_subth(n1, n2, n3, isgn, a, t, ip, w); + } + xdft3da_subth(n1, n2, n3, 1, isgn, a, t, ip, w); + if (isgn >= 0) { + cdft3db_subth(n1, n2, n3, isgn, a, t, ip, w); + rdft3d_sub(n1, n2, n3, isgn, a); + } + } else +#endif /* USE_FFT3D_THREADS */ + { + if (isgn < 0) { + rdft3d_sub(n1, n2, n3, isgn, a); + cdft3db_sub(n1, n2, n3, isgn, a, t, ip, w); + } + xdft3da_sub(n1, n2, n3, 1, isgn, a, t, ip, w); + if (isgn >= 0) { + cdft3db_sub(n1, n2, n3, isgn, a, t, ip, w); + rdft3d_sub(n1, n2, n3, isgn, a); + } + } + if (itnull != 0) { + free(t); + } +} + + +void rdft3dsort(int n1, int n2, int n3, int isgn, double ***a) +{ + int n1h, n2h, i, j; + double x, y; + + n1h = n1 >> 1; + n2h = n2 >> 1; + if (isgn < 0) { + for (i = 0; i < n1; i++) { + for (j = n2h + 1; j < n2; j++) { + a[i][j][0] = a[i][j][n3 + 1]; + a[i][j][1] = a[i][j][n3]; + } + } + for (i = n1h + 1; i < n1; i++) { + a[i][0][0] = a[i][0][n3 + 1]; + a[i][0][1] = a[i][0][n3]; + a[i][n2h][0] = a[i][n2h][n3 + 1]; + a[i][n2h][1] = a[i][n2h][n3]; + } + a[0][0][1] = a[0][0][n3]; + a[0][n2h][1] = a[0][n2h][n3]; + a[n1h][0][1] = a[n1h][0][n3]; + a[n1h][n2h][1] = a[n1h][n2h][n3]; + } else { + for (j = n2h + 1; j < n2; j++) { + y = a[0][j][0]; + x = a[0][j][1]; + a[0][j][n3] = x; + a[0][j][n3 + 1] = y; + a[0][n2 - j][n3] = x; + a[0][n2 - j][n3 + 1] = -y; + a[0][j][0] = a[0][n2 - j][0]; + a[0][j][1] = -a[0][n2 - j][1]; + } + for (i = 1; i < n1; i++) { + for (j = n2h + 1; j < n2; j++) { + y = a[i][j][0]; + x = a[i][j][1]; + a[i][j][n3] = x; + a[i][j][n3 + 1] = y; + a[n1 - i][n2 - j][n3] = x; + a[n1 - i][n2 - j][n3 + 1] = -y; + a[i][j][0] = a[n1 - i][n2 - j][0]; + a[i][j][1] = -a[n1 - i][n2 - j][1]; + } + } + for (i = n1h + 1; i < n1; i++) { + y = a[i][0][0]; + x = a[i][0][1]; + a[i][0][n3] = x; + a[i][0][n3 + 1] = y; + a[n1 - i][0][n3] = x; + a[n1 - i][0][n3 + 1] = -y; + a[i][0][0] = a[n1 - i][0][0]; + a[i][0][1] = -a[n1 - i][0][1]; + y = a[i][n2h][0]; + x = a[i][n2h][1]; + a[i][n2h][n3] = x; + a[i][n2h][n3 + 1] = y; + a[n1 - i][n2h][n3] = x; + a[n1 - i][n2h][n3 + 1] = -y; + a[i][n2h][0] = a[n1 - i][n2h][0]; + a[i][n2h][1] = -a[n1 - i][n2h][1]; + } + a[0][0][n3] = a[0][0][1]; + a[0][0][n3 + 1] = 0; + a[0][0][1] = 0; + a[0][n2h][n3] = a[0][n2h][1]; + a[0][n2h][n3 + 1] = 0; + a[0][n2h][1] = 0; + a[n1h][0][n3] = a[n1h][0][1]; + a[n1h][0][n3 + 1] = 0; + a[n1h][0][1] = 0; + a[n1h][n2h][n3] = a[n1h][n2h][1]; + a[n1h][n2h][n3 + 1] = 0; + a[n1h][n2h][1] = 0; + } +} + + +void ddct3d(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void ddxt3da_sub(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w); + void ddxt3db_sub(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w); +#ifdef USE_FFT3D_THREADS + void ddxt3da_subth(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w); + void ddxt3db_subth(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w); +#endif /* USE_FFT3D_THREADS */ + int n, nw, nc, itnull, nt; + + n = n1; + if (n < n2) { + n = n2; + } + if (n < n3) { + n = n3; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + itnull = 0; + if (t == NULL) { + itnull = 1; + nt = n1; + if (nt < n2) { + nt = n2; + } + nt *= 4; +#ifdef USE_FFT3D_THREADS + nt *= FFT3D_MAX_THREADS; +#endif /* USE_FFT3D_THREADS */ + if (n3 == 2) { + nt >>= 1; + } + t = (double *) malloc(sizeof(double) * nt); + fft3d_alloc_error_check(t); + } +#ifdef USE_FFT3D_THREADS + if ((double) n1 * n2 * n3 >= (double) FFT3D_THREADS_BEGIN_N) { + ddxt3da_subth(n1, n2, n3, 0, isgn, a, t, ip, w); + ddxt3db_subth(n1, n2, n3, 0, isgn, a, t, ip, w); + } else +#endif /* USE_FFT3D_THREADS */ + { + ddxt3da_sub(n1, n2, n3, 0, isgn, a, t, ip, w); + ddxt3db_sub(n1, n2, n3, 0, isgn, a, t, ip, w); + } + if (itnull != 0) { + free(t); + } +} + + +void ddst3d(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w) +{ + void makewt(int nw, int *ip, double *w); + void makect(int nc, int *ip, double *c); + void ddxt3da_sub(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w); + void ddxt3db_sub(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w); +#ifdef USE_FFT3D_THREADS + void ddxt3da_subth(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w); + void ddxt3db_subth(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w); +#endif /* USE_FFT3D_THREADS */ + int n, nw, nc, itnull, nt; + + n = n1; + if (n < n2) { + n = n2; + } + if (n < n3) { + n = n3; + } + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + itnull = 0; + if (t == NULL) { + itnull = 1; + nt = n1; + if (nt < n2) { + nt = n2; + } + nt *= 4; +#ifdef USE_FFT3D_THREADS + nt *= FFT3D_MAX_THREADS; +#endif /* USE_FFT3D_THREADS */ + if (n3 == 2) { + nt >>= 1; + } + t = (double *) malloc(sizeof(double) * nt); + fft3d_alloc_error_check(t); + } +#ifdef USE_FFT3D_THREADS + if ((double) n1 * n2 * n3 >= (double) FFT3D_THREADS_BEGIN_N) { + ddxt3da_subth(n1, n2, n3, 1, isgn, a, t, ip, w); + ddxt3db_subth(n1, n2, n3, 1, isgn, a, t, ip, w); + } else +#endif /* USE_FFT3D_THREADS */ + { + ddxt3da_sub(n1, n2, n3, 1, isgn, a, t, ip, w); + ddxt3db_sub(n1, n2, n3, 1, isgn, a, t, ip, w); + } + if (itnull != 0) { + free(t); + } +} + + +/* -------- child routines -------- */ + + +void xdft3da_sub(int n1, int n2, int n3, int icr, int isgn, + double ***a, double *t, int *ip, double *w) +{ + void cdft(int n, int isgn, double *a, int *ip, double *w); + void rdft(int n, int isgn, double *a, int *ip, double *w); + int i, j, k; + + for (i = 0; i < n1; i++) { + if (icr == 0) { + for (j = 0; j < n2; j++) { + cdft(n3, isgn, a[i][j], ip, w); + } + } else if (isgn >= 0) { + for (j = 0; j < n2; j++) { + rdft(n3, isgn, a[i][j], ip, w); + } + } + if (n3 > 4) { + for (k = 0; k < n3; k += 8) { + for (j = 0; j < n2; j++) { + t[2 * j] = a[i][j][k]; + t[2 * j + 1] = a[i][j][k + 1]; + t[2 * n2 + 2 * j] = a[i][j][k + 2]; + t[2 * n2 + 2 * j + 1] = a[i][j][k + 3]; + t[4 * n2 + 2 * j] = a[i][j][k + 4]; + t[4 * n2 + 2 * j + 1] = a[i][j][k + 5]; + t[6 * n2 + 2 * j] = a[i][j][k + 6]; + t[6 * n2 + 2 * j + 1] = a[i][j][k + 7]; + } + cdft(2 * n2, isgn, t, ip, w); + cdft(2 * n2, isgn, &t[2 * n2], ip, w); + cdft(2 * n2, isgn, &t[4 * n2], ip, w); + cdft(2 * n2, isgn, &t[6 * n2], ip, w); + for (j = 0; j < n2; j++) { + a[i][j][k] = t[2 * j]; + a[i][j][k + 1] = t[2 * j + 1]; + a[i][j][k + 2] = t[2 * n2 + 2 * j]; + a[i][j][k + 3] = t[2 * n2 + 2 * j + 1]; + a[i][j][k + 4] = t[4 * n2 + 2 * j]; + a[i][j][k + 5] = t[4 * n2 + 2 * j + 1]; + a[i][j][k + 6] = t[6 * n2 + 2 * j]; + a[i][j][k + 7] = t[6 * n2 + 2 * j + 1]; + } + } + } else if (n3 == 4) { + for (j = 0; j < n2; j++) { + t[2 * j] = a[i][j][0]; + t[2 * j + 1] = a[i][j][1]; + t[2 * n2 + 2 * j] = a[i][j][2]; + t[2 * n2 + 2 * j + 1] = a[i][j][3]; + } + cdft(2 * n2, isgn, t, ip, w); + cdft(2 * n2, isgn, &t[2 * n2], ip, w); + for (j = 0; j < n2; j++) { + a[i][j][0] = t[2 * j]; + a[i][j][1] = t[2 * j + 1]; + a[i][j][2] = t[2 * n2 + 2 * j]; + a[i][j][3] = t[2 * n2 + 2 * j + 1]; + } + } else if (n3 == 2) { + for (j = 0; j < n2; j++) { + t[2 * j] = a[i][j][0]; + t[2 * j + 1] = a[i][j][1]; + } + cdft(2 * n2, isgn, t, ip, w); + for (j = 0; j < n2; j++) { + a[i][j][0] = t[2 * j]; + a[i][j][1] = t[2 * j + 1]; + } + } + if (icr != 0 && isgn < 0) { + for (j = 0; j < n2; j++) { + rdft(n3, isgn, a[i][j], ip, w); + } + } + } +} + + +void cdft3db_sub(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w) +{ + void cdft(int n, int isgn, double *a, int *ip, double *w); + int i, j, k; + + if (n3 > 4) { + for (j = 0; j < n2; j++) { + for (k = 0; k < n3; k += 8) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][j][k]; + t[2 * i + 1] = a[i][j][k + 1]; + t[2 * n1 + 2 * i] = a[i][j][k + 2]; + t[2 * n1 + 2 * i + 1] = a[i][j][k + 3]; + t[4 * n1 + 2 * i] = a[i][j][k + 4]; + t[4 * n1 + 2 * i + 1] = a[i][j][k + 5]; + t[6 * n1 + 2 * i] = a[i][j][k + 6]; + t[6 * n1 + 2 * i + 1] = a[i][j][k + 7]; + } + cdft(2 * n1, isgn, t, ip, w); + cdft(2 * n1, isgn, &t[2 * n1], ip, w); + cdft(2 * n1, isgn, &t[4 * n1], ip, w); + cdft(2 * n1, isgn, &t[6 * n1], ip, w); + for (i = 0; i < n1; i++) { + a[i][j][k] = t[2 * i]; + a[i][j][k + 1] = t[2 * i + 1]; + a[i][j][k + 2] = t[2 * n1 + 2 * i]; + a[i][j][k + 3] = t[2 * n1 + 2 * i + 1]; + a[i][j][k + 4] = t[4 * n1 + 2 * i]; + a[i][j][k + 5] = t[4 * n1 + 2 * i + 1]; + a[i][j][k + 6] = t[6 * n1 + 2 * i]; + a[i][j][k + 7] = t[6 * n1 + 2 * i + 1]; + } + } + } + } else if (n3 == 4) { + for (j = 0; j < n2; j++) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][j][0]; + t[2 * i + 1] = a[i][j][1]; + t[2 * n1 + 2 * i] = a[i][j][2]; + t[2 * n1 + 2 * i + 1] = a[i][j][3]; + } + cdft(2 * n1, isgn, t, ip, w); + cdft(2 * n1, isgn, &t[2 * n1], ip, w); + for (i = 0; i < n1; i++) { + a[i][j][0] = t[2 * i]; + a[i][j][1] = t[2 * i + 1]; + a[i][j][2] = t[2 * n1 + 2 * i]; + a[i][j][3] = t[2 * n1 + 2 * i + 1]; + } + } + } else if (n3 == 2) { + for (j = 0; j < n2; j++) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][j][0]; + t[2 * i + 1] = a[i][j][1]; + } + cdft(2 * n1, isgn, t, ip, w); + for (i = 0; i < n1; i++) { + a[i][j][0] = t[2 * i]; + a[i][j][1] = t[2 * i + 1]; + } + } + } +} + + +void rdft3d_sub(int n1, int n2, int n3, int isgn, double ***a) +{ + int n1h, n2h, i, j, k, l; + double xi; + + n1h = n1 >> 1; + n2h = n2 >> 1; + if (isgn < 0) { + for (i = 1; i < n1h; i++) { + j = n1 - i; + xi = a[i][0][0] - a[j][0][0]; + a[i][0][0] += a[j][0][0]; + a[j][0][0] = xi; + xi = a[j][0][1] - a[i][0][1]; + a[i][0][1] += a[j][0][1]; + a[j][0][1] = xi; + xi = a[i][n2h][0] - a[j][n2h][0]; + a[i][n2h][0] += a[j][n2h][0]; + a[j][n2h][0] = xi; + xi = a[j][n2h][1] - a[i][n2h][1]; + a[i][n2h][1] += a[j][n2h][1]; + a[j][n2h][1] = xi; + for (k = 1; k < n2h; k++) { + l = n2 - k; + xi = a[i][k][0] - a[j][l][0]; + a[i][k][0] += a[j][l][0]; + a[j][l][0] = xi; + xi = a[j][l][1] - a[i][k][1]; + a[i][k][1] += a[j][l][1]; + a[j][l][1] = xi; + xi = a[j][k][0] - a[i][l][0]; + a[j][k][0] += a[i][l][0]; + a[i][l][0] = xi; + xi = a[i][l][1] - a[j][k][1]; + a[j][k][1] += a[i][l][1]; + a[i][l][1] = xi; + } + } + for (k = 1; k < n2h; k++) { + l = n2 - k; + xi = a[0][k][0] - a[0][l][0]; + a[0][k][0] += a[0][l][0]; + a[0][l][0] = xi; + xi = a[0][l][1] - a[0][k][1]; + a[0][k][1] += a[0][l][1]; + a[0][l][1] = xi; + xi = a[n1h][k][0] - a[n1h][l][0]; + a[n1h][k][0] += a[n1h][l][0]; + a[n1h][l][0] = xi; + xi = a[n1h][l][1] - a[n1h][k][1]; + a[n1h][k][1] += a[n1h][l][1]; + a[n1h][l][1] = xi; + } + } else { + for (i = 1; i < n1h; i++) { + j = n1 - i; + a[j][0][0] = 0.5 * (a[i][0][0] - a[j][0][0]); + a[i][0][0] -= a[j][0][0]; + a[j][0][1] = 0.5 * (a[i][0][1] + a[j][0][1]); + a[i][0][1] -= a[j][0][1]; + a[j][n2h][0] = 0.5 * (a[i][n2h][0] - a[j][n2h][0]); + a[i][n2h][0] -= a[j][n2h][0]; + a[j][n2h][1] = 0.5 * (a[i][n2h][1] + a[j][n2h][1]); + a[i][n2h][1] -= a[j][n2h][1]; + for (k = 1; k < n2h; k++) { + l = n2 - k; + a[j][l][0] = 0.5 * (a[i][k][0] - a[j][l][0]); + a[i][k][0] -= a[j][l][0]; + a[j][l][1] = 0.5 * (a[i][k][1] + a[j][l][1]); + a[i][k][1] -= a[j][l][1]; + a[i][l][0] = 0.5 * (a[j][k][0] - a[i][l][0]); + a[j][k][0] -= a[i][l][0]; + a[i][l][1] = 0.5 * (a[j][k][1] + a[i][l][1]); + a[j][k][1] -= a[i][l][1]; + } + } + for (k = 1; k < n2h; k++) { + l = n2 - k; + a[0][l][0] = 0.5 * (a[0][k][0] - a[0][l][0]); + a[0][k][0] -= a[0][l][0]; + a[0][l][1] = 0.5 * (a[0][k][1] + a[0][l][1]); + a[0][k][1] -= a[0][l][1]; + a[n1h][l][0] = 0.5 * (a[n1h][k][0] - a[n1h][l][0]); + a[n1h][k][0] -= a[n1h][l][0]; + a[n1h][l][1] = 0.5 * (a[n1h][k][1] + a[n1h][l][1]); + a[n1h][k][1] -= a[n1h][l][1]; + } + } +} + + +void ddxt3da_sub(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w) +{ + void ddct(int n, int isgn, double *a, int *ip, double *w); + void ddst(int n, int isgn, double *a, int *ip, double *w); + int i, j, k; + + for (i = 0; i < n1; i++) { + if (ics == 0) { + for (j = 0; j < n2; j++) { + ddct(n3, isgn, a[i][j], ip, w); + } + } else { + for (j = 0; j < n2; j++) { + ddst(n3, isgn, a[i][j], ip, w); + } + } + if (n3 > 2) { + for (k = 0; k < n3; k += 4) { + for (j = 0; j < n2; j++) { + t[j] = a[i][j][k]; + t[n2 + j] = a[i][j][k + 1]; + t[2 * n2 + j] = a[i][j][k + 2]; + t[3 * n2 + j] = a[i][j][k + 3]; + } + if (ics == 0) { + ddct(n2, isgn, t, ip, w); + ddct(n2, isgn, &t[n2], ip, w); + ddct(n2, isgn, &t[2 * n2], ip, w); + ddct(n2, isgn, &t[3 * n2], ip, w); + } else { + ddst(n2, isgn, t, ip, w); + ddst(n2, isgn, &t[n2], ip, w); + ddst(n2, isgn, &t[2 * n2], ip, w); + ddst(n2, isgn, &t[3 * n2], ip, w); + } + for (j = 0; j < n2; j++) { + a[i][j][k] = t[j]; + a[i][j][k + 1] = t[n2 + j]; + a[i][j][k + 2] = t[2 * n2 + j]; + a[i][j][k + 3] = t[3 * n2 + j]; + } + } + } else if (n3 == 2) { + for (j = 0; j < n2; j++) { + t[j] = a[i][j][0]; + t[n2 + j] = a[i][j][1]; + } + if (ics == 0) { + ddct(n2, isgn, t, ip, w); + ddct(n2, isgn, &t[n2], ip, w); + } else { + ddst(n2, isgn, t, ip, w); + ddst(n2, isgn, &t[n2], ip, w); + } + for (j = 0; j < n2; j++) { + a[i][j][0] = t[j]; + a[i][j][1] = t[n2 + j]; + } + } + } +} + + +void ddxt3db_sub(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w) +{ + void ddct(int n, int isgn, double *a, int *ip, double *w); + void ddst(int n, int isgn, double *a, int *ip, double *w); + int i, j, k; + + if (n3 > 2) { + for (j = 0; j < n2; j++) { + for (k = 0; k < n3; k += 4) { + for (i = 0; i < n1; i++) { + t[i] = a[i][j][k]; + t[n1 + i] = a[i][j][k + 1]; + t[2 * n1 + i] = a[i][j][k + 2]; + t[3 * n1 + i] = a[i][j][k + 3]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + ddct(n1, isgn, &t[n1], ip, w); + ddct(n1, isgn, &t[2 * n1], ip, w); + ddct(n1, isgn, &t[3 * n1], ip, w); + } else { + ddst(n1, isgn, t, ip, w); + ddst(n1, isgn, &t[n1], ip, w); + ddst(n1, isgn, &t[2 * n1], ip, w); + ddst(n1, isgn, &t[3 * n1], ip, w); + } + for (i = 0; i < n1; i++) { + a[i][j][k] = t[i]; + a[i][j][k + 1] = t[n1 + i]; + a[i][j][k + 2] = t[2 * n1 + i]; + a[i][j][k + 3] = t[3 * n1 + i]; + } + } + } + } else if (n3 == 2) { + for (j = 0; j < n2; j++) { + for (i = 0; i < n1; i++) { + t[i] = a[i][j][0]; + t[n1 + i] = a[i][j][1]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + ddct(n1, isgn, &t[n1], ip, w); + } else { + ddst(n1, isgn, t, ip, w); + ddst(n1, isgn, &t[n1], ip, w); + } + for (i = 0; i < n1; i++) { + a[i][j][0] = t[i]; + a[i][j][1] = t[n1 + i]; + } + } + } +} + + +#ifdef USE_FFT3D_THREADS +struct fft3d_arg_st { + int nthread; + int n0; + int n1; + int n2; + int n3; + int ic; + int isgn; + double ***a; + double *t; + int *ip; + double *w; +}; +typedef struct fft3d_arg_st fft3d_arg_t; + + +void xdft3da_subth(int n1, int n2, int n3, int icr, int isgn, + double ***a, double *t, int *ip, double *w) +{ + void *xdft3da_th(void *p); + fft3d_thread_t th[FFT3D_MAX_THREADS]; + fft3d_arg_t ag[FFT3D_MAX_THREADS]; + int nthread, nt, i; + + nthread = FFT3D_MAX_THREADS; + if (nthread > n1) { + nthread = n1; + } + nt = 8 * n2; + if (n3 == 4) { + nt >>= 1; + } else if (n3 < 4) { + nt >>= 2; + } + for (i = 0; i < nthread; i++) { + ag[i].nthread = nthread; + ag[i].n0 = i; + ag[i].n1 = n1; + ag[i].n2 = n2; + ag[i].n3 = n3; + ag[i].ic = icr; + ag[i].isgn = isgn; + ag[i].a = a; + ag[i].t = &t[nt * i]; + ag[i].ip = ip; + ag[i].w = w; + fft3d_thread_create(&th[i], xdft3da_th, &ag[i]); + } + for (i = 0; i < nthread; i++) { + fft3d_thread_wait(th[i]); + } +} + + +void cdft3db_subth(int n1, int n2, int n3, int isgn, double ***a, + double *t, int *ip, double *w) +{ + void *cdft3db_th(void *p); + fft3d_thread_t th[FFT3D_MAX_THREADS]; + fft3d_arg_t ag[FFT3D_MAX_THREADS]; + int nthread, nt, i; + + nthread = FFT3D_MAX_THREADS; + if (nthread > n2) { + nthread = n2; + } + nt = 8 * n1; + if (n3 == 4) { + nt >>= 1; + } else if (n3 < 4) { + nt >>= 2; + } + for (i = 0; i < nthread; i++) { + ag[i].nthread = nthread; + ag[i].n0 = i; + ag[i].n1 = n1; + ag[i].n2 = n2; + ag[i].n3 = n3; + ag[i].isgn = isgn; + ag[i].a = a; + ag[i].t = &t[nt * i]; + ag[i].ip = ip; + ag[i].w = w; + fft3d_thread_create(&th[i], cdft3db_th, &ag[i]); + } + for (i = 0; i < nthread; i++) { + fft3d_thread_wait(th[i]); + } +} + + +void ddxt3da_subth(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w) +{ + void *ddxt3da_th(void *p); + fft3d_thread_t th[FFT3D_MAX_THREADS]; + fft3d_arg_t ag[FFT3D_MAX_THREADS]; + int nthread, nt, i; + + nthread = FFT3D_MAX_THREADS; + if (nthread > n1) { + nthread = n1; + } + nt = 4 * n2; + if (n3 == 2) { + nt >>= 1; + } + for (i = 0; i < nthread; i++) { + ag[i].nthread = nthread; + ag[i].n0 = i; + ag[i].n1 = n1; + ag[i].n2 = n2; + ag[i].n3 = n3; + ag[i].ic = ics; + ag[i].isgn = isgn; + ag[i].a = a; + ag[i].t = &t[nt * i]; + ag[i].ip = ip; + ag[i].w = w; + fft3d_thread_create(&th[i], ddxt3da_th, &ag[i]); + } + for (i = 0; i < nthread; i++) { + fft3d_thread_wait(th[i]); + } +} + + +void ddxt3db_subth(int n1, int n2, int n3, int ics, int isgn, + double ***a, double *t, int *ip, double *w) +{ + void *ddxt3db_th(void *p); + fft3d_thread_t th[FFT3D_MAX_THREADS]; + fft3d_arg_t ag[FFT3D_MAX_THREADS]; + int nthread, nt, i; + + nthread = FFT3D_MAX_THREADS; + if (nthread > n2) { + nthread = n2; + } + nt = 4 * n1; + if (n3 == 2) { + nt >>= 1; + } + for (i = 0; i < nthread; i++) { + ag[i].nthread = nthread; + ag[i].n0 = i; + ag[i].n1 = n1; + ag[i].n2 = n2; + ag[i].n3 = n3; + ag[i].ic = ics; + ag[i].isgn = isgn; + ag[i].a = a; + ag[i].t = &t[nt * i]; + ag[i].ip = ip; + ag[i].w = w; + fft3d_thread_create(&th[i], ddxt3db_th, &ag[i]); + } + for (i = 0; i < nthread; i++) { + fft3d_thread_wait(th[i]); + } +} + + +void *xdft3da_th(void *p) +{ + void cdft(int n, int isgn, double *a, int *ip, double *w); + void rdft(int n, int isgn, double *a, int *ip, double *w); + int nthread, n0, n1, n2, n3, icr, isgn, *ip, i, j, k; + double ***a, *t, *w; + + nthread = ((fft3d_arg_t *) p)->nthread; + n0 = ((fft3d_arg_t *) p)->n0; + n1 = ((fft3d_arg_t *) p)->n1; + n2 = ((fft3d_arg_t *) p)->n2; + n3 = ((fft3d_arg_t *) p)->n3; + icr = ((fft3d_arg_t *) p)->ic; + isgn = ((fft3d_arg_t *) p)->isgn; + a = ((fft3d_arg_t *) p)->a; + t = ((fft3d_arg_t *) p)->t; + ip = ((fft3d_arg_t *) p)->ip; + w = ((fft3d_arg_t *) p)->w; + for (i = n0; i < n1; i += nthread) { + if (icr == 0) { + for (j = 0; j < n2; j++) { + cdft(n3, isgn, a[i][j], ip, w); + } + } else if (isgn >= 0) { + for (j = 0; j < n2; j++) { + rdft(n3, isgn, a[i][j], ip, w); + } + } + if (n3 > 4) { + for (k = 0; k < n3; k += 8) { + for (j = 0; j < n2; j++) { + t[2 * j] = a[i][j][k]; + t[2 * j + 1] = a[i][j][k + 1]; + t[2 * n2 + 2 * j] = a[i][j][k + 2]; + t[2 * n2 + 2 * j + 1] = a[i][j][k + 3]; + t[4 * n2 + 2 * j] = a[i][j][k + 4]; + t[4 * n2 + 2 * j + 1] = a[i][j][k + 5]; + t[6 * n2 + 2 * j] = a[i][j][k + 6]; + t[6 * n2 + 2 * j + 1] = a[i][j][k + 7]; + } + cdft(2 * n2, isgn, t, ip, w); + cdft(2 * n2, isgn, &t[2 * n2], ip, w); + cdft(2 * n2, isgn, &t[4 * n2], ip, w); + cdft(2 * n2, isgn, &t[6 * n2], ip, w); + for (j = 0; j < n2; j++) { + a[i][j][k] = t[2 * j]; + a[i][j][k + 1] = t[2 * j + 1]; + a[i][j][k + 2] = t[2 * n2 + 2 * j]; + a[i][j][k + 3] = t[2 * n2 + 2 * j + 1]; + a[i][j][k + 4] = t[4 * n2 + 2 * j]; + a[i][j][k + 5] = t[4 * n2 + 2 * j + 1]; + a[i][j][k + 6] = t[6 * n2 + 2 * j]; + a[i][j][k + 7] = t[6 * n2 + 2 * j + 1]; + } + } + } else if (n3 == 4) { + for (j = 0; j < n2; j++) { + t[2 * j] = a[i][j][0]; + t[2 * j + 1] = a[i][j][1]; + t[2 * n2 + 2 * j] = a[i][j][2]; + t[2 * n2 + 2 * j + 1] = a[i][j][3]; + } + cdft(2 * n2, isgn, t, ip, w); + cdft(2 * n2, isgn, &t[2 * n2], ip, w); + for (j = 0; j < n2; j++) { + a[i][j][0] = t[2 * j]; + a[i][j][1] = t[2 * j + 1]; + a[i][j][2] = t[2 * n2 + 2 * j]; + a[i][j][3] = t[2 * n2 + 2 * j + 1]; + } + } else if (n3 == 2) { + for (j = 0; j < n2; j++) { + t[2 * j] = a[i][j][0]; + t[2 * j + 1] = a[i][j][1]; + } + cdft(2 * n2, isgn, t, ip, w); + for (j = 0; j < n2; j++) { + a[i][j][0] = t[2 * j]; + a[i][j][1] = t[2 * j + 1]; + } + } + if (icr != 0 && isgn < 0) { + for (j = 0; j < n2; j++) { + rdft(n3, isgn, a[i][j], ip, w); + } + } + } + return (void *) 0; +} + + +void *cdft3db_th(void *p) +{ + void cdft(int n, int isgn, double *a, int *ip, double *w); + int nthread, n0, n1, n2, n3, isgn, *ip, i, j, k; + double ***a, *t, *w; + + nthread = ((fft3d_arg_t *) p)->nthread; + n0 = ((fft3d_arg_t *) p)->n0; + n1 = ((fft3d_arg_t *) p)->n1; + n2 = ((fft3d_arg_t *) p)->n2; + n3 = ((fft3d_arg_t *) p)->n3; + isgn = ((fft3d_arg_t *) p)->isgn; + a = ((fft3d_arg_t *) p)->a; + t = ((fft3d_arg_t *) p)->t; + ip = ((fft3d_arg_t *) p)->ip; + w = ((fft3d_arg_t *) p)->w; + if (n3 > 4) { + for (j = n0; j < n2; j += nthread) { + for (k = 0; k < n3; k += 8) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][j][k]; + t[2 * i + 1] = a[i][j][k + 1]; + t[2 * n1 + 2 * i] = a[i][j][k + 2]; + t[2 * n1 + 2 * i + 1] = a[i][j][k + 3]; + t[4 * n1 + 2 * i] = a[i][j][k + 4]; + t[4 * n1 + 2 * i + 1] = a[i][j][k + 5]; + t[6 * n1 + 2 * i] = a[i][j][k + 6]; + t[6 * n1 + 2 * i + 1] = a[i][j][k + 7]; + } + cdft(2 * n1, isgn, t, ip, w); + cdft(2 * n1, isgn, &t[2 * n1], ip, w); + cdft(2 * n1, isgn, &t[4 * n1], ip, w); + cdft(2 * n1, isgn, &t[6 * n1], ip, w); + for (i = 0; i < n1; i++) { + a[i][j][k] = t[2 * i]; + a[i][j][k + 1] = t[2 * i + 1]; + a[i][j][k + 2] = t[2 * n1 + 2 * i]; + a[i][j][k + 3] = t[2 * n1 + 2 * i + 1]; + a[i][j][k + 4] = t[4 * n1 + 2 * i]; + a[i][j][k + 5] = t[4 * n1 + 2 * i + 1]; + a[i][j][k + 6] = t[6 * n1 + 2 * i]; + a[i][j][k + 7] = t[6 * n1 + 2 * i + 1]; + } + } + } + } else if (n3 == 4) { + for (j = n0; j < n2; j += nthread) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][j][0]; + t[2 * i + 1] = a[i][j][1]; + t[2 * n1 + 2 * i] = a[i][j][2]; + t[2 * n1 + 2 * i + 1] = a[i][j][3]; + } + cdft(2 * n1, isgn, t, ip, w); + cdft(2 * n1, isgn, &t[2 * n1], ip, w); + for (i = 0; i < n1; i++) { + a[i][j][0] = t[2 * i]; + a[i][j][1] = t[2 * i + 1]; + a[i][j][2] = t[2 * n1 + 2 * i]; + a[i][j][3] = t[2 * n1 + 2 * i + 1]; + } + } + } else if (n3 == 2) { + for (j = n0; j < n2; j += nthread) { + for (i = 0; i < n1; i++) { + t[2 * i] = a[i][j][0]; + t[2 * i + 1] = a[i][j][1]; + } + cdft(2 * n1, isgn, t, ip, w); + for (i = 0; i < n1; i++) { + a[i][j][0] = t[2 * i]; + a[i][j][1] = t[2 * i + 1]; + } + } + } + return (void *) 0; +} + + +void *ddxt3da_th(void *p) +{ + void ddct(int n, int isgn, double *a, int *ip, double *w); + void ddst(int n, int isgn, double *a, int *ip, double *w); + int nthread, n0, n1, n2, n3, ics, isgn, *ip, i, j, k; + double ***a, *t, *w; + + nthread = ((fft3d_arg_t *) p)->nthread; + n0 = ((fft3d_arg_t *) p)->n0; + n1 = ((fft3d_arg_t *) p)->n1; + n2 = ((fft3d_arg_t *) p)->n2; + n3 = ((fft3d_arg_t *) p)->n3; + ics = ((fft3d_arg_t *) p)->ic; + isgn = ((fft3d_arg_t *) p)->isgn; + a = ((fft3d_arg_t *) p)->a; + t = ((fft3d_arg_t *) p)->t; + ip = ((fft3d_arg_t *) p)->ip; + w = ((fft3d_arg_t *) p)->w; + for (i = n0; i < n1; i += nthread) { + if (ics == 0) { + for (j = 0; j < n2; j++) { + ddct(n3, isgn, a[i][j], ip, w); + } + } else { + for (j = 0; j < n2; j++) { + ddst(n3, isgn, a[i][j], ip, w); + } + } + if (n3 > 2) { + for (k = 0; k < n3; k += 4) { + for (j = 0; j < n2; j++) { + t[j] = a[i][j][k]; + t[n2 + j] = a[i][j][k + 1]; + t[2 * n2 + j] = a[i][j][k + 2]; + t[3 * n2 + j] = a[i][j][k + 3]; + } + if (ics == 0) { + ddct(n2, isgn, t, ip, w); + ddct(n2, isgn, &t[n2], ip, w); + ddct(n2, isgn, &t[2 * n2], ip, w); + ddct(n2, isgn, &t[3 * n2], ip, w); + } else { + ddst(n2, isgn, t, ip, w); + ddst(n2, isgn, &t[n2], ip, w); + ddst(n2, isgn, &t[2 * n2], ip, w); + ddst(n2, isgn, &t[3 * n2], ip, w); + } + for (j = 0; j < n2; j++) { + a[i][j][k] = t[j]; + a[i][j][k + 1] = t[n2 + j]; + a[i][j][k + 2] = t[2 * n2 + j]; + a[i][j][k + 3] = t[3 * n2 + j]; + } + } + } else if (n3 == 2) { + for (j = 0; j < n2; j++) { + t[j] = a[i][j][0]; + t[n2 + j] = a[i][j][1]; + } + if (ics == 0) { + ddct(n2, isgn, t, ip, w); + ddct(n2, isgn, &t[n2], ip, w); + } else { + ddst(n2, isgn, t, ip, w); + ddst(n2, isgn, &t[n2], ip, w); + } + for (j = 0; j < n2; j++) { + a[i][j][0] = t[j]; + a[i][j][1] = t[n2 + j]; + } + } + } + return (void *) 0; +} + + +void *ddxt3db_th(void *p) +{ + void ddct(int n, int isgn, double *a, int *ip, double *w); + void ddst(int n, int isgn, double *a, int *ip, double *w); + int nthread, n0, n1, n2, n3, ics, isgn, *ip, i, j, k; + double ***a, *t, *w; + + nthread = ((fft3d_arg_t *) p)->nthread; + n0 = ((fft3d_arg_t *) p)->n0; + n1 = ((fft3d_arg_t *) p)->n1; + n2 = ((fft3d_arg_t *) p)->n2; + n3 = ((fft3d_arg_t *) p)->n3; + ics = ((fft3d_arg_t *) p)->ic; + isgn = ((fft3d_arg_t *) p)->isgn; + a = ((fft3d_arg_t *) p)->a; + t = ((fft3d_arg_t *) p)->t; + ip = ((fft3d_arg_t *) p)->ip; + w = ((fft3d_arg_t *) p)->w; + if (n3 > 2) { + for (j = n0; j < n2; j += nthread) { + for (k = 0; k < n3; k += 4) { + for (i = 0; i < n1; i++) { + t[i] = a[i][j][k]; + t[n1 + i] = a[i][j][k + 1]; + t[2 * n1 + i] = a[i][j][k + 2]; + t[3 * n1 + i] = a[i][j][k + 3]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + ddct(n1, isgn, &t[n1], ip, w); + ddct(n1, isgn, &t[2 * n1], ip, w); + ddct(n1, isgn, &t[3 * n1], ip, w); + } else { + ddst(n1, isgn, t, ip, w); + ddst(n1, isgn, &t[n1], ip, w); + ddst(n1, isgn, &t[2 * n1], ip, w); + ddst(n1, isgn, &t[3 * n1], ip, w); + } + for (i = 0; i < n1; i++) { + a[i][j][k] = t[i]; + a[i][j][k + 1] = t[n1 + i]; + a[i][j][k + 2] = t[2 * n1 + i]; + a[i][j][k + 3] = t[3 * n1 + i]; + } + } + } + } else if (n3 == 2) { + for (j = n0; j < n2; j += nthread) { + for (i = 0; i < n1; i++) { + t[i] = a[i][j][0]; + t[n1 + i] = a[i][j][1]; + } + if (ics == 0) { + ddct(n1, isgn, t, ip, w); + ddct(n1, isgn, &t[n1], ip, w); + } else { + ddst(n1, isgn, t, ip, w); + ddst(n1, isgn, &t[n1], ip, w); + } + for (i = 0; i < n1; i++) { + a[i][j][0] = t[i]; + a[i][j][1] = t[n1 + i]; + } + } + } + return (void *) 0; +} +#endif /* USE_FFT3D_THREADS */ +
diff --git a/third_party/tensorflow_dependencies/fft2d/fftsg3d.f b/third_party/tensorflow_dependencies/fft2d/fftsg3d.f new file mode 100644 index 0000000..f08b1dc --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/fftsg3d.f
@@ -0,0 +1,926 @@ +! Fast Fourier/Cosine/Sine Transform +! dimension :three +! data length :power of 2 +! decimation :frequency +! radix :split-radix, row-column +! data :inplace +! table :use +! subroutines +! cdft3d: Complex Discrete Fourier Transform +! rdft3d: Real Discrete Fourier Transform +! ddct3d: Discrete Cosine Transform +! ddst3d: Discrete Sine Transform +! necessary package +! fftsg.f : 1D-FFT package +! +! +! -------- Complex DFT (Discrete Fourier Transform) -------- +! [definition] +! <case1> +! X(k1,k2,k3) = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 +! x(j1,j2,j3) * +! exp(2*pi*i*j1*k1/n1) * +! exp(2*pi*i*j2*k2/n2) * +! exp(2*pi*i*j3*k3/n3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! <case2> +! X(k1,k2,k3) = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 +! x(j1,j2,j3) * +! exp(-2*pi*i*j1*k1/n1) * +! exp(-2*pi*i*j2*k2/n2) * +! exp(-2*pi*i*j3*k3/n3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! (notes: sum_j=0^n-1 is a summation from j=0 to n-1) +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call cdft3d(n1max, n2max, 2*n1, n2, n3, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call cdft3d(n1max, n2max, 2*n1, n2, n3, -1, a, t, ip, w) +! [parameters] +! n1max :row1 size of the 3D array (integer) +! n2max :row2 size of the 3D array (integer) +! 2*n1 :data length (integer) +! n1 >= 1, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 1, n2 = power of 2 +! n3 :data length (integer) +! n3 >= 1, n3 = power of 2 +! a(0:2*n1-1,0:n2-1,0:n3-1) +! :input/output data (real*8) +! input data +! a(2*j1,j2,j3) = Re(x(j1,j2,j3)), +! a(2*j1+1,j2,j3) = Im(x(j1,j2,j3)), +! 0<=j1<n1, 0<=j2<n2, 0<=j3<n3 +! output data +! a(2*k1,k2,k3) = Re(X(k1,k2,k3)), +! a(2*k1+1,k2,k3) = Im(X(k1,k2,k3)), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! t(0:*) :work area (real*8) +! length of t >= max(8*n2, 8*n3) +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1, n2, n3)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1/2, n2/2, n3/2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call cdft3d(n1max, n2max, 2*n1, n2, n3, -1, a, t, ip, w) +! is +! call cdft3d(n1max, n2max, 2*n1, n2, n3, 1, a, t, ip, w) +! do j3 = 0, n3 - 1 +! do j2 = 0, n2 - 1 +! do j1 = 0, 2 * n1 - 1 +! a(j1,j2,j3) = a(j1,j2,j3) * (1.0d0/n1/n2/n3) +! end do +! end do +! end do +! . +! +! +! -------- Real DFT / Inverse of Real DFT -------- +! [definition] +! <case1> RDFT +! R(k1,k2,k3) = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 +! a(j1,j2,j3) * +! cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2 + +! 2*pi*j3*k3/n3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! I(k1,k2,k3) = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 +! a(j1,j2,j3) * +! sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2 + +! 2*pi*j3*k3/n3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! <case2> IRDFT (excluding scale) +! a(k1,k2,k3) = (1/2) * sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 +! (R(j1,j2,j3) * +! cos(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2 + +! 2*pi*j3*k3/n3) + +! I(j1,j2,j3) * +! sin(2*pi*j1*k1/n1 + 2*pi*j2*k2/n2 + +! 2*pi*j3*k3/n3)), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! (notes: R(mod(n1-k1,n1),mod(n2-k2,n2),mod(n3-k3,n3)) = R(k1,k2,k3), +! I(mod(n1-k1,n1),mod(n2-k2,n2),mod(n3-k3,n3)) = -I(k1,k2,k3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3) +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call rdft3d(n1max, n2max, n1, n2, n3, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call rdft3d(n1max, n2max, n1, n2, n3, -1, a, t, ip, w) +! [parameters] +! n1max :row1 size of the 3D array (integer) +! n2max :row2 size of the 3D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! n3 :data length (integer) +! n3 >= 2, n3 = power of 2 +! a(0:n1-1,0:n2-1,0:n3-1) +! :input/output data (real*8) +! <case1> +! output data +! a(2*k1,k2,k3) = R(k1,k2,k3) +! = R(n1-k1,mod(n2-k2,n2),mod(n3-k3,n3)), +! a(2*k1+1,k2,k3) = I(k1,k2,k3) +! = -I(n1-k1,mod(n2-k2,n2),mod(n3-k3,n3)), +! 0<k1<n1/2, 0<=k2<n2, 0<=k3<n3, +! a(0,k2,k3) = R(0,k2,k3) +! = R(0,n2-k2,mod(n3-k3,n3)), +! a(1,k2,k3) = I(0,k2,k3) +! = -I(0,n2-k2,mod(n3-k3,n3)), +! a(1,n2-k2,k3) = R(n1/2,k2,mod(n3-k3,n3)) +! = R(n1/2,n2-k2,k3), +! a(0,n2-k2,k3) = -I(n1/2,k2,mod(n3-k3,n3)) +! = I(n1/2,n2-k2,k3), +! 0<k2<n2/2, 0<=k3<n3, +! a(0,0,k3) = R(0,0,k3) +! = R(0,0,n3-k3), +! a(1,0,k3) = I(0,0,k3) +! = -I(0,0,n3-k3), +! a(0,n2/2,k3) = R(0,n2/2,k3) +! = R(0,n2/2,n3-k3), +! a(1,n2/2,k3) = I(0,n2/2,k3) +! = -I(0,n2/2,n3-k3), +! a(1,0,n3-k3) = R(n1/2,0,k3) +! = R(n1/2,0,n3-k3), +! a(0,0,n3-k3) = -I(n1/2,0,k3) +! = I(n1/2,0,n3-k3), +! a(1,n2/2,n3-k3) = R(n1/2,n2/2,k3) +! = R(n1/2,n2/2,n3-k3), +! a(0,n2/2,n3-k3) = -I(n1/2,n2/2,k3) +! = I(n1/2,n2/2,n3-k3), +! 0<k3<n3/2, +! a(0,0,0) = R(0,0,0), +! a(1,0,0) = R(n1/2,0,0), +! a(0,0,n3/2) = R(0,0,n3/2), +! a(1,0,n3/2) = R(n1/2,0,n3/2), +! a(0,n2/2,0) = R(0,n2/2,0), +! a(1,n2/2,0) = R(n1/2,n2/2,0), +! a(0,n2/2,n3/2) = R(0,n2/2,n3/2), +! a(1,n2/2,n3/2) = R(n1/2,n2/2,n3/2) +! <case2> +! input data +! a(2*j1,j2,j3) = R(j1,j2,j3) +! = R(n1-j1,mod(n2-j2,n2),mod(n3-j3,n3)), +! a(2*j1+1,j2,j3) = I(j1,j2,j3) +! = -I(n1-j1,mod(n2-j2,n2),mod(n3-j3,n3)), +! 0<j1<n1/2, 0<=j2<n2, 0<=j3<n3, +! a(0,j2,j3) = R(0,j2,j3) +! = R(0,n2-j2,mod(n3-j3,n3)), +! a(1,j2,j3) = I(0,j2,j3) +! = -I(0,n2-j2,mod(n3-j3,n3)), +! a(1,n2-j2,j3) = R(n1/2,j2,mod(n3-j3,n3)) +! = R(n1/2,n2-j2,j3), +! a(0,n2-j2,j3) = -I(n1/2,j2,mod(n3-j3,n3)) +! = I(n1/2,n2-j2,j3), +! 0<j2<n2/2, 0<=j3<n3, +! a(0,0,j3) = R(0,0,j3) +! = R(0,0,n3-j3), +! a(1,0,j3) = I(0,0,j3) +! = -I(0,0,n3-j3), +! a(0,n2/2,j3) = R(0,n2/2,j3) +! = R(0,n2/2,n3-j3), +! a(1,n2/2,j3) = I(0,n2/2,j3) +! = -I(0,n2/2,n3-j3), +! a(1,0,n3-j3) = R(n1/2,0,j3) +! = R(n1/2,0,n3-j3), +! a(0,0,n3-j3) = -I(n1/2,0,j3) +! = I(n1/2,0,n3-j3), +! a(1,n2/2,n3-j3) = R(n1/2,n2/2,j3) +! = R(n1/2,n2/2,n3-j3), +! a(0,n2/2,n3-j3) = -I(n1/2,n2/2,j3) +! = I(n1/2,n2/2,n3-j3), +! 0<j3<n3/2, +! a(0,0,0) = R(0,0,0), +! a(1,0,0) = R(n1/2,0,0), +! a(0,0,n3/2) = R(0,0,n3/2), +! a(1,0,n3/2) = R(n1/2,0,n3/2), +! a(0,n2/2,0) = R(0,n2/2,0), +! a(1,n2/2,0) = R(n1/2,n2/2,0), +! a(0,n2/2,n3/2) = R(0,n2/2,n3/2), +! a(1,n2/2,n3/2) = R(n1/2,n2/2,n3/2) +! ---- output ordering ---- +! call rdft3d(n1max, n2max, n1, n2, n3, 1, a, t, ip, w) +! call rdft3dsort(n1max, n2max, n1, n2, n3, 1, a) +! ! stored data is a(0:n1-1,0:n2-1,0:n3+1): +! ! a(2*k1,k2,k3) = R(k1,k2,k3), +! ! a(2*k1+1,k2,k3) = I(k1,k2,k3), +! ! 0<=k1<=n1/2, 0<=k2<n2, 0<=k3<n3. +! ! the stored data is larger than the input data! +! ---- input ordering ---- +! call rdft3dsort(n1max, n2max, n1, n2, n3, -1, a) +! call rdft3d(n1max, n2max, n1, n2, n3, -1, a, t, ip, w) +! t(0:*) :work area (real*8) +! length of t >= max(8*n2, 8*n3) +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2, n3)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1/4, n2/2, n3/2) + n1/4 +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call rdft3d(n1max, n2max, n1, n2, n3, 1, a, t, ip, w) +! is +! call rdft3d(n1max, n2max, n1, n2, n3, -1, a, t, ip, w) +! do j3 = 0, n3 - 1 +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1,j2,j3) = a(j1,j2,j3) * (2.0d0/n1/n2/n3) +! end do +! end do +! end do +! . +! +! +! -------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- +! [definition] +! <case1> IDCT (excluding scale) +! C(k1,k2,k3) = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 +! a(j1,j2,j3) * +! cos(pi*j1*(k1+1/2)/n1) * +! cos(pi*j2*(k2+1/2)/n2) * +! cos(pi*j3*(k3+1/2)/n3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! <case2> DCT +! C(k1,k2,k3) = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 +! a(j1,j2,j3) * +! cos(pi*(j1+1/2)*k1/n1) * +! cos(pi*(j2+1/2)*k2/n2) * +! cos(pi*(j3+1/2)*k3/n3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call ddct3d(n1max, n2max, n1, n2, n3, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call ddct3d(n1max, n2max, n1, n2, n3, -1, a, t, ip, w) +! [parameters] +! n1max :row1 size of the 3D array (integer) +! n2max :row2 size of the 3D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! n3 :data length (integer) +! n3 >= 2, n3 = power of 2 +! a(0:n1-1,0:n2-1,0:n3-1) +! :input/output data (real*8) +! output data +! a(k1,k2,k3) = C(k1,k2,k3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! t(0:*) :work area (real*8) +! length of t >= max(4*n2, 4*n3) +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2/2, n3/2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1*3/2, n2*3/2, n3*3/2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call ddct3d(n1max, n2max, n1, n2, n3, -1, a, t, ip, w) +! is +! do j3 = 0, n3 - 1 +! do j2 = 0, n2 - 1 +! a(0, j2, j3) = a(0, j2, j3) * 0.5d0 +! end do +! do j1 = 0, n1 - 1 +! a(j1, 0, j3) = a(j1, 0, j3) * 0.5d0 +! end do +! end do +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1, j2, 0) = a(j1, j2, 0) * 0.5d0 +! end do +! end do +! call ddct3d(n1max, n2max, n1, n2, n3, 1, a, t, ip, w) +! do j3 = 0, n3 - 1 +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1,j2,j3) = a(j1,j2,j3) * (8.0d0/n1/n2/n3) +! end do +! end do +! end do +! . +! +! +! -------- DST (Discrete Sine Transform) / Inverse of DST -------- +! [definition] +! <case1> IDST (excluding scale) +! S(k1,k2,k3) = sum_j1=1^n1 sum_j2=1^n2 sum_j3=1^n3 +! A(j1,j2,j3) * +! sin(pi*j1*(k1+1/2)/n1) * +! sin(pi*j2*(k2+1/2)/n2) * +! sin(pi*j3*(k3+1/2)/n3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! <case2> DST +! S(k1,k2,k3) = sum_j1=0^n1-1 sum_j2=0^n2-1 sum_j3=0^n3-1 +! a(j1,j2,j3) * +! sin(pi*(j1+1/2)*k1/n1) * +! sin(pi*(j2+1/2)*k2/n2) * +! sin(pi*(j3+1/2)*k3/n3), +! 0<k1<=n1, 0<k2<=n2, 0<k3<=n3 +! [usage] +! <case1> +! ip(0) = 0 ! first time only +! call ddst3d(n1max, n2max, n1, n2, n3, 1, a, t, ip, w) +! <case2> +! ip(0) = 0 ! first time only +! call ddst3d(n1max, n2max, n1, n2, n3, -1, a, t, ip, w) +! [parameters] +! n1max :row1 size of the 3D array (integer) +! n2max :row2 size of the 3D array (integer) +! n1 :data length (integer) +! n1 >= 2, n1 = power of 2 +! n2 :data length (integer) +! n2 >= 2, n2 = power of 2 +! n3 :data length (integer) +! n3 >= 2, n3 = power of 2 +! a(0:n1-1,0:n2-1,0:n3-1) +! :input/output data (real*8) +! <case1> +! input data +! a(mod(j1,n1),mod(j2,n2),mod(j3,n3)) = A(j1,j2,j3), +! 0<j1<=n1, 0<j2<=n2, 0<j3<=n3 +! output data +! a(k1,k2,k3) = S(k1,k2,k3), +! 0<=k1<n1, 0<=k2<n2, 0<=k3<n3 +! <case2> +! output data +! a(mod(k1,n1),mod(k2,n2),mod(k3,n3)) = S(k1,k2,k3), +! 0<k1<=n1, 0<k2<=n2, 0<k3<=n3 +! t(0:*) :work area (real*8) +! length of t >= max(4*n2, 4*n3) +! ip(0:*):work area for bit reversal (integer) +! length of ip >= 2+sqrt(n) +! (n = max(n1/2, n2/2, n3/2)) +! ip(0),ip(1) are pointers of the cos/sin table. +! w(0:*) :cos/sin table (real*8) +! length of w >= max(n1*3/2, n2*3/2, n3*3/2) +! w(),ip() are initialized if ip(0) = 0. +! [remark] +! Inverse of +! call ddst3d(n1max, n2max, n1, n2, n3, -1, a, t, ip, w) +! is +! do j3 = 0, n3 - 1 +! do j2 = 0, n2 - 1 +! a(0, j2, j3) = a(0, j2, j3) * 0.5d0 +! end do +! do j1 = 0, n1 - 1 +! a(j1, 0, j3) = a(j1, 0, j3) * 0.5d0 +! end do +! end do +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1, j2, 0) = a(j1, j2, 0) * 0.5d0 +! end do +! end do +! call ddst3d(n1max, n2max, n1, n2, n3, 1, a, t, ip, w) +! do j3 = 0, n3 - 1 +! do j2 = 0, n2 - 1 +! do j1 = 0, n1 - 1 +! a(j1,j2,j3) = a(j1,j2,j3) * (8.0d0/n1/n2/n3) +! end do +! end do +! end do +! . +! +! + subroutine cdft3d(n1max, n2max, n1, n2, n3, isgn, a, + & t, ip, w) + integer n1max, n2max, n1, n2, n3, isgn, ip(0 : *), n + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), + & t(0 : *), w(0 : *) + n = 2 * max(n2, n3) + n = max(n, n1) + if (n .gt. 4 * ip(0)) then + call makewt(n / 4, ip, w) + end if + call xdft3da_sub(n1max, n2max, n1, n2, n3, 0, + & isgn, a, t, ip, w) + call cdft3db_sub(n1max, n2max, n1, n2, n3, + & isgn, a, t, ip, w) + end +! + subroutine rdft3d(n1max, n2max, n1, n2, n3, isgn, a, + & t, ip, w) + integer n1max, n2max, n1, n2, n3, isgn, ip(0 : *), + & n, nw, nc + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), + & t(0 : *), w(0 : *) + n = 2 * max(n2, n3) + n = max(n, n1) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n1 .gt. 4 * nc) then + nc = n1 / 4 + call makect(nc, ip, w(nw)) + end if + if (isgn .lt. 0) then + call rdft3d_sub(n1max, n2max, n1, n2, n3, isgn, a) + call cdft3db_sub(n1max, n2max, n1, n2, n3, + & isgn, a, t, ip, w) + call xdft3da_sub(n1max, n2max, n1, n2, n3, 1, + & isgn, a, t, ip, w) + else + call xdft3da_sub(n1max, n2max, n1, n2, n3, 1, + & isgn, a, t, ip, w) + call cdft3db_sub(n1max, n2max, n1, n2, n3, + & isgn, a, t, ip, w) + call rdft3d_sub(n1max, n2max, n1, n2, n3, isgn, a) + end if + end +! + subroutine rdft3dsort(n1max, n2max, n1, n2, n3, isgn, a) + integer n1max, n2max, n1, n2, n3, isgn, n2h, n3h, j, k + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), x, y + n2h = n2 / 2 + n3h = n3 / 2 + if (isgn .lt. 0) then + do k = 0, n3 - 1 + do j = n2h + 1, n2 - 1 + a(0, j, k) = a(n1 + 1, j, k) + a(1, j, k) = a(n1, j, k) + end do + end do + do k = n3h + 1, n3 - 1 + a(0, 0, k) = a(n1 + 1, 0, k) + a(1, 0, k) = a(n1, 0, k) + a(0, n2h, k) = a(n1 + 1, n2h, k) + a(1, n2h, k) = a(n1, n2h, k) + end do + a(1, 0, 0) = a(n1, 0, 0) + a(1, n2h, 0) = a(n1, n2h, 0) + a(1, 0, n3h) = a(n1, 0, n3h) + a(1, n2h, n3h) = a(n1, n2h, n3h) + else + do j = n2h + 1, n2 - 1 + y = a(0, j, 0) + x = a(1, j, 0) + a(n1, j, 0) = x + a(n1 + 1, j, 0) = y + a(n1, n2 - j, 0) = x + a(n1 + 1, n2 - j, 0) = -y + a(0, j, 0) = a(0, n2 - j, 0) + a(1, j, 0) = -a(1, n2 - j, 0) + end do + do k = 1, n3 - 1 + do j = n2h + 1, n2 - 1 + y = a(0, j, k) + x = a(1, j, k) + a(n1, j, k) = x + a(n1 + 1, j, k) = y + a(n1, n2 - j, n3 - k) = x + a(n1 + 1, n2 - j, n3 - k) = -y + a(0, j, k) = a(0, n2 - j, n3 - k) + a(1, j, k) = -a(1, n2 - j, n3 - k) + end do + end do + do k = n3h + 1, n3 - 1 + y = a(0, 0, k) + x = a(1, 0, k) + a(n1, 0, k) = x + a(n1 + 1, 0, k) = y + a(n1, 0, n3 - k) = x + a(n1 + 1, 0, n3 - k) = -y + a(0, 0, k) = a(0, 0, n3 - k) + a(1, 0, k) = -a(1, 0, n3 - k) + y = a(0, n2h, k) + x = a(1, n2h, k) + a(n1, n2h, k) = x + a(n1 + 1, n2h, k) = y + a(n1, n2h, n3 - k) = x + a(n1 + 1, n2h, n3 - k) = -y + a(0, n2h, k) = a(0, n2h, n3 - k) + a(1, n2h, k) = -a(1, n2h, n3 - k) + end do + a(n1, 0, 0) = a(1, 0, 0) + a(n1 + 1, 0, 0) = 0 + a(1, 0, 0) = 0 + a(n1, n2h, 0) = a(1, n2h, 0) + a(n1 + 1, n2h, 0) = 0 + a(1, n2h, 0) = 0 + a(n1, 0, n3h) = a(1, 0, n3h) + a(n1 + 1, 0, n3h) = 0 + a(1, 0, n3h) = 0 + a(n1, n2h, n3h) = a(1, n2h, n3h) + a(n1 + 1, n2h, n3h) = 0 + a(1, n2h, n3h) = 0 + end if + end +! + subroutine ddct3d(n1max, n2max, n1, n2, n3, isgn, a, + & t, ip, w) + integer n1max, n2max, n1, n2, n3, isgn, ip(0 : *), + & n, nw, nc + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), + & t(0 : *), w(0 : *) + n = max(n2, n3) + n = max(n, n1) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. nc) then + nc = n + call makect(nc, ip, w(nw)) + end if + call ddxt3da_sub(n1max, n2max, n1, n2, n3, 0, + & isgn, a, t, ip, w) + call ddxt3db_sub(n1max, n2max, n1, n2, n3, 0, + & isgn, a, t, ip, w) + end +! + subroutine ddst3d(n1max, n2max, n1, n2, n3, isgn, a, + & t, ip, w) + integer n1max, n2max, n1, n2, n3, isgn, ip(0 : *), + & n, nw, nc + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), + & t(0 : *), w(0 : *) + n = max(n2, n3) + n = max(n, n1) + nw = ip(0) + if (n .gt. 4 * nw) then + nw = n / 4 + call makewt(nw, ip, w) + end if + nc = ip(1) + if (n .gt. nc) then + nc = n + call makect(nc, ip, w(nw)) + end if + call ddxt3da_sub(n1max, n2max, n1, n2, n3, 1, + & isgn, a, t, ip, w) + call ddxt3db_sub(n1max, n2max, n1, n2, n3, 1, + & isgn, a, t, ip, w) + end +! +! -------- child routines -------- +! + subroutine xdft3da_sub(n1max, n2max, n1, n2, n3, icr, + & isgn, a, t, ip, w) + integer n1max, n2max, n1, n2, n3, icr, isgn, + & ip(0 : *), i, j, k + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), + & t(0 : *), w(0 : *) + do k = 0, n3 - 1 + if (icr .eq. 0) then + do j = 0, n2 - 1 + call cdft(n1, isgn, a(0, j, k), ip, w) + end do + else if (isgn .ge. 0) then + do j = 0, n2 - 1 + call rdft(n1, isgn, a(0, j, k), ip, w) + end do + end if + if (n1 .gt. 4) then + do i = 0, n1 - 8, 8 + do j = 0, n2 - 1 + t(2 * j) = a(i, j, k) + t(2 * j + 1) = a(i + 1, j, k) + t(2 * n2 + 2 * j) = a(i + 2, j, k) + t(2 * n2 + 2 * j + 1) = a(i + 3, j, k) + t(4 * n2 + 2 * j) = a(i + 4, j, k) + t(4 * n2 + 2 * j + 1) = a(i + 5, j, k) + t(6 * n2 + 2 * j) = a(i + 6, j, k) + t(6 * n2 + 2 * j + 1) = a(i + 7, j, k) + end do + call cdft(2 * n2, isgn, t, ip, w) + call cdft(2 * n2, isgn, t(2 * n2), ip, w) + call cdft(2 * n2, isgn, t(4 * n2), ip, w) + call cdft(2 * n2, isgn, t(6 * n2), ip, w) + do j = 0, n2 - 1 + a(i, j, k) = t(2 * j) + a(i + 1, j, k) = t(2 * j + 1) + a(i + 2, j, k) = t(2 * n2 + 2 * j) + a(i + 3, j, k) = t(2 * n2 + 2 * j + 1) + a(i + 4, j, k) = t(4 * n2 + 2 * j) + a(i + 5, j, k) = t(4 * n2 + 2 * j + 1) + a(i + 6, j, k) = t(6 * n2 + 2 * j) + a(i + 7, j, k) = t(6 * n2 + 2 * j + 1) + end do + end do + else if (n1 .eq. 4) then + do j = 0, n2 - 1 + t(2 * j) = a(0, j, k) + t(2 * j + 1) = a(1, j, k) + t(2 * n2 + 2 * j) = a(2, j, k) + t(2 * n2 + 2 * j + 1) = a(3, j, k) + end do + call cdft(2 * n2, isgn, t, ip, w) + call cdft(2 * n2, isgn, t(2 * n2), ip, w) + do j = 0, n2 - 1 + a(0, j, k) = t(2 * j) + a(1, j, k) = t(2 * j + 1) + a(2, j, k) = t(2 * n2 + 2 * j) + a(3, j, k) = t(2 * n2 + 2 * j + 1) + end do + else if (n1 .eq. 2) then + do j = 0, n2 - 1 + t(2 * j) = a(0, j, k) + t(2 * j + 1) = a(1, j, k) + end do + call cdft(2 * n2, isgn, t, ip, w) + do j = 0, n2 - 1 + a(0, j, k) = t(2 * j) + a(1, j, k) = t(2 * j + 1) + end do + end if + if (icr .ne. 0 .and. isgn .lt. 0) then + do j = 0, n2 - 1 + call rdft(n1, isgn, a(0, j, k), ip, w) + end do + end if + end do + end +! + subroutine cdft3db_sub(n1max, n2max, n1, n2, n3, + & isgn, a, t, ip, w) + integer n1max, n2max, n1, n2, n3, isgn, ip(0 : *), + & i, j, k + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), + & t(0 : *), w(0 : *) + if (n1 .gt. 4) then + do j = 0, n2 - 1 + do i = 0, n1 - 8, 8 + do k = 0, n3 - 1 + t(2 * k) = a(i, j, k) + t(2 * k + 1) = a(i + 1, j, k) + t(2 * n3 + 2 * k) = a(i + 2, j, k) + t(2 * n3 + 2 * k + 1) = a(i + 3, j, k) + t(4 * n3 + 2 * k) = a(i + 4, j, k) + t(4 * n3 + 2 * k + 1) = a(i + 5, j, k) + t(6 * n3 + 2 * k) = a(i + 6, j, k) + t(6 * n3 + 2 * k + 1) = a(i + 7, j, k) + end do + call cdft(2 * n3, isgn, t, ip, w) + call cdft(2 * n3, isgn, t(2 * n3), ip, w) + call cdft(2 * n3, isgn, t(4 * n3), ip, w) + call cdft(2 * n3, isgn, t(6 * n3), ip, w) + do k = 0, n3 - 1 + a(i, j, k) = t(2 * k) + a(i + 1, j, k) = t(2 * k + 1) + a(i + 2, j, k) = t(2 * n3 + 2 * k) + a(i + 3, j, k) = t(2 * n3 + 2 * k + 1) + a(i + 4, j, k) = t(4 * n3 + 2 * k) + a(i + 5, j, k) = t(4 * n3 + 2 * k + 1) + a(i + 6, j, k) = t(6 * n3 + 2 * k) + a(i + 7, j, k) = t(6 * n3 + 2 * k + 1) + end do + end do + end do + else if (n1 .eq. 4) then + do j = 0, n2 - 1 + do k = 0, n3 - 1 + t(2 * k) = a(0, j, k) + t(2 * k + 1) = a(1, j, k) + t(2 * n3 + 2 * k) = a(2, j, k) + t(2 * n3 + 2 * k + 1) = a(3, j, k) + end do + call cdft(2 * n3, isgn, t, ip, w) + call cdft(2 * n3, isgn, t(2 * n3), ip, w) + do k = 0, n3 - 1 + a(0, j, k) = t(2 * k) + a(1, j, k) = t(2 * k + 1) + a(2, j, k) = t(2 * n3 + 2 * k) + a(3, j, k) = t(2 * n3 + 2 * k + 1) + end do + end do + else if (n1 .eq. 2) then + do j = 0, n2 - 1 + do k = 0, n3 - 1 + t(2 * k) = a(0, j, k) + t(2 * k + 1) = a(1, j, k) + end do + call cdft(2 * n3, isgn, t, ip, w) + do k = 0, n3 - 1 + a(0, j, k) = t(2 * k) + a(1, j, k) = t(2 * k + 1) + end do + end do + end if + end +! + subroutine rdft3d_sub(n1max, n2max, n1, n2, n3, isgn, a) + integer n1max, n2max, n1, n2, n3, isgn, + & n2h, n3h, i, j, k, l + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), xi + n2h = n2 / 2 + n3h = n3 / 2 + if (isgn .lt. 0) then + do k = 1, n3h - 1 + l = n3 - k + xi = a(0, 0, k) - a(0, 0, l) + a(0, 0, k) = a(0, 0, k) + a(0, 0, l) + a(0, 0, l) = xi + xi = a(1, 0, l) - a(1, 0, k) + a(1, 0, k) = a(1, 0, k) + a(1, 0, l) + a(1, 0, l) = xi + xi = a(0, n2h, k) - a(0, n2h, l) + a(0, n2h, k) = a(0, n2h, k) + a(0, n2h, l) + a(0, n2h, l) = xi + xi = a(1, n2h, l) - a(1, n2h, k) + a(1, n2h, k) = a(1, n2h, k) + a(1, n2h, l) + a(1, n2h, l) = xi + do i = 1, n2h - 1 + j = n2 - i + xi = a(0, i, k) - a(0, j, l) + a(0, i, k) = a(0, i, k) + a(0, j, l) + a(0, j, l) = xi + xi = a(1, j, l) - a(1, i, k) + a(1, i, k) = a(1, i, k) + a(1, j, l) + a(1, j, l) = xi + xi = a(0, i, l) - a(0, j, k) + a(0, i, l) = a(0, i, l) + a(0, j, k) + a(0, j, k) = xi + xi = a(1, j, k) - a(1, i, l) + a(1, i, l) = a(1, i, l) + a(1, j, k) + a(1, j, k) = xi + end do + end do + do i = 1, n2h - 1 + j = n2 - i + xi = a(0, i, 0) - a(0, j, 0) + a(0, i, 0) = a(0, i, 0) + a(0, j, 0) + a(0, j, 0) = xi + xi = a(1, j, 0) - a(1, i, 0) + a(1, i, 0) = a(1, i, 0) + a(1, j, 0) + a(1, j, 0) = xi + xi = a(0, i, n3h) - a(0, j, n3h) + a(0, i, n3h) = a(0, i, n3h) + a(0, j, n3h) + a(0, j, n3h) = xi + xi = a(1, j, n3h) - a(1, i, n3h) + a(1, i, n3h) = a(1, i, n3h) + a(1, j, n3h) + a(1, j, n3h) = xi + end do + else + do k = 1, n3h - 1 + l = n3 - k + a(0, 0, l) = 0.5d0 * (a(0, 0, k) - a(0, 0, l)) + a(0, 0, k) = a(0, 0, k) - a(0, 0, l) + a(1, 0, l) = 0.5d0 * (a(1, 0, k) + a(1, 0, l)) + a(1, 0, k) = a(1, 0, k) - a(1, 0, l) + a(0, n2h, l) = 0.5d0 * (a(0, n2h, k) - a(0, n2h, l)) + a(0, n2h, k) = a(0, n2h, k) - a(0, n2h, l) + a(1, n2h, l) = 0.5d0 * (a(1, n2h, k) + a(1, n2h, l)) + a(1, n2h, k) = a(1, n2h, k) - a(1, n2h, l) + do i = 1, n2h - 1 + j = n2 - i + a(0, j, l) = 0.5d0 * (a(0, i, k) - a(0, j, l)) + a(0, i, k) = a(0, i, k) - a(0, j, l) + a(1, j, l) = 0.5d0 * (a(1, i, k) + a(1, j, l)) + a(1, i, k) = a(1, i, k) - a(1, j, l) + a(0, j, k) = 0.5d0 * (a(0, i, l) - a(0, j, k)) + a(0, i, l) = a(0, i, l) - a(0, j, k) + a(1, j, k) = 0.5d0 * (a(1, i, l) + a(1, j, k)) + a(1, i, l) = a(1, i, l) - a(1, j, k) + end do + end do + do i = 1, n2h - 1 + j = n2 - i + a(0, j, 0) = 0.5d0 * (a(0, i, 0) - a(0, j, 0)) + a(0, i, 0) = a(0, i, 0) - a(0, j, 0) + a(1, j, 0) = 0.5d0 * (a(1, i, 0) + a(1, j, 0)) + a(1, i, 0) = a(1, i, 0) - a(1, j, 0) + a(0, j, n3h) = 0.5d0 * (a(0, i, n3h) - a(0, j, n3h)) + a(0, i, n3h) = a(0, i, n3h) - a(0, j, n3h) + a(1, j, n3h) = 0.5d0 * (a(1, i, n3h) + a(1, j, n3h)) + a(1, i, n3h) = a(1, i, n3h) - a(1, j, n3h) + end do + end if + end +! + subroutine ddxt3da_sub(n1max, n2max, n1, n2, n3, ics, + & isgn, a, t, ip, w) + integer n1max, n2max, n1, n2, n3, ics, isgn, + & ip(0 : *), i, j, k + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), + & t(0 : *), w(0 : *) + do k = 0, n3 - 1 + if (ics .eq. 0) then + do j = 0, n2 - 1 + call ddct(n1, isgn, a(0, j, k), ip, w) + end do + else + do j = 0, n2 - 1 + call ddst(n1, isgn, a(0, j, k), ip, w) + end do + end if + if (n1 .gt. 2) then + do i = 0, n1 - 4, 4 + do j = 0, n2 - 1 + t(j) = a(i, j, k) + t(n2 + j) = a(i + 1, j, k) + t(2 * n2 + j) = a(i + 2, j, k) + t(3 * n2 + j) = a(i + 3, j, k) + end do + if (ics .eq. 0) then + call ddct(n2, isgn, t, ip, w) + call ddct(n2, isgn, t(n2), ip, w) + call ddct(n2, isgn, t(2 * n2), ip, w) + call ddct(n2, isgn, t(3 * n2), ip, w) + else + call ddst(n2, isgn, t, ip, w) + call ddst(n2, isgn, t(n2), ip, w) + call ddst(n2, isgn, t(2 * n2), ip, w) + call ddst(n2, isgn, t(3 * n2), ip, w) + end if + do j = 0, n2 - 1 + a(i, j, k) = t(j) + a(i + 1, j, k) = t(n2 + j) + a(i + 2, j, k) = t(2 * n2 + j) + a(i + 3, j, k) = t(3 * n2 + j) + end do + end do + else if (n1 .eq. 2) then + do j = 0, n2 - 1 + t(j) = a(0, j, k) + t(n2 + j) = a(1, j, k) + end do + if (ics .eq. 0) then + call ddct(n2, isgn, t, ip, w) + call ddct(n2, isgn, t(n2), ip, w) + else + call ddst(n2, isgn, t, ip, w) + call ddst(n2, isgn, t(n2), ip, w) + end if + do j = 0, n2 - 1 + a(0, j, k) = t(j) + a(1, j, k) = t(n2 + j) + end do + end if + end do + end +! + subroutine ddxt3db_sub(n1max, n2max, n1, n2, n3, ics, + & isgn, a, t, ip, w) + integer n1max, n2max, n1, n2, n3, ics, isgn, + & ip(0 : *), i, j, k + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : n3 - 1), + & t(0 : *), w(0 : *) + if (n1 .gt. 2) then + do j = 0, n2 - 1 + do i = 0, n1 - 4, 4 + do k = 0, n3 - 1 + t(k) = a(i, j, k) + t(n3 + k) = a(i + 1, j, k) + t(2 * n3 + k) = a(i + 2, j, k) + t(3 * n3 + k) = a(i + 3, j, k) + end do + if (ics .eq. 0) then + call ddct(n3, isgn, t, ip, w) + call ddct(n3, isgn, t(n3), ip, w) + call ddct(n3, isgn, t(2 * n3), ip, w) + call ddct(n3, isgn, t(3 * n3), ip, w) + else + call ddst(n3, isgn, t, ip, w) + call ddst(n3, isgn, t(n3), ip, w) + call ddst(n3, isgn, t(2 * n3), ip, w) + call ddst(n3, isgn, t(3 * n3), ip, w) + end if + do k = 0, n3 - 1 + a(i, j, k) = t(k) + a(i + 1, j, k) = t(n3 + k) + a(i + 2, j, k) = t(2 * n3 + k) + a(i + 3, j, k) = t(3 * n3 + k) + end do + end do + end do + else if (n1 .eq. 2) then + do j = 0, n2 - 1 + do k = 0, n3 - 1 + t(k) = a(0, j, k) + t(n3 + k) = a(1, j, k) + end do + if (ics .eq. 0) then + call ddct(n3, isgn, t, ip, w) + call ddct(n3, isgn, t(n3), ip, w) + else + call ddst(n3, isgn, t, ip, w) + call ddst(n3, isgn, t(n3), ip, w) + end if + do k = 0, n3 - 1 + a(0, j, k) = t(k) + a(1, j, k) = t(n3 + k) + end do + end do + end if + end +!
diff --git a/third_party/tensorflow_dependencies/fft2d/readme2d.txt b/third_party/tensorflow_dependencies/fft2d/readme2d.txt new file mode 100644 index 0000000..7cc4dfa --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/readme2d.txt
@@ -0,0 +1,77 @@ +General Purpose 2D,3D FFT (Fast Fourier Transform) Package + +Files + alloc.c : 2D-array Allocation + alloc.h : 2D-array Allocation + fft4f2d.c : 2D FFT Package in C - Version I (radix 4, 2) + fft4f2d.f : 2D FFT Package in Fortran - Version I (radix 4, 2) + fftsg.c : 1D FFT Package in C - Fast Version (Split-Radix) + fftsg.f : 1D FFT Package in Fortran - Fast Version (Split-Radix) + fftsg2d.c : 2D FFT Package in C - Version II (Split-Radix) + fftsg2d.f : 2D FFT Package in Fortran - Version II (Split-Radix) + fftsg3d.c : 3D FFT Package in C - Version II (Split-Radix) + fftsg3d.f : 3D FFT Package in Fortran - Version II (Split-Radix) + shrtdct.c : 8x8, 16x16 DCT Package + sample2d/ + Makefile : for gcc, cc + Makefile.f77: for Fortran + Makefile.pth: Pthread version + fft4f2dt.c : Test Program for "fft4f2d.c" + fft4f2dt.f : Test Program for "fft4f2d.f" + fftsg2dt.c : Test Program for "fftsg2d.c" + fftsg2dt.f : Test Program for "fftsg2d.f" + fftsg3dt.c : Test Program for "fftsg3d.c" + fftsg3dt.f : Test Program for "fftsg3d.f" + shrtdctt.c : Test Program for "shrtdct.c" + +Difference of Files + C and Fortran versions are equal and + the same routines are in each version. + ---- Difference between "fft4f2d.*" and "fftsg2d.*" ---- + "fft4f2d.*" are optimized for the old machines that + don't have the large size CPU cache. + "fftsg2d.*", "fftsg3d.*" use 1D FFT routines in "fftsg.*". + "fftsg2d.*", "fftsg3d.*" are optimized for the machines that + have the multi-level (L1,L2,etc) cache. + +Routines in the Package + in fft4f2d.*, fftsg2d.* + cdft2d: 2-dim Complex Discrete Fourier Transform + rdft2d: 2-dim Real Discrete Fourier Transform + ddct2d: 2-dim Discrete Cosine Transform + ddst2d: 2-dim Discrete Sine Transform + rdft2dsort: rdft2d input/output ordering (fftsg2d.*) + in fftsg3d.* + cdft3d: 3-dim Complex Discrete Fourier Transform + rdft3d: 3-dim Real Discrete Fourier Transform + ddct3d: 3-dim Discrete Cosine Transform + ddst3d: 3-dim Discrete Sine Transform + rdft3dsort: rdft3d input/output ordering + in fftsg.* + cdft: 1-dim Complex Discrete Fourier Transform + rdft: 1-dim Real Discrete Fourier Transform + ddct: 1-dim Discrete Cosine Transform + ddst: 1-dim Discrete Sine Transform + dfct: 1-dim Real Symmetric DFT + dfst: 1-dim Real Anti-symmetric DFT + (these routines are called by fftsg2d.*, fftsg3d.*) + in shrtdct.c + ddct8x8s : Normalized 8x8 DCT + ddct16x16s: Normalized 16x16 DCT + (faster than ddct2d()) + +Usage + Brief explanations are in block comments of each packages. + The examples are given in the test programs. + +Copyright + Copyright(C) 1997,2001 Takuya OOURA (email: ooura@kurims.kyoto-u.ac.jp). + You may use, copy, modify this code for any purpose and + without fee. You may distribute this ORIGINAL package. + +History + ... + Nov. 2001 : Add 3D-FFT routines + Dec. 2006 : Fix a documentation bug in "fftsg3d.*" + Dec. 2006 : Fix a minor bug in "fftsg.f" +
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile b/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile new file mode 100644 index 0000000..130e0a4 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile
@@ -0,0 +1,72 @@ +# ---- for GNU gcc ---- + +CC = gcc + +CFLAGS = -Wall + +OFLAGS = -O2 + +# ---- for SUN WS cc ---- +# +#CC = cc +# +#CFLAGS = +# +#OFLAGS = -xO2 + + + + +all: fft4f2dt fftsg2dt fftsg3dt shrtdctt + + +fft4f2dt : fft4f2dt.o fft4f2d.o alloc.o + $(CC) fft4f2dt.o fft4f2d.o alloc.o -lm -o fft4f2dt + +fftsg2dt : fftsg2dt.o fftsg2d.o fftsg.o alloc.o + $(CC) fftsg2dt.o fftsg2d.o fftsg.o alloc.o -lm -o fftsg2dt + +fftsg3dt : fftsg3dt.o fftsg3d.o fftsg.o alloc.o + $(CC) fftsg3dt.o fftsg3d.o fftsg.o alloc.o -lm -o fftsg3dt + +shrtdctt : shrtdctt.o shrtdct.o + $(CC) shrtdctt.o shrtdct.o -lm -o shrtdctt + + +fft4f2dt.o : fft4f2dt.c + $(CC) $(CFLAGS) $(OFLAGS) -c fft4f2dt.c -o fft4f2dt.o + +fftsg2dt.o : fftsg2dt.c + $(CC) $(CFLAGS) $(OFLAGS) -c fftsg2dt.c -o fftsg2dt.o + +fftsg3dt.o : fftsg3dt.c + $(CC) $(CFLAGS) $(OFLAGS) -c fftsg3dt.c -o fftsg3dt.o + +shrtdctt.o : shrtdctt.c + $(CC) $(CFLAGS) $(OFLAGS) -c shrtdctt.c -o shrtdctt.o + + +fft4f2d.o : ../fft4f2d.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../fft4f2d.c -o fft4f2d.o + +fftsg2d.o : ../fftsg2d.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../fftsg2d.c -o fftsg2d.o + +fftsg3d.o : ../fftsg3d.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../fftsg3d.c -o fftsg3d.o + +fftsg.o : ../fftsg.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../fftsg.c -o fftsg.o + +alloc.o : ../alloc.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../alloc.c -o alloc.o + +shrtdct.o : ../shrtdct.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../shrtdct.c -o shrtdct.o + + + + +clean: + rm -f *.o +
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile.f77 b/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile.f77 new file mode 100644 index 0000000..0162fdc --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile.f77
@@ -0,0 +1,60 @@ +# ---- for GNU g77 ---- + +F77 = g77 + +FFLAGS = -Wall + +OFLAGS = -O2 + +# ---- for SUN WS f77 ---- +# +#F77 = f77 +# +#FFLAGS = +# +#OFLAGS = -xO2 + + + + +all: fft4f2dt_f fftsg2dt_f fftsg3dt_f + + +fft4f2dt_f : fft4f2dt_f.o fft4f2d_f.o + $(F77) fft4f2dt_f.o fft4f2d_f.o -o fft4f2dt_f + +fftsg2dt_f : fftsg2dt_f.o fftsg2d_f.o fftsg_f.o + $(F77) fftsg2dt_f.o fftsg2d_f.o fftsg_f.o -o fftsg2dt_f + +fftsg3dt_f : fftsg3dt_f.o fftsg3d_f.o fftsg_f.o + $(F77) fftsg3dt_f.o fftsg3d_f.o fftsg_f.o -o fftsg3dt_f + + +fft4f2dt_f.o : fft4f2dt.f + $(F77) $(FFLAGS) $(OFLAGS) -c fft4f2dt.f -o fft4f2dt_f.o + +fftsg2dt_f.o : fftsg2dt.f + $(F77) $(FFLAGS) $(OFLAGS) -c fftsg2dt.f -o fftsg2dt_f.o + +fftsg3dt_f.o : fftsg3dt.f + $(F77) $(FFLAGS) $(OFLAGS) -c fftsg3dt.f -o fftsg3dt_f.o + + +fft4f2d_f.o : ../fft4f2d.f + $(F77) $(FFLAGS) $(OFLAGS) -c ../fft4f2d.f -o fft4f2d_f.o + +fftsg2d_f.o : ../fftsg2d.f + $(F77) $(FFLAGS) $(OFLAGS) -c ../fftsg2d.f -o fftsg2d_f.o + +fftsg3d_f.o : ../fftsg3d.f + $(F77) $(FFLAGS) $(OFLAGS) -c ../fftsg3d.f -o fftsg3d_f.o + +fftsg_f.o : ../fftsg.f + $(F77) $(FFLAGS) $(OFLAGS) -c ../fftsg.f -o fftsg_f.o + + + + +clean: + rm -f *.o +
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile.pth b/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile.pth new file mode 100644 index 0000000..d46941e --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/Makefile.pth
@@ -0,0 +1,54 @@ +# ---- for GNU gcc ---- + +CC = gcc + +CFLAGS = -Wall -DUSE_FFT2D_PTHREADS -DUSE_FFT3D_PTHREADS + +OFLAGS = -O2 + +# ---- for SUN WS cc ---- +# +#CC = cc +# +#CFLAGS = -Wall -DUSE_FFT2D_PTHREADS -DUSE_FFT3D_PTHREADS +# +#OFLAGS = -xO2 + + + + +all: fftsg2dt_pt fftsg3dt_pt + + +fftsg2dt_pt : fftsg2dt.o fftsg2dpt.o fftsg.o alloc.o + $(CC) fftsg2dt.o fftsg2dpt.o fftsg.o alloc.o -lm -lpthread -o fftsg2dt_pt + +fftsg3dt_pt : fftsg3dt.o fftsg3dpt.o fftsg.o alloc.o + $(CC) fftsg3dt.o fftsg3dpt.o fftsg.o alloc.o -lm -lpthread -o fftsg3dt_pt + + +fftsg2dt.o : fftsg2dt.c + $(CC) $(CFLAGS) $(OFLAGS) -c fftsg2dt.c -o fftsg2dt.o + +fftsg3dt.o : fftsg3dt.c + $(CC) $(CFLAGS) $(OFLAGS) -c fftsg3dt.c -o fftsg3dt.o + + +fftsg2dpt.o : ../fftsg2d.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../fftsg2d.c -o fftsg2dpt.o + +fftsg3dpt.o : ../fftsg3d.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../fftsg3d.c -o fftsg3dpt.o + +fftsg.o : ../fftsg.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../fftsg.c -o fftsg.o + +alloc.o : ../alloc.c + $(CC) $(CFLAGS) $(OFLAGS) -c ../alloc.c -o alloc.o + + + + +clean: + rm -f *.o +
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/alloc.h b/third_party/tensorflow_dependencies/fft2d/sample2d/alloc.h new file mode 100644 index 0000000..3467cc4 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/alloc.h
@@ -0,0 +1,20 @@ +/* ---- memory allocation ---- */ + + +#include <stdlib.h> +#include <stdio.h> + + +int *alloc_1d_int(int n1); +void free_1d_int(int *i); +double *alloc_1d_double(int n1); +void free_1d_double(double *d); +int **alloc_2d_int(int n1, int n2); +void free_2d_int(int **ii); +double **alloc_2d_double(int n1, int n2); +void free_2d_double(double **dd); +int ***alloc_3d_int(int n1, int n2, int n3); +void free_3d_int(int ***iii); +double ***alloc_3d_double(int n1, int n2, int n3); +void free_3d_double(double ***ddd); +
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/fft4f2dt.c b/third_party/tensorflow_dependencies/fft2d/sample2d/fft4f2dt.c new file mode 100644 index 0000000..2f300fd --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/fft4f2dt.c
@@ -0,0 +1,109 @@ +/* test of fft4f2d.c */ + +#include <math.h> +#include <stdio.h> +#include "alloc.h" +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +/* random number generator, 0 <= RND < 1 */ +#define RND(p) ((*(p) = (*(p) * 7141 + 54773) % 259200) * (1.0 / 259200)) + + +int main() +{ + void cdft2d(int, int, int, double **, int *, double *); + void rdft2d(int, int, int, double **, int *, double *); + void ddct2d(int, int, int, double **, double **, int *, double *); + void ddst2d(int, int, int, double **, double **, int *, double *); + void putdata2d(int n1, int n2, double **a); + double errorcheck2d(int n1, int n2, double scale, double **a); + int *ip, n1, n2, n, i; + double **a, **t, *w, err; + + printf("data length n1=? (n1 = power of 2) \n"); + scanf("%d", &n1); + printf("data length n2=? (n2 = power of 2) \n"); + scanf("%d", &n2); + + a = alloc_2d_double(n1, n2); + t = alloc_2d_double(n1, n2); + n = MAX(n1, n2 / 2); + ip = alloc_1d_int(2 + (int) sqrt(n + 0.5)); + n = MAX(n1 / 2, n2 / 4) + MAX(n1, n2); + w = alloc_1d_double(n); + ip[0] = 0; + + /* check of CDFT */ + putdata2d(n1, n2, a); + cdft2d(n1, n2, 1, a, ip, w); + cdft2d(n1, n2, -1, a, ip, w); + err = errorcheck2d(n1, n2, 2.0 / n1 / n2, a); + printf("cdft2d err= %g \n", err); + + /* check of RDFT */ + putdata2d(n1, n2, a); + rdft2d(n1, n2, 1, a, ip, w); + rdft2d(n1, n2, -1, a, ip, w); + err = errorcheck2d(n1, n2, 2.0 / n1 / n2, a); + printf("rdft2d err= %g \n", err); + + /* check of DDCT */ + putdata2d(n1, n2, a); + ddct2d(n1, n2, 1, a, t, ip, w); + ddct2d(n1, n2, -1, a, t, ip, w); + for (i = 0; i <= n1 - 1; i++) { + a[i][0] *= 0.5; + } + for (i = 0; i <= n2 - 1; i++) { + a[0][i] *= 0.5; + } + err = errorcheck2d(n1, n2, 4.0 / n1 / n2, a); + printf("ddct2d err= %g \n", err); + + /* check of DDST */ + putdata2d(n1, n2, a); + ddst2d(n1, n2, 1, a, t, ip, w); + ddst2d(n1, n2, -1, a, t, ip, w); + for (i = 0; i <= n1 - 1; i++) { + a[i][0] *= 0.5; + } + for (i = 0; i <= n2 - 1; i++) { + a[0][i] *= 0.5; + } + err = errorcheck2d(n1, n2, 4.0 / n1 / n2, a); + printf("ddst2d err= %g \n", err); + + free_1d_double(w); + free_1d_int(ip); + free_2d_double(t); + free_2d_double(a); + return 0; +} + + +void putdata2d(int n1, int n2, double **a) +{ + int j1, j2, seed = 0; + + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] = RND(&seed); + } + } +} + + +double errorcheck2d(int n1, int n2, double scale, double **a) +{ + int j1, j2, seed = 0; + double err = 0, e; + + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + e = RND(&seed) - a[j1][j2] * scale; + err = MAX(err, fabs(e)); + } + } + return err; +} +
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/fft4f2dt.f b/third_party/tensorflow_dependencies/fft2d/sample2d/fft4f2dt.f new file mode 100644 index 0000000..43ac8ac --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/fft4f2dt.f
@@ -0,0 +1,95 @@ +! test of fft4f2d.f +! + program main + integer nmax, nmaxsqrt + parameter (nmax = 1024) + parameter (nmaxsqrt = 32) + integer ip(0 : nmaxsqrt + 1), n1, n2, i + real*8 a(0 : nmax - 1, 0 : nmax - 1), + & t(0 : nmax - 1, 0 : nmax - 1), w(0 : nmax * 3 / 2 - 1), + & err, errorcheck2d +! + write (*, *) 'data length n1=? (n1 = power of 2) ' + read (*, *) n1 + write (*, *) 'data length n2=? (n2 = power of 2) ' + read (*, *) n2 + ip(0) = 0 +! +! check of CDFT + call putdata2d(nmax, n1, n2, a) + call cdft2d(nmax, n1, n2, 1, a, ip, w) + call cdft2d(nmax, n1, n2, -1, a, ip, w) + err = errorcheck2d(nmax, n1, n2, 2.0d0 / n1 / n2, a) + write (*, *) 'cdft2d err= ', err +! +! check of RDFT + call putdata2d(nmax, n1, n2, a) + call rdft2d(nmax, n1, n2, 1, a, ip, w) + call rdft2d(nmax, n1, n2, -1, a, ip, w) + err = errorcheck2d(nmax, n1, n2, 2.0d0 / n1 / n2, a) + write (*, *) 'rdft2d err= ', err +! +! check of DDCT + call putdata2d(nmax, n1, n2, a) + call ddct2d(nmax, n1, n2, 1, a, t, ip, w) + call ddct2d(nmax, n1, n2, -1, a, t, ip, w) + do i = 0, n1 - 1 + a(i, 0) = a(i, 0) * 0.5d0 + end do + do i = 0, n2 - 1 + a(0, i) = a(0, i) * 0.5d0 + end do + err = errorcheck2d(nmax, n1, n2, 4.0d0 / n1 / n2, a) + write (*, *) 'ddct2d err= ', err +! +! check of DDST + call putdata2d(nmax, n1, n2, a) + call ddst2d(nmax, n1, n2, 1, a, t, ip, w) + call ddst2d(nmax, n1, n2, -1, a, t, ip, w) + do i = 0, n1 - 1 + a(i, 0) = a(i, 0) * 0.5d0 + end do + do i = 0, n2 - 1 + a(0, i) = a(0, i) * 0.5d0 + end do + err = errorcheck2d(nmax, n1, n2, 4.0d0 / n1 / n2, a) + write (*, *) 'ddst2d err= ', err +! + end +! +! + subroutine putdata2d(n1max, n1, n2, a) + integer n1max, n1, n2, j1, j2, seed + real*8 a(0 : n1max - 1, 0 : *), drnd + seed = 0 + do j2 = 0, n2 - 1 + do j1 = 0, n1 - 1 + a(j1, j2) = drnd(seed) + end do + end do + end +! +! + function errorcheck2d(n1max, n1, n2, scale, a) + integer n1max, n1, n2, j1, j2, seed + real*8 scale, a(0 : n1max - 1, 0 : *), drnd, err, e, + & errorcheck2d + err = 0 + seed = 0 + do j2 = 0, n2 - 1 + do j1 = 0, n1 - 1 + e = drnd(seed) - a(j1, j2) * scale + err = max(err, abs(e)) + end do + end do + errorcheck2d = err + end +! +! +! random number generator, 0 <= drnd < 1 + real*8 function drnd(seed) + integer seed + seed = mod(seed * 7141 + 54773, 259200) + drnd = seed * (1.0d0 / 259200) + end +!
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg2dt.c b/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg2dt.c new file mode 100644 index 0000000..c4cf935 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg2dt.c
@@ -0,0 +1,107 @@ +/* test of fftsg2d.c */ + +#include <math.h> +#include <stdio.h> +#include "alloc.h" +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +/* random number generator, 0 <= RND < 1 */ +#define RND(p) ((*(p) = (*(p) * 7141 + 54773) % 259200) * (1.0 / 259200)) + + +int main() +{ + void cdft2d(int, int, int, double **, double *, int *, double *); + void rdft2d(int, int, int, double **, double *, int *, double *); + void ddct2d(int, int, int, double **, double *, int *, double *); + void ddst2d(int, int, int, double **, double *, int *, double *); + void putdata2d(int n1, int n2, double **a); + double errorcheck2d(int n1, int n2, double scale, double **a); + int *ip, n1, n2, n, i; + double **a, *w, err; + + printf("data length n1=? (n1 = power of 2) \n"); + scanf("%d", &n1); + printf("data length n2=? (n2 = power of 2) \n"); + scanf("%d", &n2); + + a = alloc_2d_double(n1, n2); + n = MAX(n1, n2 / 2); + ip = alloc_1d_int(2 + (int) sqrt(n + 0.5)); + n = MAX(n1, n2) * 3 / 2; + w = alloc_1d_double(n); + ip[0] = 0; + + /* check of CDFT */ + putdata2d(n1, n2, a); + cdft2d(n1, n2, 1, a, NULL, ip, w); + cdft2d(n1, n2, -1, a, NULL, ip, w); + err = errorcheck2d(n1, n2, 2.0 / n1 / n2, a); + printf("cdft2d err= %g \n", err); + + /* check of RDFT */ + putdata2d(n1, n2, a); + rdft2d(n1, n2, 1, a, NULL, ip, w); + rdft2d(n1, n2, -1, a, NULL, ip, w); + err = errorcheck2d(n1, n2, 2.0 / n1 / n2, a); + printf("rdft2d err= %g \n", err); + + /* check of DDCT */ + putdata2d(n1, n2, a); + ddct2d(n1, n2, 1, a, NULL, ip, w); + ddct2d(n1, n2, -1, a, NULL, ip, w); + for (i = 0; i <= n1 - 1; i++) { + a[i][0] *= 0.5; + } + for (i = 0; i <= n2 - 1; i++) { + a[0][i] *= 0.5; + } + err = errorcheck2d(n1, n2, 4.0 / n1 / n2, a); + printf("ddct2d err= %g \n", err); + + /* check of DDST */ + putdata2d(n1, n2, a); + ddst2d(n1, n2, 1, a, NULL, ip, w); + ddst2d(n1, n2, -1, a, NULL, ip, w); + for (i = 0; i <= n1 - 1; i++) { + a[i][0] *= 0.5; + } + for (i = 0; i <= n2 - 1; i++) { + a[0][i] *= 0.5; + } + err = errorcheck2d(n1, n2, 4.0 / n1 / n2, a); + printf("ddst2d err= %g \n", err); + + free_1d_double(w); + free_1d_int(ip); + free_2d_double(a); + return 0; +} + + +void putdata2d(int n1, int n2, double **a) +{ + int j1, j2, seed = 0; + + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] = RND(&seed); + } + } +} + + +double errorcheck2d(int n1, int n2, double scale, double **a) +{ + int j1, j2, seed = 0; + double err = 0, e; + + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + e = RND(&seed) - a[j1][j2] * scale; + err = MAX(err, fabs(e)); + } + } + return err; +} +
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg2dt.f b/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg2dt.f new file mode 100644 index 0000000..a375c05 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg2dt.f
@@ -0,0 +1,94 @@ +! test of fftsg2d.f +! + program main + integer nmax, nmaxsqrt + parameter (nmax = 1024) + parameter (nmaxsqrt = 32) + integer ip(0 : nmaxsqrt + 1), n1, n2, i + real*8 a(0 : nmax - 1, 0 : nmax - 1), t(0 : 8 * nmax - 1), + & w(0 : nmax * 3 / 2 - 1), err, errorcheck2d +! + write (*, *) 'data length n1=? (n1 = power of 2) ' + read (*, *) n1 + write (*, *) 'data length n2=? (n2 = power of 2) ' + read (*, *) n2 + ip(0) = 0 +! +! check of CDFT + call putdata2d(nmax, n1, n2, a) + call cdft2d(nmax, n1, n2, 1, a, t, ip, w) + call cdft2d(nmax, n1, n2, -1, a, t, ip, w) + err = errorcheck2d(nmax, n1, n2, 2.0d0 / n1 / n2, a) + write (*, *) 'cdft2d err= ', err +! +! check of RDFT + call putdata2d(nmax, n1, n2, a) + call rdft2d(nmax, n1, n2, 1, a, t, ip, w) + call rdft2d(nmax, n1, n2, -1, a, t, ip, w) + err = errorcheck2d(nmax, n1, n2, 2.0d0 / n1 / n2, a) + write (*, *) 'rdft2d err= ', err +! +! check of DDCT + call putdata2d(nmax, n1, n2, a) + call ddct2d(nmax, n1, n2, 1, a, t, ip, w) + call ddct2d(nmax, n1, n2, -1, a, t, ip, w) + do i = 0, n1 - 1 + a(i, 0) = a(i, 0) * 0.5d0 + end do + do i = 0, n2 - 1 + a(0, i) = a(0, i) * 0.5d0 + end do + err = errorcheck2d(nmax, n1, n2, 4.0d0 / n1 / n2, a) + write (*, *) 'ddct2d err= ', err +! +! check of DDST + call putdata2d(nmax, n1, n2, a) + call ddst2d(nmax, n1, n2, 1, a, t, ip, w) + call ddst2d(nmax, n1, n2, -1, a, t, ip, w) + do i = 0, n1 - 1 + a(i, 0) = a(i, 0) * 0.5d0 + end do + do i = 0, n2 - 1 + a(0, i) = a(0, i) * 0.5d0 + end do + err = errorcheck2d(nmax, n1, n2, 4.0d0 / n1 / n2, a) + write (*, *) 'ddst2d err= ', err +! + end +! +! + subroutine putdata2d(n1max, n1, n2, a) + integer n1max, n1, n2, j1, j2, seed + real*8 a(0 : n1max - 1, 0 : *), drnd + seed = 0 + do j2 = 0, n2 - 1 + do j1 = 0, n1 - 1 + a(j1, j2) = drnd(seed) + end do + end do + end +! +! + function errorcheck2d(n1max, n1, n2, scale, a) + integer n1max, n1, n2, j1, j2, seed + real*8 scale, a(0 : n1max - 1, 0 : *), drnd, err, e, + & errorcheck2d + err = 0 + seed = 0 + do j2 = 0, n2 - 1 + do j1 = 0, n1 - 1 + e = drnd(seed) - a(j1, j2) * scale + err = max(err, abs(e)) + end do + end do + errorcheck2d = err + end +! +! +! random number generator, 0 <= drnd < 1 + real*8 function drnd(seed) + integer seed + seed = mod(seed * 7141 + 54773, 259200) + drnd = seed * (1.0d0 / 259200) + end +!
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg3dt.c b/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg3dt.c new file mode 100644 index 0000000..87879e6 --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg3dt.c
@@ -0,0 +1,128 @@ +/* test of fftsg3d.c */ + +#include <math.h> +#include <stdio.h> +#include "alloc.h" +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +/* random number generator, 0 <= RND < 1 */ +#define RND(p) ((*(p) = (*(p) * 7141 + 54773) % 259200) * (1.0 / 259200)) + + +int main() +{ + void cdft3d(int, int, int, int, double ***, double *, int *, double *); + void rdft3d(int, int, int, int, double ***, double *, int *, double *); + void ddct3d(int, int, int, int, double ***, double *, int *, double *); + void ddst3d(int, int, int, int, double ***, double *, int *, double *); + void putdata3d(int n1, int n2, int n3, double ***a); + double errorcheck3d(int n1, int n2, int n3, double scale, double ***a); + int *ip, n1, n2, n3, n, nt, i, j; + double ***a, *w, err; + + printf("data length n1=? (n1 = power of 2) \n"); + scanf("%d", &n1); + printf("data length n2=? (n2 = power of 2) \n"); + scanf("%d", &n2); + printf("data length n3=? (n3 = power of 2) \n"); + scanf("%d", &n3); + + a = alloc_3d_double(n1, n2, n3); + nt = MAX(n1, n2); + n = MAX(nt, n3 / 2); + ip = alloc_1d_int(2 + (int) sqrt(n + 0.5)); + n = MAX(nt, n3) * 3 / 2; + w = alloc_1d_double(n); + ip[0] = 0; + + /* check of CDFT */ + putdata3d(n1, n2, n3, a); + cdft3d(n1, n2, n3, 1, a, NULL, ip, w); + cdft3d(n1, n2, n3, -1, a, NULL, ip, w); + err = errorcheck3d(n1, n2, n3, 2.0 / n1 / n2 / n3, a); + printf("cdft3d err= %g \n", err); + + /* check of RDFT */ + putdata3d(n1, n2, n3, a); + rdft3d(n1, n2, n3, 1, a, NULL, ip, w); + rdft3d(n1, n2, n3, -1, a, NULL, ip, w); + err = errorcheck3d(n1, n2, n3, 2.0 / n1 / n2 / n3, a); + printf("rdft3d err= %g \n", err); + + /* check of DDCT */ + putdata3d(n1, n2, n3, a); + ddct3d(n1, n2, n3, 1, a, NULL, ip, w); + ddct3d(n1, n2, n3, -1, a, NULL, ip, w); + for (i = 0; i <= n1 - 1; i++) { + for (j = 0; j <= n2 - 1; j++) { + a[i][j][0] *= 0.5; + } + for (j = 0; j <= n3 - 1; j++) { + a[i][0][j] *= 0.5; + } + } + for (i = 0; i <= n2 - 1; i++) { + for (j = 0; j <= n3 - 1; j++) { + a[0][i][j] *= 0.5; + } + } + err = errorcheck3d(n1, n2, n3, 8.0 / n1 / n2 / n3, a); + printf("ddct3d err= %g \n", err); + + /* check of DDST */ + putdata3d(n1, n2, n3, a); + ddst3d(n1, n2, n3, 1, a, NULL, ip, w); + ddst3d(n1, n2, n3, -1, a, NULL, ip, w); + for (i = 0; i <= n1 - 1; i++) { + for (j = 0; j <= n2 - 1; j++) { + a[i][j][0] *= 0.5; + } + for (j = 0; j <= n3 - 1; j++) { + a[i][0][j] *= 0.5; + } + } + for (i = 0; i <= n2 - 1; i++) { + for (j = 0; j <= n3 - 1; j++) { + a[0][i][j] *= 0.5; + } + } + err = errorcheck3d(n1, n2, n3, 8.0 / n1 / n2 / n3, a); + printf("ddst3d err= %g \n", err); + + free_1d_double(w); + free_1d_int(ip); + free_3d_double(a); + return 0; +} + + +void putdata3d(int n1, int n2, int n3, double ***a) +{ + int j1, j2, j3, seed = 0; + + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + for (j3 = 0; j3 <= n3 - 1; j3++) { + a[j1][j2][j3] = RND(&seed); + } + } + } +} + + +double errorcheck3d(int n1, int n2, int n3, double scale, double ***a) +{ + int j1, j2, j3, seed = 0; + double err = 0, e; + + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + for (j3 = 0; j3 <= n3 - 1; j3++) { + e = RND(&seed) - a[j1][j2][j3] * scale; + err = MAX(err, fabs(e)); + } + } + } + return err; +} +
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg3dt.f b/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg3dt.f new file mode 100644 index 0000000..bbada0d --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/fftsg3dt.f
@@ -0,0 +1,119 @@ +! test of fftsg3d.f +! + program main + integer nmax, nmaxsqrt + parameter (nmax = 128) + parameter (nmaxsqrt = 16) + integer ip(0 : nmaxsqrt + 1), n1, n2, n3, i, j + real*8 a(0 : nmax - 1, 0 : nmax - 1, 0 : nmax - 1), + & t(0 : 8 * nmax - 1), + & w(0 : nmax * 3 / 2 - 1), err, errorcheck3d +! + write (*, *) 'data length n1=? (n1 = power of 2) ' + read (*, *) n1 + write (*, *) 'data length n2=? (n2 = power of 2) ' + read (*, *) n2 + write (*, *) 'data length n3=? (n3 = power of 2) ' + read (*, *) n3 + ip(0) = 0 +! +! check of CDFT + call putdata3d(nmax, nmax, n1, n2, n3, a) + call cdft3d(nmax, nmax, n1, n2, n3, 1, a, t, ip, w) + call cdft3d(nmax, nmax, n1, n2, n3, -1, a, t, ip, w) + err = errorcheck3d(nmax, nmax, n1, n2, n3, + & 2.0d0 / n1 / n2 / n3, a) + write (*, *) 'cdft3d err= ', err +! +! check of RDFT + call putdata3d(nmax, nmax, n1, n2, n3, a) + call rdft3d(nmax, nmax, n1, n2, n3, 1, a, t, ip, w) + call rdft3d(nmax, nmax, n1, n2, n3, -1, a, t, ip, w) + err = errorcheck3d(nmax, nmax, n1, n2, n3, + & 2.0d0 / n1 / n2 / n3, a) + write (*, *) 'rdft3d err= ', err +! +! check of DDCT + call putdata3d(nmax, nmax, n1, n2, n3, a) + call ddct3d(nmax, nmax, n1, n2, n3, 1, a, t, ip, w) + call ddct3d(nmax, nmax, n1, n2, n3, -1, a, t, ip, w) + do j = 0, n2 - 1 + do i = 0, n1 - 1 + a(i, j, 0) = a(i, j, 0) * 0.5d0 + end do + end do + do j = 0, n3 - 1 + do i = 0, n1 - 1 + a(i, 0, j) = a(i, 0, j) * 0.5d0 + end do + do i = 0, n2 - 1 + a(0, i, j) = a(0, i, j) * 0.5d0 + end do + end do + err = errorcheck3d(nmax, nmax, n1, n2, n3, + & 8.0d0 / n1 / n2 / n3, a) + write (*, *) 'ddct3d err= ', err +! +! check of DDST + call putdata3d(nmax, nmax, n1, n2, n3, a) + call ddst3d(nmax, nmax, n1, n2, n3, 1, a, t, ip, w) + call ddst3d(nmax, nmax, n1, n2, n3, -1, a, t, ip, w) + do j = 0, n2 - 1 + do i = 0, n1 - 1 + a(i, j, 0) = a(i, j, 0) * 0.5d0 + end do + end do + do j = 0, n3 - 1 + do i = 0, n1 - 1 + a(i, 0, j) = a(i, 0, j) * 0.5d0 + end do + do i = 0, n2 - 1 + a(0, i, j) = a(0, i, j) * 0.5d0 + end do + end do + err = errorcheck3d(nmax, nmax, n1, n2, n3, + & 8.0d0 / n1 / n2 / n3, a) + write (*, *) 'ddst3d err= ', err +! + end +! +! + subroutine putdata3d(n1max, n2max, n1, n2, n3, a) + integer n1max, n2max, n1, n2, n3, j1, j2, j3, seed + real*8 a(0 : n1max - 1, 0 : n2max - 1, 0 : *), drnd + seed = 0 + do j3 = 0, n3 - 1 + do j2 = 0, n2 - 1 + do j1 = 0, n1 - 1 + a(j1, j2, j3) = drnd(seed) + end do + end do + end do + end +! +! + function errorcheck3d(n1max, n2max, n1, n2, n3, scale, a) + integer n1max, n2max, n1, n2, n3, j1, j2, j3, seed + real*8 scale, a(0 : n1max - 1, 0 : n2max - 1, 0 : *), + & drnd, err, e, errorcheck3d + err = 0 + seed = 0 + do j3 = 0, n3 - 1 + do j2 = 0, n2 - 1 + do j1 = 0, n1 - 1 + e = drnd(seed) - a(j1, j2, j3) * scale + err = max(err, abs(e)) + end do + end do + end do + errorcheck3d = err + end +! +! +! random number generator, 0 <= drnd < 1 + real*8 function drnd(seed) + integer seed + seed = mod(seed * 7141 + 54773, 259200) + drnd = seed * (1.0d0 / 259200) + end +!
diff --git a/third_party/tensorflow_dependencies/fft2d/sample2d/shrtdctt.c b/third_party/tensorflow_dependencies/fft2d/sample2d/shrtdctt.c new file mode 100644 index 0000000..70d665f --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/sample2d/shrtdctt.c
@@ -0,0 +1,68 @@ +/* test of shrtdct.c */ + +#include <math.h> +#include <stdio.h> +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +/* random number generator, 0 <= RND < 1 */ +#define RND(p) ((*(p) = (*(p) * 7141 + 54773) % 259200) * (1.0 / 259200)) + +#define NMAX 16 + +int main() +{ + void ddct8x8s(int isgn, double **a); + void ddct16x16s(int isgn, double **a); + void putdata2d(int n1, int n2, double **a); + double errorcheck2d(int n1, int n2, double scale, double **a); + double err; + + int i; + double aarr[NMAX][NMAX], *a[NMAX], barr[NMAX][NMAX], *b[NMAX]; + for (i = 0; i < NMAX; i++) a[i] = aarr[i]; + for (i = 0; i < NMAX; i++) b[i] = barr[i]; + + /* check of 8x8 DCT */ + putdata2d(8, 8, a); + ddct8x8s(-1, a); + ddct8x8s(1, a); + err = errorcheck2d(8, 8, 1.0, a); + printf("ddct8x8s err= %g\n", err); + + /* check of 16x16 DCT */ + putdata2d(16, 16, a); + ddct16x16s(-1, a); + ddct16x16s(1, a); + err = errorcheck2d(16, 16, 1.0, a); + printf("ddct16x16s err= %g\n", err); + + return 0; +} + + +void putdata2d(int n1, int n2, double **a) +{ + int j1, j2, seed = 0; + + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + a[j1][j2] = RND(&seed); + } + } +} + + +double errorcheck2d(int n1, int n2, double scale, double **a) +{ + int j1, j2, seed = 0; + double err = 0, e; + + for (j1 = 0; j1 <= n1 - 1; j1++) { + for (j2 = 0; j2 <= n2 - 1; j2++) { + e = RND(&seed) - a[j1][j2] * scale; + err = MAX(err, fabs(e)); + } + } + return err; +} +
diff --git a/third_party/tensorflow_dependencies/fft2d/shrtdct.c b/third_party/tensorflow_dependencies/fft2d/shrtdct.c new file mode 100644 index 0000000..455cb4c --- /dev/null +++ b/third_party/tensorflow_dependencies/fft2d/shrtdct.c
@@ -0,0 +1,538 @@ +/* +Short Discrete Cosine Transform + data length :8x8, 16x16 + method :row-column, radix 4 FFT +functions + ddct8x8s : 8x8 DCT + ddct16x16s: 16x16 DCT +function prototypes + void ddct8x8s(int isgn, double **a); + void ddct16x16s(int isgn, double **a); +*/ + + +/* +-------- 8x8 DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + <case1> Normalized 8x8 IDCT + C[k1][k2] = (1/4) * sum_j1=0^7 sum_j2=0^7 + a[j1][j2] * s[j1] * s[j2] * + cos(pi*j1*(k1+1/2)/8) * + cos(pi*j2*(k2+1/2)/8), 0<=k1<8, 0<=k2<8 + (s[0] = 1/sqrt(2), s[j] = 1, j > 0) + <case2> Normalized 8x8 DCT + C[k1][k2] = (1/4) * s[k1] * s[k2] * sum_j1=0^7 sum_j2=0^7 + a[j1][j2] * + cos(pi*(j1+1/2)*k1/8) * + cos(pi*(j2+1/2)*k2/8), 0<=k1<8, 0<=k2<8 + (s[0] = 1/sqrt(2), s[j] = 1, j > 0) + [usage] + <case1> + ddct8x8s(1, a); + <case2> + ddct8x8s(-1, a); + [parameters] + a[0...7][0...7] :input/output data (double **) + output data + a[k1][k2] = C[k1][k2], 0<=k1<8, 0<=k2<8 +*/ + + +/* Cn_kR = sqrt(2.0/n) * cos(pi/2*k/n) */ +/* Cn_kI = sqrt(2.0/n) * sin(pi/2*k/n) */ +/* Wn_kR = cos(pi/2*k/n) */ +/* Wn_kI = sin(pi/2*k/n) */ +#define C8_1R 0.49039264020161522456 +#define C8_1I 0.09754516100806413392 +#define C8_2R 0.46193976625564337806 +#define C8_2I 0.19134171618254488586 +#define C8_3R 0.41573480615127261854 +#define C8_3I 0.27778511650980111237 +#define C8_4R 0.35355339059327376220 +#define W8_4R 0.70710678118654752440 + + +void ddct8x8s(int isgn, double **a) +{ + int j; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + double xr, xi; + + if (isgn < 0) { + for (j = 0; j <= 7; j++) { + x0r = a[0][j] + a[7][j]; + x1r = a[0][j] - a[7][j]; + x0i = a[2][j] + a[5][j]; + x1i = a[2][j] - a[5][j]; + x2r = a[4][j] + a[3][j]; + x3r = a[4][j] - a[3][j]; + x2i = a[6][j] + a[1][j]; + x3i = a[6][j] - a[1][j]; + xr = x0r + x2r; + xi = x0i + x2i; + a[0][j] = C8_4R * (xr + xi); + a[4][j] = C8_4R * (xr - xi); + xr = x0r - x2r; + xi = x0i - x2i; + a[2][j] = C8_2R * xr - C8_2I * xi; + a[6][j] = C8_2R * xi + C8_2I * xr; + xr = W8_4R * (x1i - x3i); + x1i = W8_4R * (x1i + x3i); + x3i = x1i - x3r; + x1i += x3r; + x3r = x1r - xr; + x1r += xr; + a[1][j] = C8_1R * x1r - C8_1I * x1i; + a[7][j] = C8_1R * x1i + C8_1I * x1r; + a[3][j] = C8_3R * x3r - C8_3I * x3i; + a[5][j] = C8_3R * x3i + C8_3I * x3r; + } + for (j = 0; j <= 7; j++) { + x0r = a[j][0] + a[j][7]; + x1r = a[j][0] - a[j][7]; + x0i = a[j][2] + a[j][5]; + x1i = a[j][2] - a[j][5]; + x2r = a[j][4] + a[j][3]; + x3r = a[j][4] - a[j][3]; + x2i = a[j][6] + a[j][1]; + x3i = a[j][6] - a[j][1]; + xr = x0r + x2r; + xi = x0i + x2i; + a[j][0] = C8_4R * (xr + xi); + a[j][4] = C8_4R * (xr - xi); + xr = x0r - x2r; + xi = x0i - x2i; + a[j][2] = C8_2R * xr - C8_2I * xi; + a[j][6] = C8_2R * xi + C8_2I * xr; + xr = W8_4R * (x1i - x3i); + x1i = W8_4R * (x1i + x3i); + x3i = x1i - x3r; + x1i += x3r; + x3r = x1r - xr; + x1r += xr; + a[j][1] = C8_1R * x1r - C8_1I * x1i; + a[j][7] = C8_1R * x1i + C8_1I * x1r; + a[j][3] = C8_3R * x3r - C8_3I * x3i; + a[j][5] = C8_3R * x3i + C8_3I * x3r; + } + } else { + for (j = 0; j <= 7; j++) { + x1r = C8_1R * a[1][j] + C8_1I * a[7][j]; + x1i = C8_1R * a[7][j] - C8_1I * a[1][j]; + x3r = C8_3R * a[3][j] + C8_3I * a[5][j]; + x3i = C8_3R * a[5][j] - C8_3I * a[3][j]; + xr = x1r - x3r; + xi = x1i + x3i; + x1r += x3r; + x3i -= x1i; + x1i = W8_4R * (xr + xi); + x3r = W8_4R * (xr - xi); + xr = C8_2R * a[2][j] + C8_2I * a[6][j]; + xi = C8_2R * a[6][j] - C8_2I * a[2][j]; + x0r = C8_4R * (a[0][j] + a[4][j]); + x0i = C8_4R * (a[0][j] - a[4][j]); + x2r = x0r - xr; + x2i = x0i - xi; + x0r += xr; + x0i += xi; + a[0][j] = x0r + x1r; + a[7][j] = x0r - x1r; + a[2][j] = x0i + x1i; + a[5][j] = x0i - x1i; + a[4][j] = x2r - x3i; + a[3][j] = x2r + x3i; + a[6][j] = x2i - x3r; + a[1][j] = x2i + x3r; + } + for (j = 0; j <= 7; j++) { + x1r = C8_1R * a[j][1] + C8_1I * a[j][7]; + x1i = C8_1R * a[j][7] - C8_1I * a[j][1]; + x3r = C8_3R * a[j][3] + C8_3I * a[j][5]; + x3i = C8_3R * a[j][5] - C8_3I * a[j][3]; + xr = x1r - x3r; + xi = x1i + x3i; + x1r += x3r; + x3i -= x1i; + x1i = W8_4R * (xr + xi); + x3r = W8_4R * (xr - xi); + xr = C8_2R * a[j][2] + C8_2I * a[j][6]; + xi = C8_2R * a[j][6] - C8_2I * a[j][2]; + x0r = C8_4R * (a[j][0] + a[j][4]); + x0i = C8_4R * (a[j][0] - a[j][4]); + x2r = x0r - xr; + x2i = x0i - xi; + x0r += xr; + x0i += xi; + a[j][0] = x0r + x1r; + a[j][7] = x0r - x1r; + a[j][2] = x0i + x1i; + a[j][5] = x0i - x1i; + a[j][4] = x2r - x3i; + a[j][3] = x2r + x3i; + a[j][6] = x2i - x3r; + a[j][1] = x2i + x3r; + } + } +} + + + +/* +-------- 16x16 DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + <case1> Normalized 16x16 IDCT + C[k1][k2] = (1/8) * sum_j1=0^15 sum_j2=0^15 + a[j1][j2] * s[j1] * s[j2] * + cos(pi*j1*(k1+1/2)/16) * + cos(pi*j2*(k2+1/2)/16), 0<=k1<16, 0<=k2<16 + (s[0] = 1/sqrt(2), s[j] = 1, j > 0) + <case2> Normalized 16x16 DCT + C[k1][k2] = (1/8) * s[k1] * s[k2] * sum_j1=0^15 sum_j2=0^15 + a[j1][j2] * + cos(pi*(j1+1/2)*k1/16) * + cos(pi*(j2+1/2)*k2/16), 0<=k1<16, 0<=k2<16 + (s[0] = 1/sqrt(2), s[j] = 1, j > 0) + [usage] + <case1> + ddct16x16s(1, a); + <case2> + ddct16x16s(-1, a); + [parameters] + a[0...15][0...15] :input/output data (double **) + output data + a[k1][k2] = C[k1][k2], 0<=k1<16, 0<=k2<16 +*/ + + +/* Cn_kR = sqrt(2.0/n) * cos(pi/2*k/n) */ +/* Cn_kI = sqrt(2.0/n) * sin(pi/2*k/n) */ +/* Wn_kR = cos(pi/2*k/n) */ +/* Wn_kI = sin(pi/2*k/n) */ +#define C16_1R 0.35185093438159561476 +#define C16_1I 0.03465429229977286565 +#define C16_2R 0.34675996133053686546 +#define C16_2I 0.06897484482073575308 +#define C16_3R 0.33832950029358816957 +#define C16_3I 0.10263113188058934529 +#define C16_4R 0.32664074121909413196 +#define C16_4I 0.13529902503654924610 +#define C16_5R 0.31180625324666780814 +#define C16_5I 0.16666391461943662432 +#define C16_6R 0.29396890060483967924 +#define C16_6I 0.19642373959677554532 +#define C16_7R 0.27330046675043937206 +#define C16_7I 0.22429189658565907106 +#define C16_8R 0.25 +#define W16_4R 0.92387953251128675613 +#define W16_4I 0.38268343236508977173 +#define W16_8R 0.70710678118654752440 + + +void ddct16x16s(int isgn, double **a) +{ + int j; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + double x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i; + double xr, xi; + + if (isgn < 0) { + for (j = 0; j <= 15; j++) { + x4r = a[0][j] - a[15][j]; + xr = a[0][j] + a[15][j]; + x4i = a[8][j] - a[7][j]; + xi = a[8][j] + a[7][j]; + x0r = xr + xi; + x0i = xr - xi; + x5r = a[2][j] - a[13][j]; + xr = a[2][j] + a[13][j]; + x5i = a[10][j] - a[5][j]; + xi = a[10][j] + a[5][j]; + x1r = xr + xi; + x1i = xr - xi; + x6r = a[4][j] - a[11][j]; + xr = a[4][j] + a[11][j]; + x6i = a[12][j] - a[3][j]; + xi = a[12][j] + a[3][j]; + x2r = xr + xi; + x2i = xr - xi; + x7r = a[6][j] - a[9][j]; + xr = a[6][j] + a[9][j]; + x7i = a[14][j] - a[1][j]; + xi = a[14][j] + a[1][j]; + x3r = xr + xi; + x3i = xr - xi; + xr = x0r + x2r; + xi = x1r + x3r; + a[0][j] = C16_8R * (xr + xi); + a[8][j] = C16_8R * (xr - xi); + xr = x0r - x2r; + xi = x1r - x3r; + a[4][j] = C16_4R * xr - C16_4I * xi; + a[12][j] = C16_4R * xi + C16_4I * xr; + x0r = W16_8R * (x1i - x3i); + x2r = W16_8R * (x1i + x3i); + xr = x0i + x0r; + xi = x2r + x2i; + a[2][j] = C16_2R * xr - C16_2I * xi; + a[14][j] = C16_2R * xi + C16_2I * xr; + xr = x0i - x0r; + xi = x2r - x2i; + a[6][j] = C16_6R * xr - C16_6I * xi; + a[10][j] = C16_6R * xi + C16_6I * xr; + xr = W16_8R * (x6r - x6i); + xi = W16_8R * (x6i + x6r); + x6r = x4r - xr; + x6i = x4i - xi; + x4r += xr; + x4i += xi; + xr = W16_4I * x7r - W16_4R * x7i; + xi = W16_4I * x7i + W16_4R * x7r; + x7r = W16_4R * x5r - W16_4I * x5i; + x7i = W16_4R * x5i + W16_4I * x5r; + x5r = x7r + xr; + x5i = x7i + xi; + x7r -= xr; + x7i -= xi; + xr = x4r + x5r; + xi = x5i + x4i; + a[1][j] = C16_1R * xr - C16_1I * xi; + a[15][j] = C16_1R * xi + C16_1I * xr; + xr = x4r - x5r; + xi = x5i - x4i; + a[7][j] = C16_7R * xr - C16_7I * xi; + a[9][j] = C16_7R * xi + C16_7I * xr; + xr = x6r - x7i; + xi = x7r + x6i; + a[5][j] = C16_5R * xr - C16_5I * xi; + a[11][j] = C16_5R * xi + C16_5I * xr; + xr = x6r + x7i; + xi = x7r - x6i; + a[3][j] = C16_3R * xr - C16_3I * xi; + a[13][j] = C16_3R * xi + C16_3I * xr; + } + for (j = 0; j <= 15; j++) { + x4r = a[j][0] - a[j][15]; + xr = a[j][0] + a[j][15]; + x4i = a[j][8] - a[j][7]; + xi = a[j][8] + a[j][7]; + x0r = xr + xi; + x0i = xr - xi; + x5r = a[j][2] - a[j][13]; + xr = a[j][2] + a[j][13]; + x5i = a[j][10] - a[j][5]; + xi = a[j][10] + a[j][5]; + x1r = xr + xi; + x1i = xr - xi; + x6r = a[j][4] - a[j][11]; + xr = a[j][4] + a[j][11]; + x6i = a[j][12] - a[j][3]; + xi = a[j][12] + a[j][3]; + x2r = xr + xi; + x2i = xr - xi; + x7r = a[j][6] - a[j][9]; + xr = a[j][6] + a[j][9]; + x7i = a[j][14] - a[j][1]; + xi = a[j][14] + a[j][1]; + x3r = xr + xi; + x3i = xr - xi; + xr = x0r + x2r; + xi = x1r + x3r; + a[j][0] = C16_8R * (xr + xi); + a[j][8] = C16_8R * (xr - xi); + xr = x0r - x2r; + xi = x1r - x3r; + a[j][4] = C16_4R * xr - C16_4I * xi; + a[j][12] = C16_4R * xi + C16_4I * xr; + x0r = W16_8R * (x1i - x3i); + x2r = W16_8R * (x1i + x3i); + xr = x0i + x0r; + xi = x2r + x2i; + a[j][2] = C16_2R * xr - C16_2I * xi; + a[j][14] = C16_2R * xi + C16_2I * xr; + xr = x0i - x0r; + xi = x2r - x2i; + a[j][6] = C16_6R * xr - C16_6I * xi; + a[j][10] = C16_6R * xi + C16_6I * xr; + xr = W16_8R * (x6r - x6i); + xi = W16_8R * (x6i + x6r); + x6r = x4r - xr; + x6i = x4i - xi; + x4r += xr; + x4i += xi; + xr = W16_4I * x7r - W16_4R * x7i; + xi = W16_4I * x7i + W16_4R * x7r; + x7r = W16_4R * x5r - W16_4I * x5i; + x7i = W16_4R * x5i + W16_4I * x5r; + x5r = x7r + xr; + x5i = x7i + xi; + x7r -= xr; + x7i -= xi; + xr = x4r + x5r; + xi = x5i + x4i; + a[j][1] = C16_1R * xr - C16_1I * xi; + a[j][15] = C16_1R * xi + C16_1I * xr; + xr = x4r - x5r; + xi = x5i - x4i; + a[j][7] = C16_7R * xr - C16_7I * xi; + a[j][9] = C16_7R * xi + C16_7I * xr; + xr = x6r - x7i; + xi = x7r + x6i; + a[j][5] = C16_5R * xr - C16_5I * xi; + a[j][11] = C16_5R * xi + C16_5I * xr; + xr = x6r + x7i; + xi = x7r - x6i; + a[j][3] = C16_3R * xr - C16_3I * xi; + a[j][13] = C16_3R * xi + C16_3I * xr; + } + } else { + for (j = 0; j <= 15; j++) { + x5r = C16_1R * a[1][j] + C16_1I * a[15][j]; + x5i = C16_1R * a[15][j] - C16_1I * a[1][j]; + xr = C16_7R * a[7][j] + C16_7I * a[9][j]; + xi = C16_7R * a[9][j] - C16_7I * a[7][j]; + x4r = x5r + xr; + x4i = x5i - xi; + x5r -= xr; + x5i += xi; + x7r = C16_5R * a[5][j] + C16_5I * a[11][j]; + x7i = C16_5R * a[11][j] - C16_5I * a[5][j]; + xr = C16_3R * a[3][j] + C16_3I * a[13][j]; + xi = C16_3R * a[13][j] - C16_3I * a[3][j]; + x6r = x7r + xr; + x6i = x7i - xi; + x7r -= xr; + x7i += xi; + xr = x4r - x6r; + xi = x4i - x6i; + x4r += x6r; + x4i += x6i; + x6r = W16_8R * (xi + xr); + x6i = W16_8R * (xi - xr); + xr = x5r + x7i; + xi = x5i - x7r; + x5r -= x7i; + x5i += x7r; + x7r = W16_4I * x5r + W16_4R * x5i; + x7i = W16_4I * x5i - W16_4R * x5r; + x5r = W16_4R * xr + W16_4I * xi; + x5i = W16_4R * xi - W16_4I * xr; + xr = C16_4R * a[4][j] + C16_4I * a[12][j]; + xi = C16_4R * a[12][j] - C16_4I * a[4][j]; + x2r = C16_8R * (a[0][j] + a[8][j]); + x3r = C16_8R * (a[0][j] - a[8][j]); + x0r = x2r + xr; + x1r = x3r + xi; + x2r -= xr; + x3r -= xi; + x0i = C16_2R * a[2][j] + C16_2I * a[14][j]; + x2i = C16_2R * a[14][j] - C16_2I * a[2][j]; + x1i = C16_6R * a[6][j] + C16_6I * a[10][j]; + x3i = C16_6R * a[10][j] - C16_6I * a[6][j]; + xr = x0i - x1i; + xi = x2i + x3i; + x0i += x1i; + x2i -= x3i; + x1i = W16_8R * (xi + xr); + x3i = W16_8R * (xi - xr); + xr = x0r + x0i; + xi = x0r - x0i; + a[0][j] = xr + x4r; + a[15][j] = xr - x4r; + a[8][j] = xi + x4i; + a[7][j] = xi - x4i; + xr = x1r + x1i; + xi = x1r - x1i; + a[2][j] = xr + x5r; + a[13][j] = xr - x5r; + a[10][j] = xi + x5i; + a[5][j] = xi - x5i; + xr = x2r + x2i; + xi = x2r - x2i; + a[4][j] = xr + x6r; + a[11][j] = xr - x6r; + a[12][j] = xi + x6i; + a[3][j] = xi - x6i; + xr = x3r + x3i; + xi = x3r - x3i; + a[6][j] = xr + x7r; + a[9][j] = xr - x7r; + a[14][j] = xi + x7i; + a[1][j] = xi - x7i; + } + for (j = 0; j <= 15; j++) { + x5r = C16_1R * a[j][1] + C16_1I * a[j][15]; + x5i = C16_1R * a[j][15] - C16_1I * a[j][1]; + xr = C16_7R * a[j][7] + C16_7I * a[j][9]; + xi = C16_7R * a[j][9] - C16_7I * a[j][7]; + x4r = x5r + xr; + x4i = x5i - xi; + x5r -= xr; + x5i += xi; + x7r = C16_5R * a[j][5] + C16_5I * a[j][11]; + x7i = C16_5R * a[j][11] - C16_5I * a[j][5]; + xr = C16_3R * a[j][3] + C16_3I * a[j][13]; + xi = C16_3R * a[j][13] - C16_3I * a[j][3]; + x6r = x7r + xr; + x6i = x7i - xi; + x7r -= xr; + x7i += xi; + xr = x4r - x6r; + xi = x4i - x6i; + x4r += x6r; + x4i += x6i; + x6r = W16_8R * (xi + xr); + x6i = W16_8R * (xi - xr); + xr = x5r + x7i; + xi = x5i - x7r; + x5r -= x7i; + x5i += x7r; + x7r = W16_4I * x5r + W16_4R * x5i; + x7i = W16_4I * x5i - W16_4R * x5r; + x5r = W16_4R * xr + W16_4I * xi; + x5i = W16_4R * xi - W16_4I * xr; + xr = C16_4R * a[j][4] + C16_4I * a[j][12]; + xi = C16_4R * a[j][12] - C16_4I * a[j][4]; + x2r = C16_8R * (a[j][0] + a[j][8]); + x3r = C16_8R * (a[j][0] - a[j][8]); + x0r = x2r + xr; + x1r = x3r + xi; + x2r -= xr; + x3r -= xi; + x0i = C16_2R * a[j][2] + C16_2I * a[j][14]; + x2i = C16_2R * a[j][14] - C16_2I * a[j][2]; + x1i = C16_6R * a[j][6] + C16_6I * a[j][10]; + x3i = C16_6R * a[j][10] - C16_6I * a[j][6]; + xr = x0i - x1i; + xi = x2i + x3i; + x0i += x1i; + x2i -= x3i; + x1i = W16_8R * (xi + xr); + x3i = W16_8R * (xi - xr); + xr = x0r + x0i; + xi = x0r - x0i; + a[j][0] = xr + x4r; + a[j][15] = xr - x4r; + a[j][8] = xi + x4i; + a[j][7] = xi - x4i; + xr = x1r + x1i; + xi = x1r - x1i; + a[j][2] = xr + x5r; + a[j][13] = xr - x5r; + a[j][10] = xi + x5i; + a[j][5] = xi - x5i; + xr = x2r + x2i; + xi = x2r - x2i; + a[j][4] = xr + x6r; + a[j][11] = xr - x6r; + a[j][12] = xi + x6i; + a[j][3] = xi - x6i; + xr = x3r + x3i; + xi = x3r - x3i; + a[j][6] = xr + x7r; + a[j][9] = xr - x7r; + a[j][14] = xi + x7i; + a[j][1] = xi - x7i; + } + } +} +
diff --git a/third_party/tensorflow_dependencies/flatbuffers b/third_party/tensorflow_dependencies/flatbuffers new file mode 160000 index 0000000..6d0aae7 --- /dev/null +++ b/third_party/tensorflow_dependencies/flatbuffers
@@ -0,0 +1 @@ +Subproject commit 6d0aae73cd2ad3f8ee93c952af6b33e99049ad9c
diff --git a/third_party/tensorflow_dependencies/fp16 b/third_party/tensorflow_dependencies/fp16 new file mode 160000 index 0000000..4dfe081 --- /dev/null +++ b/third_party/tensorflow_dependencies/fp16
@@ -0,0 +1 @@ +Subproject commit 4dfe081cf6bcd15db339cf2680b9281b8451eeb3
diff --git a/third_party/tensorflow_dependencies/gemmlowp b/third_party/tensorflow_dependencies/gemmlowp new file mode 160000 index 0000000..fda83bd --- /dev/null +++ b/third_party/tensorflow_dependencies/gemmlowp
@@ -0,0 +1 @@ +Subproject commit fda83bdc38b118cc6b56753bd540caa49e570745
diff --git a/third_party/tensorflow_dependencies/neon_2_sse b/third_party/tensorflow_dependencies/neon_2_sse new file mode 160000 index 0000000..42b2beb --- /dev/null +++ b/third_party/tensorflow_dependencies/neon_2_sse
@@ -0,0 +1 @@ +Subproject commit 42b2bebacee25452e150095ef4480b3fa26e30f5
diff --git a/third_party/tensorflow_dependencies/ruy b/third_party/tensorflow_dependencies/ruy new file mode 160000 index 0000000..bebf022 --- /dev/null +++ b/third_party/tensorflow_dependencies/ruy
@@ -0,0 +1 @@ +Subproject commit bebf022784e9b22277b84373c9877aebff8411a7
diff --git a/tools/convexhull_framework/README.TXT b/tools/convexhull_framework/README.TXT new file mode 100644 index 0000000..22e1314 --- /dev/null +++ b/tools/convexhull_framework/README.TXT
@@ -0,0 +1,167 @@ +This testing framework is initial developed by Intel for convex hull study. +It is contributed to Alliance of Open Media for convex hull study and future AV2 +Common Test Condition (CTC) testing. + +For questions and technical support, please contact ryan.lei@intel.com or +maggie.sun@intel.com + +This readme file provides a simple introduction of the framework and steps to +use it for different studies. + +Prerequisites +1. Inside ./bin folder, make sure you have executables for all external tools, + such as vmafossexec, ffmpeg, HDRMetrics, encoder, decoder, etc. You can get + the pre-build binary or source code for the following tools that are needed: + ffmpeg: https://ffmpeg.org/download.html + vmaf tools: https://github.com/Netflix/vmaf + HDRMetrics: https://gitlab.com/standards/HDRTools + libaom AV1 encoder/decoder: https://aomedia.googlesource.com/aom/ + SVT HEVC encoder: https://github.com/OpenVisualCloud/SVT-HEVC + SVT AV1 encoder: https://github.com/OpenVisualCloud/SVT-AV1 + Please always follow the manual of these tools to update the command + parameters used in the script + +2. VMAF requires a model file to run. currently, vmaf_v0.6.1 model files + (vmaf_v0.6.1.pkl.model, vmaf_v0.6.1.pkl) are used and stored under the ./bin + folder. + +3. HDRMetrics requires a template config file (HDRMetricsYUV420_template.cfg). + It is also located under the ./bin folder. Test framework will generate + individual config file based on this template. + +4. VBA macro binary file (vbaProject-AV2.bin) for bdrate calculation is also + stored under ./bin folder, which is needed for BDRATE calculation inside the + excel file. + +5. Test framework is implemented in python 3. It requires few extra python + packages, such as xlrd, xlsxwriter, argparse, etc. + +Things you need to update inside ./src/Config.py to configure the test. +1. Update the Clips table following the existing example to provide the list of + video sequences that you want to test. The first value is the yuv file name + without .yuv suffix. All test video sequences should be in the folder + specified by ContentPath. Test framework will extract the string before the + first "_" as the short name to identify the test sequence and use that to + generate file name of other intermediate files, so please make sure the short + name of the test sequence is unique. Currently only 8 bit yuv sequences in + yuv420p format are supported. + +2. Update FrameNum to specify number of frames you want to process. + +3. Update DnScaleRatio list to provide the list of downscaling ratios. + +4. Update DnScalingAlgos and UpScalingAlgos list to specify downscaling/upscaling + filter types that you want to test. The name of the filter types is that + supported by ffmpeg. The size of these two lists must be the same. Filter + types for downscaling and upscaling can be different. + +5. Update QPs list to specify the list of QPs you want to test for different + codecs. QPs must be in the valid QP range for different coding standards. + For example, [0, 51] for hevc and [0, 63] for AV1 + +6. Update QualityEvalMethods to specify tools you want to use to calculate + quality metrics in the QualityList. Currently, only VMAF and HDRTools are + supported. You also need to update QualityList and QualityEvalMethods to + specify what quality metrics you want to calculate. Test framework will filter + out other metrics and only report the metrics that are specified. + +7. Update LogCmdOnly flag. When it is set to True, the test framework will only + capture all process command sequences into a log file (under ./test/testLogs + folder with time stamp) without actually running it on your system. This + feature is to support the use case in which actual processing tasks need to + distributed on to a server cluster and executed in parallel. + +8. Update SMOKE_TEST flag, It is used for sanity check purpose, in which only + few frames are processed to reduce the test time. + +Command lines for running the tests: +below is the full command line options in help message: + -h, --help show this help message and exit + -f, --function function to run: clean, scaling, sumscaling, + encode, convexhull, summary + -k, --KeepUpscaleOutput [0|1] in function clean, if keep upscaled yuv + files. It is false by default + -s, --SaveMemory [0|1] save memory mode will delete most files in + intermediate steps and keeps only necessary ones + for RD calculation. It is false by default + -l, --LoggingLevel logging level: 0:No Logging, 1: Critical, 2: Error, + 3:Warning, 4: Info, 5: Debug + -c, --CodecName CodecName: av1 or hevc + -m, --EncodeMethod EncodeMethod: ffmpeg, aom, svt + -p, --EncodePreset EncodePreset: medium, slow, fast, etc for ffmpeg, + 0,1,2... for aom and svt + +Sample command for typical operations: +1. python ConvexHullTest.py -f clean + This command will clean up all intermediate files under ./test folder + +2. python ConvexHullTest.py -f scaling + This command will run the standalone downscaling and upscaling tests. + Downscaled YUV files are stored under + ./test/downscaledYUVs folder. Upscaled YUV files are stored under + ./test/upscaledYUVs folder. Quality metrics log files are stored under + ./test/qualityLogs folder. Other processing logs and command logs are stored + under ./test/testLogs folder. In case HDRMetric is used, individual config + files are generated and stored under ./test/configFiles folder. All + intermediate file names indicate the input, output resolution and filter types + that are used. + +3. python ConvexHullTest.py -f sumscaling + This command will summarize the quality metrics for the scaling test into + excel files under ./analysis/scalingresult folder. There are excel files for + each individual test sequence and also excel file that summarizes quality + result for all test sequences based on classes. + +4. python ConvexHullTest.py -f encode -c hevc -m ffmpeg -p medium + This command will run the encoding test. It actually contains downscale + (optional), encode, decode, upscale, quality metrics steps. Different + encoding method and codec name can be specified. For a particular encoder, + encoding preset should also be specified. Downscale step will be skipped if + downscaled yuv files already generated in ./test/downscaledYUVs. Encoded + bitstreams are stored under ./test/bitstreams folder. Decoded YUV files are + stored under ./test/decodedYUVs folder. Decoded and then upscaled YUV files + are stored under ./test/decUpscaledYUVs folder. Quality logs are stored under + ./test/qualityLogs folder. + +5. python ConvexHullTest.py -f convexhull -c hevc -m ffmpeg -p medium + This command will summarize the per sequence quality result based on + different scaling ratios and scaling filter types. + Please make sure the same encoding method/codec name/preset are used as the + previous steps. Output excel files are stored under ./analysis/rdresult + folder. For each sequence and downscaling/upscaling filter type, an excel + sheet is generated that contains the bitrate and quality metric for different + downscaled resolutions. Rate distortion curve for all quality metrics will + be drawn in a scatter plot. Convex hull will be calculated and draw on top + of the rate distortion curve. + In this step, a summary excel file is also generated, which include the + convex hull rate distortion points for all test content and downscaling and + upscaling algorithm pair. This excel file is needed when you want to + calculate bdrate between two encoding runs to evaluate the quality impact on + overall convex hull from a coding tool. + +6. python ConvexHullTest.py -f summary -c hevc -m ffmpeg -p medium + This command will summarize the quality metrics across all test sequences + into an excel file stored under the ./analysis/summary folder. BDRATE between + different resolutions will be calculated. Average result based on content + classes will be calculated. + +In order to calculate BDRATE between convex hull from two encoding test runs +with different codec or different encoding preset, ./src/ConvexHullBDRate.py +script is needed. Command line options for this script is as following: + +usage: ConvexHullBDRate.py [options] + +optional arguments: + -h, --help show this help message and exit + -i1 , --input1 convex hull summary excel file for base mode + -i2 , --input2 convex hull summary excel file for target mode + -o , --output output excel file with BDRATE for base and target modes + +To use this script, the convex hull summary excel files for base and target +modes are needed. Script will parse the rate distortion data from the convex hull +for each individual test content, then it will use the bdrate macro to calculate +the bdrate between two convex hulls. + +a sample command is: +python ConvexHullBDRate.py -i1 ConvexHullRD_ffmpeg_hevc_medium.xlsx +-i2 ConvexHullRD_ffmpeg_hevc_veryslow.xlsx -o ConvexHullBDRate.xlsm
diff --git a/tools/convexhull_framework/bin/HDRMetricsYUV420_template.cfg b/tools/convexhull_framework/bin/HDRMetricsYUV420_template.cfg new file mode 100644 index 0000000..3a21c63 --- /dev/null +++ b/tools/convexhull_framework/bin/HDRMetricsYUV420_template.cfg
@@ -0,0 +1,99 @@ +# HDRMetrics default configuration file +# format: parameter=value or parameter="stringvalue", no SPACES! + +############################################################################### +# +# Input file information +# +############################################################################### +Input0File="" # 1st Input file name +Input1File="" # 2nd Input file name +LogFile="" # Output Log file name +NumberOfFrames=10 # Number of frames to process +SilentMode=0 # Enable Silent mode +MaxSampleValue=10000.0 # Maximum sample value for floating point (openEXR) data files +############################################################################### +# +# Metrics +# +############################################################################### +EnableMSSSIM=1 # Enable MSSSIM computation +EnableSSIM=1 # Enable SSIM computation + +############################################################################### +# +# First input parameters +# +############################################################################### +Input0Width=1280 # 1st Input source width +Input0Height=720 # 1st Input source height +Input0ChromaFormat=1 # 1st Input Chroma Format + # 0 : 400 + # 1 : 420 + # 2 : 422 + # 3 : 444 +Input0Interleaved=0 # 1st Input Interleaved Source +Input0FourCCCode=0 # 1st Input Pixel Format + # 0: UYVY + # 1: YUY2 + # 2: YUYV + # 3: YVYU + # 4: BGR + # 5: V210 + # 6: Y444I +Input0BitDepthCmp0=8 # 1st Input Bitdepth Cmp0 +Input0BitDepthCmp1=8 # 1st Input Bitdepth Cmp1 +Input0BitDepthCmp2=8 # 1st Input Bitdepth Cmp2 +Input0ColorSpace=0 # 1st Input Color Space + # 0: YUV + # 1: RGB + # 2: XYZ +Input0ColorPrimaries=0 # 1st Input Color Primaries + # 0: BT.709 + # 1: BT.2020 + # 2: P3D60 + # 3: P3D65 + # 4: None +Input0FileHeader=0 # 1st Input Header (bytes) +Input0StartFrame=0 # 1st Input Start Frame +Input0FrameSkip=0 # 1st Input Frame Skipping +Input0Rate=24.0 # 1st Input Frame Rate + +############################################################################### +# +# Second input source parameters +# +############################################################################### +Input1Width=1280 # 2nd Input source width +Input1Height=720 # 2nd Input source height +Input1ChromaFormat=1 # 2nd Input Chroma Format + # 0 : 400 + # 1 : 420 + # 2 : 422 + # 3 : 444 +Input1Interleaved=0 # 2nd Input Interleaved Source +Input1FourCCCode=0 # 2nd Input Pixel Format + # 0: UYVY + # 1: YUY2 + # 2: YUYV + # 3: YVYU + # 4: BGR + # 5: V210 + # 6: Y444I +Input1BitDepthCmp0=8 # 2nd Input Bitdepth Cmp0 +Input1BitDepthCmp1=8 # 2nd Input Bitdepth Cmp1 +Input1BitDepthCmp2=8 # 2nd Input Bitdepth Cmp2 +Input1ColorSpace=0 # 2nd Input Color Space + # 0: YUV + # 1: RGB + # 2: XYZ +Input1ColorPrimaries=0 # 2nd Input Color Primaries + # 0: BT.709 + # 1: BT.2020 + # 2: P3D60 + # 3: P3D65 + # 4: None +Input1FileHeader=0 # 2nd Input Header (bytes) +Input1StartFrame=0 # 2nd Input Start Frame +Input1FrameSkip=0 # 2nd Input Frame Skipping +Input0Rate=24.0 # 2nd Input Frame Rate
diff --git a/tools/convexhull_framework/bin/vbaProject-AV2.bin b/tools/convexhull_framework/bin/vbaProject-AV2.bin new file mode 100644 index 0000000..a9df27b --- /dev/null +++ b/tools/convexhull_framework/bin/vbaProject-AV2.bin Binary files differ
diff --git a/tools/convexhull_framework/bin/vbaProject_JVET-L0242.bin b/tools/convexhull_framework/bin/vbaProject_JVET-L0242.bin new file mode 100644 index 0000000..0154878 --- /dev/null +++ b/tools/convexhull_framework/bin/vbaProject_JVET-L0242.bin Binary files differ
diff --git a/tools/convexhull_framework/bin/vmaf_v0.6.1.pkl b/tools/convexhull_framework/bin/vmaf_v0.6.1.pkl new file mode 100644 index 0000000..59b880f --- /dev/null +++ b/tools/convexhull_framework/bin/vmaf_v0.6.1.pkl
@@ -0,0 +1,108 @@ +(dp0 +S'param_dict' +p1 +(dp2 +S'C' +p3 +F4.0 +sS'score_transform' +p4 +(dp5 +S'p2' +p6 +F-0.00705305 +sS'out_gte_in' +p7 +S'true' +p8 +sS'p0' +p9 +F1.70674692 +sS'p1' +p10 +F1.72643844 +ssS'norm_type' +p11 +S'clip_0to1' +p12 +sS'score_clip' +p13 +(lp14 +F0.0 +aF100.0 +asS'nu' +p15 +F0.9 +sS'gamma' +p16 +F0.04 +ssS'model_dict' +p17 +(dp18 +S'model' +p19 +Nsg4 +g5 +sg11 +S'linear_rescale' +p20 +sg13 +g14 +sS'feature_names' +p21 +(lp22 +S'VMAF_feature_adm2_score' +p23 +aS'VMAF_feature_motion2_score' +p24 +aS'VMAF_feature_vif_scale0_score' +p25 +aS'VMAF_feature_vif_scale1_score' +p26 +aS'VMAF_feature_vif_scale2_score' +p27 +aS'VMAF_feature_vif_scale3_score' +p28 +asS'intercepts' +p29 +(lp30 +F-0.3092981927591963 +aF-1.7993968597186747 +aF-0.003017198086831897 +aF-0.1728125095425364 +aF-0.5294309090081222 +aF-0.7577185792093722 +aF-1.083428597549764 +asS'model_type' +p31 +S'LIBSVMNUSVR' +p32 +sS'slopes' +p33 +(lp34 +F0.012020766332648465 +aF2.8098077502505414 +aF0.06264407466686016 +aF1.222763456258933 +aF1.5360318811084146 +aF1.7620864995501058 +aF2.08656468286432 +asS'feature_dict' +p35 +(dp36 +S'VMAF_feature' +p37 +(lp38 +S'vif_scale0' +p39 +aS'vif_scale1' +p40 +aS'vif_scale2' +p41 +aS'vif_scale3' +p42 +aS'adm2' +p43 +aS'motion2' +p44 +asss. \ No newline at end of file
diff --git a/tools/convexhull_framework/bin/vmaf_v0.6.1.pkl.model b/tools/convexhull_framework/bin/vmaf_v0.6.1.pkl.model new file mode 100644 index 0000000..25c4a4b --- /dev/null +++ b/tools/convexhull_framework/bin/vmaf_v0.6.1.pkl.model
@@ -0,0 +1,218 @@ +svm_type nu_svr +kernel_type rbf +gamma 0.04 +nr_class 2 +total_sv 211 +rho -1.33133 +SV +-4 1:0.65734273 2:0.34681232 3:0.093755557 4:0.60913934 5:0.69117362 6:0.73495824 +4 1:0.8727433 2:0.49612229 3:0.59146724 4:0.78105663 5:0.84916292 6:0.8882561 +4 1:0.89890005 2:0.49612229 3:0.66823667 4:0.86050887 5:0.90873162 6:0.93335071 +4 1:0.20371751 2:0.49612229 3:0.10534315 4:-1.110223e-16 6:2.220446e-16 +4 1:0.33913836 2:0.49612229 3:0.14024497 4:0.074708413 5:0.10231651 6:0.1259153 +4 1:0.66426757 2:0.49612229 3:0.35268026 4:0.4805681 5:0.59603341 6:0.67408692 +4 1:0.59561632 2:0.49612229 3:0.27561601 4:0.33977371 5:0.4325213 6:0.50244952 +4 1:0.50821444 2:0.49612229 3:0.20276685 4:0.2004308 5:0.25758651 6:0.30054029 +4 1:0.77877298 2:0.49612229 3:0.444392 4:0.61630491 5:0.71210086 6:0.77386496 +4 1:0.71666017 2:0.49612229 3:0.35967401 4:0.47825205 5:0.57045236 6:0.63752441 +4 1:0.64025669 2:0.49612229 3:0.27766156 4:0.33407105 5:0.40732401 6:0.46359154 +4 1:0.88343983 2:0.23066177 3:0.65873851 4:0.86090402 5:0.90661213 6:0.93008753 +4 1:0.90822691 2:0.23066177 3:0.71439481 4:0.90904598 5:0.94146542 6:0.95674338 +-4 1:0.49037399 2:0.23066177 3:0.32329421 4:0.33686197 5:0.39456977 6:0.44944683 +-4 1:0.69044383 2:0.23066177 3:0.43933868 4:0.56327049 5:0.65339511 6:0.71348696 +-4 1:0.62390093 2:0.23066177 3:0.3800888 4:0.44927578 5:0.52327759 6:0.57907725 +4 1:0.81887942 2:0.23066177 3:0.56208506 4:0.76164281 5:0.83176644 6:0.86914911 +4 1:0.77189471 2:0.23066177 3:0.50145055 4:0.66525882 5:0.74327951 6:0.79017822 +4 1:0.71405433 2:0.23066177 3:0.43952897 4:0.55736023 5:0.63319876 6:0.68402869 +4 1:0.92114073 3:0.45198963 4:0.97703695 5:0.9907273 6:0.99510256 +4 1:1 3:0.83319067 4:0.98956086 5:0.99577089 6:0.99784595 +4 4:0.10344019 5:0.34323945 6:0.63855969 +4 1:0.19531482 3:0.034330388 4:0.25480402 5:0.54197045 6:0.78020579 +4 1:0.48394064 3:0.11866359 4:0.58816959 5:0.86435738 6:0.96191842 +4 1:0.47628079 3:0.11185039 4:0.56180003 5:0.83415721 6:0.93617329 +4 1:0.46278632 3:0.10308547 4:0.52247575 5:0.78583924 6:0.89392193 +4 1:0.7038079 3:0.2174879 4:0.84423613 5:0.9662906 6:0.98430594 +4 1:0.69596686 3:0.20657211 4:0.81196884 5:0.94140702 6:0.96680805 +4 1:0.68404358 3:0.19261438 4:0.76066415 5:0.89973293 6:0.93660362 +4 1:0.84073022 2:0.34681232 3:0.22411304 4:0.88845644 5:0.94169671 6:0.96221395 +-4 1:0.33900937 2:0.34681232 3:0.027607294 4:0.40659646 5:0.45456869 6:0.48256597 +-4 1:0.44593129 2:0.34681232 3:0.041939301 4:0.45284872 5:0.5157613 6:0.55335821 +-4 1:0.67301747 2:0.34681232 3:0.11526222 4:0.68549511 5:0.78556255 6:0.83507583 +-4 1:0.62833533 2:0.34681232 3:0.092281981 4:0.61278125 5:0.70626575 6:0.75613977 +-4 1:0.57196879 2:0.34681232 3:0.067548447 4:0.53383404 5:0.61287548 6:0.65468717 +-0.3312466607741135 1:0.75125028 2:0.34681232 3:0.1457048 4:0.75791308 5:0.84155109 6:0.88132116 +-4 1:0.71121936 2:0.34681232 3:0.12095689 4:0.68834617 5:0.77453583 6:0.81892861 +-4 1:0.80269544 2:0.25207203 3:0.3681723 4:0.80658472 5:0.8702283 6:0.90583519 +-4 1:0.86095387 2:0.25207203 3:0.52475418 4:0.85053413 5:0.90454501 6:0.93093678 +-4 1:0.5008963 2:0.25207203 3:0.2005129 4:0.41516485 5:0.45282017 6:0.47396143 +-4 1:0.56977992 2:0.25207203 3:0.21631076 4:0.45848604 5:0.51102137 6:0.53823055 +-4 1:0.72779828 2:0.25207203 3:0.3051639 4:0.67537297 5:0.75767261 6:0.80327187 +-4 1:0.68848569 2:0.25207203 3:0.27393051 4:0.60399854 5:0.68000038 6:0.72275152 +-4 1:0.64121401 2:0.25207203 3:0.23994344 4:0.52538719 5:0.5891732 6:0.62164073 +-4 1:0.76673633 2:0.25207203 3:0.33053889 4:0.73085549 5:0.80341439 6:0.84546456 +-4 1:0.73041172 2:0.25207203 3:0.29691153 4:0.66166141 5:0.73408074 6:0.77757209 +-4 1:0.68529047 2:0.25207203 3:0.26283557 4:0.58611788 5:0.65192525 6:0.69015011 +4 1:0.86902267 2:0.48885268 3:0.5143645 4:0.8587242 5:0.91841685 6:0.94498293 +4 1:0.89266106 2:0.48885268 3:0.55208861 4:0.89938377 5:0.94642982 6:0.96615102 +-4 1:0.42554844 2:0.48885268 3:0.2554221 4:0.36916892 5:0.43100226 6:0.50888404 +-4 1:0.52520274 2:0.48885268 3:0.27824915 4:0.42915458 5:0.50850476 6:0.58585271 +-4 1:0.69357445 2:0.48885268 3:0.35289928 4:0.61359907 5:0.7217863 6:0.78790011 +-4 1:0.64679648 2:0.48885268 3:0.31268451 4:0.5167094 5:0.61224976 6:0.68477529 +4 1:0.80595874 2:0.48885268 3:0.44075432 4:0.7803455 5:0.86328719 6:0.90222545 +-4 1:0.7715192 2:0.48885268 3:0.4012577 4:0.70792536 5:0.80063653 6:0.85083872 +4 1:0.82199966 2:0.20629643 3:0.30562098 4:0.80541317 5:0.89285836 6:0.92907353 +-4 1:0.84774006 2:0.20629643 3:0.36755712 4:0.8681203 5:0.93297792 6:0.95700049 +4 1:0.26631905 2:0.20629643 3:0.076468978 4:0.29833807 5:0.37989948 6:0.4576277 +-4 1:0.65439648 2:0.20629643 3:0.19487894 4:0.63045155 5:0.76931142 6:0.83706632 +4 1:0.55295603 2:0.20629643 3:0.13877412 4:0.4724047 5:0.59295828 6:0.66834832 +4 1:0.75448924 2:0.20629643 3:0.24707248 4:0.72284103 5:0.83178838 6:0.88053503 +4 1:0.83852041 2:0.15600331 3:0.1625414 4:0.81948421 5:0.90185357 6:0.9347395 +4 1:0.85805266 2:0.15600331 3:0.19693206 4:0.86294641 5:0.92990351 6:0.95498998 +-4 1:0.43384835 2:0.15600331 3:0.030541611 4:0.37279112 5:0.4588284 6:0.52004828 +-4 1:0.72588966 2:0.48885268 3:0.35394597 4:0.61189191 5:0.70897304 6:0.77099691 +-4 1:0.65865915 2:0.20629643 3:0.1796405 4:0.56432133 5:0.68049028 6:0.74616621 +-4 1:0.53095193 2:0.15600331 3:0.046271684 4:0.4328793 5:0.5309142 6:0.59282089 +-4 1:0.71891465 2:0.15600331 3:0.11085278 4:0.68794624 5:0.80350923 6:0.85660483 +-4 1:0.68635753 2:0.15600331 3:0.091457045 4:0.60849701 5:0.72282659 6:0.78137183 +-4 1:0.64162333 2:0.15600331 3:0.068820233 4:0.51732819 5:0.62198733 6:0.67977328 +4 1:0.78395225 2:0.15600331 3:0.13401869 4:0.75274384 5:0.8506531 6:0.89321405 +-4 1:0.75276337 2:0.15600331 3:0.11289462 4:0.67598462 5:0.78117168 6:0.83259364 +-4 1:0.71345342 2:0.15600331 3:0.089218917 4:0.58797907 5:0.69284768 6:0.74971699 +4 1:0.93500967 2:0.08765484 3:0.72226864 4:0.93291747 5:0.960644 6:0.97304054 +4 1:0.95150668 2:0.08765484 3:0.77391346 4:0.95596295 5:0.97544784 6:0.98405871 +-4 1:0.48148634 2:0.08765484 3:0.36628046 4:0.45852823 5:0.56005228 6:0.65708595 +-4 1:0.59853216 2:0.08765484 3:0.42071301 4:0.56376512 5:0.66454599 6:0.741236 +-4 1:0.79297271 2:0.08765484 3:0.5597726 4:0.80653689 5:0.88996341 6:0.92691132 +-4 1:0.76798941 2:0.08765484 3:0.52069978 4:0.74484555 5:0.83431246 6:0.87935204 +-4 1:0.73225133 2:0.08765484 3:0.47011786 4:0.66069877 5:0.75226598 6:0.80539407 +-4 1:0.87240592 2:0.08765484 3:0.62680052 4:0.88208508 5:0.93041565 6:0.9505376 +-4 1:0.84834872 2:0.08765484 3:0.58154998 4:0.82429855 5:0.8858516 6:0.91563291 +-4 1:0.84365382 2:0.93973481 3:0.36718425 4:0.81512123 5:0.88887359 6:0.92320992 +-4 1:0.89242364 2:0.93973481 3:0.41336953 4:0.88038833 5:0.93688884 6:0.95992879 +-4 1:0.31373571 2:0.93973481 3:0.18757116 4:0.34864297 5:0.3777168 6:0.38922611 +-4 1:0.42490775 2:0.93973481 3:0.20295859 4:0.39290035 5:0.43632323 6:0.45871216 +-4 1:0.66865444 2:0.93973481 3:0.28594627 4:0.63969879 5:0.73360583 6:0.78380069 +-4 1:0.62642524 2:0.93973481 3:0.26141889 4:0.56602175 5:0.64775366 6:0.69263211 +-4 1:0.57430455 2:0.93973481 3:0.23537634 4:0.48984694 5:0.55363885 6:0.5853905 +-4 1:0.76178555 2:0.93973481 3:0.32205372 4:0.7176044 5:0.80237787 6:0.84588741 +-4 1:0.72282163 2:0.93973481 3:0.29554025 4:0.64471949 5:0.72634443 6:0.77062686 +-4 1:0.67693861 2:0.93973481 3:0.2669659 4:0.56720118 5:0.63868728 6:0.67673331 +4 1:0.86023804 2:0.49739676 3:0.53966638 4:0.77392585 5:0.84784447 6:0.89031641 +1.296591709971377 1:0.31779385 2:0.49739676 3:0.17094319 4:0.12195679 5:0.13277563 6:0.14165413 +4 1:0.68317784 2:0.49739676 3:0.37192301 4:0.52750491 5:0.62426522 6:0.6929947 +4 1:0.55611181 2:0.49739676 3:0.24752355 4:0.28326524 5:0.33261781 6:0.37104424 +4 1:0.7772257 2:0.49739676 3:0.43832146 4:0.63397606 5:0.7240692 6:0.78367237 +4 1:0.66186286 2:0.49739676 3:0.30599867 4:0.39201262 5:0.45927759 6:0.51239284 +4 1:0.94601776 2:0.04579546 3:0.69472114 4:0.97790884 5:0.9891237 6:0.993277 +4 1:0.98838404 2:0.04579546 3:0.90293444 4:0.99181622 5:0.99642641 6:0.9978864 +4 1:0.30006056 2:0.04579546 3:0.31879 4:0.45852885 5:0.59717781 6:0.71487885 +-4 1:0.44902891 2:0.04579546 3:0.35412414 4:0.55926446 5:0.70175505 6:0.79649177 +-4 1:0.69856222 2:0.04579546 3:0.45989947 4:0.82115248 5:0.92520734 6:0.9594384 +-4 1:0.67730161 2:0.04579546 3:0.44400319 4:0.77920819 5:0.88713866 6:0.92903178 +-4 1:0.64419192 2:0.04579546 3:0.42297435 4:0.72390263 5:0.83364665 6:0.88344569 +-4 1:0.80781899 2:0.04579546 3:0.52334234 4:0.88859427 5:0.94013924 6:0.95946903 +-4 1:0.78080761 2:0.04579546 3:0.499439 4:0.84012074 5:0.90229375 6:0.92936693 +4 1:0.97128596 2:0.014623935 3:0.90135809 4:0.99584619 5:0.9970631 6:0.99757649 +4 1:0.99645027 2:0.014623935 3:1 4:1 5:1 6:1 +-4 1:0.5326065 2:0.014623935 3:0.75468972 4:0.76017077 5:0.83753774 6:0.92265059 +-4 1:0.62757004 2:0.014623935 3:0.77708563 4:0.84258654 5:0.91016348 6:0.95440359 +-4 1:0.79306842 2:0.014623935 3:0.78900741 4:0.90386551 5:0.96905764 6:0.98466408 +-4 1:0.77722867 2:0.014623935 3:0.78701408 4:0.89679281 5:0.96056131 6:0.977629 +-4 1:0.75934622 2:0.014623935 3:0.78422805 4:0.88268036 5:0.94383829 6:0.96596858 +-4 1:0.8878718 2:0.014623935 3:0.81445984 4:0.96615706 5:0.98858241 6:0.99176534 +-4 1:0.88211614 2:0.014623935 3:0.81253935 4:0.95982371 5:0.98309178 6:0.9870796 +4 1:0.83805466 2:0.22767235 3:0.31750162 4:0.85145925 5:0.9121085 6:0.93772147 +4 1:0.86620985 2:0.22767235 3:0.35742938 4:0.89821492 5:0.94339974 6:0.96076173 +4 1:0.39289606 2:0.22767235 3:0.12019254 4:0.3951559 5:0.44657802 6:0.46771549 +4 1:0.48692411 2:0.22767235 3:0.13362033 4:0.43434224 5:0.49900609 6:0.53177669 +4 1:0.69743918 2:0.22767235 3:0.2263303 4:0.68859985 5:0.78706365 6:0.83662428 +4 1:0.65237548 2:0.22767235 3:0.19328493 4:0.60107975 5:0.69684945 6:0.74949279 +4 1:0.59461718 2:0.22767235 3:0.15963705 4:0.51010642 5:0.59283393 6:0.63883591 +4 1:0.77302727 2:0.22767235 3:0.26078021 4:0.76359704 5:0.8470807 6:0.8858359 +4 1:0.72953038 2:0.22767235 3:0.22331233 4:0.67735915 5:0.77029889 6:0.81802539 +4 1:0.87210923 2:0.16787772 3:0.69408521 4:0.91495146 5:0.94890261 6:0.96269344 +-4 1:0.81595959 2:0.08765484 3:0.52947327 4:0.7501341 5:0.82294191 6:0.86264385 +4 1:0.72562415 2:0.49739676 3:0.37130724 4:0.51472366 5:0.59961357 6:0.66258291 +-4 1:0.87135693 2:0.014623935 3:0.80905852 4:0.94637428 5:0.97242826 6:0.97946694 +-4 1:0.48910215 2:0.16787772 3:0.49792761 4:0.59161372 5:0.62979552 6:0.64254584 +-4 1:0.5685964 2:0.16787772 3:0.5149767 4:0.63026581 5:0.67890679 6:0.69964851 +-4 1:0.75935478 2:0.16787772 3:0.60695536 4:0.80906778 5:0.87125816 6:0.89810007 +-4 1:0.71788601 2:0.16787772 3:0.57600091 4:0.75310216 5:0.81471966 6:0.84249923 +-4 1:0.66516668 2:0.16787772 3:0.54473368 4:0.69254626 5:0.74796983 6:0.77177867 +4 1:0.81880869 2:0.16787772 3:0.64309172 4:0.86078024 5:0.90892223 6:0.92908907 +-4 1:0.78054558 2:0.16787772 3:0.60849279 4:0.80724494 5:0.86183239 6:0.88618408 +4 1:0.95353512 2:0.055921852 3:0.61526026 4:0.94655706 5:0.97211195 6:0.98210701 +4 1:0.98368527 2:0.055921852 3:0.7405327 4:0.96928567 5:0.9853799 6:0.99080378 +4 1:0.11318821 2:0.055921852 3:0.1590151 4:0.30536689 5:0.48614515 6:0.64344462 +4 1:0.30298819 2:0.055921852 3:0.19401703 4:0.41679982 5:0.61495039 6:0.74140301 +4 1:0.60614412 2:0.055921852 3:0.31791569 4:0.72365433 5:0.88324129 6:0.93484545 +4 1:0.58738733 2:0.055921852 3:0.29301498 4:0.67070014 5:0.83429953 6:0.89348041 +4 1:0.79496816 2:0.055921852 3:0.42192974 4:0.86711004 5:0.94030868 6:0.96084539 +4 1:0.77749763 2:0.055921852 3:0.38714172 4:0.81340799 5:0.90059649 6:0.93006702 +4 1:0.75215882 2:0.055921852 3:0.34721658 4:0.73960747 5:0.84370247 6:0.88485372 +4 1:0.89732805 2:0.58937038 3:0.58823535 4:0.80035053 5:0.86988422 6:0.90533033 +-4 1:0.9228759 2:0.58937038 3:0.65797705 4:0.87169952 5:0.92200942 6:0.94454256 +4 1:0.19504362 2:0.58937038 3:0.21585801 4:0.1754362 5:0.20844015 6:0.23846443 +4 1:0.34425894 2:0.58937038 3:0.24672569 4:0.24188506 5:0.29544562 6:0.33843061 +4 1:0.66407117 2:0.58937038 3:0.40045124 4:0.55415203 5:0.66628031 6:0.73418465 +4 1:0.60780044 2:0.58937038 3:0.34931828 4:0.4519606 5:0.54893247 6:0.61355219 +4 1:0.53476258 2:0.58937038 3:0.29851601 4:0.34826788 5:0.42168642 6:0.47203603 +4 1:0.79195776 2:0.58937038 3:0.47493233 4:0.66775916 5:0.76196439 6:0.81489875 +4 1:0.7415564 2:0.58937038 3:0.41507439 4:0.56413083 5:0.65815516 6:0.7166999 +4 1:0.82021207 2:1 3:0.37381485 4:0.7891612 5:0.87031145 6:0.90944281 +-3.795805084530972 1:0.85903236 2:1 3:0.43235998 4:0.86707094 5:0.92632217 6:0.95151451 +-4 1:0.25243046 2:1 3:0.084027451 4:0.15537936 5:0.17410072 6:0.17212333 +-4 1:0.35643487 2:1 3:0.10644455 4:0.21484368 5:0.25587544 6:0.27527817 +-4 1:0.57605414 2:1 3:0.19031962 4:0.43030863 5:0.5277316 6:0.59069772 +-4 1:0.49071444 2:1 3:0.14452095 4:0.31406915 5:0.38353445 6:0.42653517 +4 1:0.73255545 2:1 3:0.28883701 4:0.65284485 5:0.75623242 6:0.81297442 +0.4082706381617505 1:0.67015395 2:1 3:0.2367756 4:0.5367057 5:0.64063877 6:0.70451767 +-4 1:0.84450653 2:0.083369236 3:0.57279245 4:0.85249389 5:0.91751611 6:0.94621989 +-4 1:0.39559773 2:0.083369236 3:0.28184137 4:0.37025203 5:0.46733936 6:0.53517338 +-4 1:0.70621493 2:0.083369236 3:0.42718441 4:0.69347659 5:0.81124449 6:0.87136343 +-4 1:0.65615861 2:0.083369236 3:0.37833052 4:0.59301482 5:0.71772587 6:0.7905538 +-4 1:0.58837863 2:0.083369236 3:0.33229353 4:0.48675881 5:0.60141743 6:0.67458413 +-4 1:0.77687144 2:0.083369236 3:0.48094343 4:0.76665994 5:0.86191893 6:0.90760934 +-1.966116876631112 1:0.72849768 2:0.083369236 3:0.42082971 4:0.66591147 5:0.77995959 6:0.84260661 +-3.906831378063804 1:0.66320082 2:0.083369236 3:0.36350305 4:0.54888271 5:0.66506794 6:0.73685112 +4 1:0.84500499 2:0.42532178 3:0.43562507 4:0.80721931 5:0.87934044 6:0.91434143 +4 1:0.8874543 2:0.42532178 3:0.50912639 4:0.87959883 5:0.93223488 6:0.95450335 +4 1:0.31032192 2:0.42532178 3:0.18976794 4:0.30662908 5:0.34637104 6:0.3661022 +4 1:0.41026349 2:0.42532178 3:0.20589097 4:0.35241209 5:0.40358156 6:0.42577381 +4 1:0.67552108 2:0.42532178 3:0.30879992 4:0.60375124 5:0.70097073 6:0.75507206 +4 1:0.62772585 2:0.42532178 3:0.27349745 4:0.5196735 5:0.60339149 6:0.65103342 +4 1:0.5741386 2:0.42532178 3:0.24033766 4:0.43855753 5:0.50243186 6:0.53322825 +4 1:0.7629976 2:0.42532178 3:0.35347476 4:0.69239941 5:0.78245146 6:0.83117443 +4 1:0.71746409 2:0.42532178 3:0.31296983 4:0.60525302 5:0.69243388 6:0.7432587 +-4 1:0.73137955 2:0.16787772 3:0.57222383 4:0.74405775 5:0.79993424 6:0.82484891 +4 1:0.67383121 2:0.58937038 3:0.35481019 4:0.45269287 5:0.53578336 6:0.59116487 +4 1:0.5905971 2:1 3:0.18559792 4:0.41535212 5:0.50422336 6:0.56173557 +4 1:0.66157018 2:0.42532178 3:0.27479904 4:0.51802649 5:0.59270541 6:0.63560969 +-4 1:0.66827754 2:0.54342577 3:0.18169339 4:0.50290989 5:0.59875259 6:0.65332628 +4 1:0.85027066 2:0.20820673 3:0.40997978 4:0.82462749 5:0.89794736 6:0.93142825 +4 1:0.87892054 2:0.20820673 3:0.45891267 4:0.87823329 5:0.93535353 6:0.95883927 +4 1:0.3986268 2:0.20820673 3:0.17753958 4:0.33495583 5:0.39777832 6:0.44399359 +-4 1:0.48997993 2:0.20820673 3:0.20172681 4:0.39715881 5:0.47368229 6:0.52781628 +4 1:0.7022939 2:0.20820673 3:0.31094767 4:0.6676259 5:0.77726116 6:0.83518027 +-4 1:0.65773092 2:0.20820673 3:0.27420721 4:0.57889989 5:0.68485118 6:0.74837036 +0.2951376518668717 1:0.60031736 2:0.20820673 3:0.23419121 4:0.48018865 5:0.57200972 6:0.63197473 +4 1:0.77623676 2:0.20820673 3:0.3510016 4:0.74206651 5:0.83508543 6:0.88101902 +4 1:0.73562396 2:0.20820673 3:0.31004997 4:0.6557112 5:0.75585014 6:0.81164989 +-4 1:0.67923081 2:0.20820673 3:0.26679137 4:0.55816547 5:0.65579282 6:0.71593631 +4 1:0.83968539 2:0.54342577 3:0.32439292 4:0.78747769 5:0.87303614 6:0.91271252 +4 1:0.86656342 2:0.54342577 3:0.37898741 4:0.85252726 5:0.92049615 6:0.94848246 +-4 1:0.42728303 2:0.54342577 3:0.10123262 4:0.31581962 5:0.38571265 6:0.42827036 +-4 1:0.63194526 2:0.54342577 3:0.18169045 4:0.51611903 5:0.62179755 6:0.68216176 +4 1:0.56954706 2:0.54342577 3:0.14271477 4:0.41491191 5:0.50173488 6:0.55220392 +4 1:0.76753176 2:0.54342577 3:0.26295318 4:0.6905031 5:0.79291823 6:0.84469464 +-4 1:0.72348649 2:0.54342577 3:0.22334634 4:0.60145902 5:0.70573225 6:0.76318544 +4 1:0.83584492 2:0.047285912 3:0.53826775 4:0.933335 5:0.95948954 6:0.96870909 +4 1:0.85530855 2:0.047285912 3:0.55323777 4:0.95113339 5:0.97249918 6:0.9795177 +-4 1:0.53835734 2:0.047285912 3:0.41965074 4:0.71632669 5:0.73953043 6:0.73487553 +-4 1:0.59175144 2:0.047285912 3:0.43113594 4:0.74141738 5:0.76929188 6:0.77018949 +-4 1:0.75962366 2:0.047285912 3:0.49613729 4:0.87838146 5:0.91688438 6:0.93150362 +-4 1:0.72043129 2:0.047285912 3:0.47217411 4:0.83138845 5:0.8704229 6:0.88419439 +-4 1:0.67287449 2:0.047285912 3:0.44652268 4:0.77691812 5:0.81043483 6:0.8177009 +-4 1:0.8023177 2:0.047285912 3:0.51559706 4:0.90512389 5:0.93743101 6:0.9492968 +-4 1:0.76751376 2:0.047285912 3:0.49225957 4:0.86357299 5:0.89948127 6:0.91221155 +-4 1:0.72124785 2:0.047285912 3:0.46606653 4:0.81323145 5:0.84847474 6:0.85892657
diff --git a/tools/convexhull_framework/src/CalcQtyWithFfmpeg.py b/tools/convexhull_framework/src/CalcQtyWithFfmpeg.py new file mode 100644 index 0000000..0aa1301 --- /dev/null +++ b/tools/convexhull_framework/src/CalcQtyWithFfmpeg.py
@@ -0,0 +1,76 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os +import re +import logging +from Config import BinPath, LoggerName, LogCmdOnly, FFMPEG +from Utils import GetShortContentName, ExecuteCmd + +subloggername = "CalcQtyMetrics_FFMPEGTool" +loggername = LoggerName + '.' + '%s' % subloggername +logger = logging.getLogger(loggername) + + +FFMPEGMetricsFullList = ['PSNR_Y', 'PSNR_U', 'PSNR_V'] + +def ParseFfmpegLogFile(psnr_log): + floats = len(FFMPEGMetricsFullList) * [0.0] + flog = open(psnr_log, 'r') + cnt = 0 + for line in flog: + cnt += 1 + item = re.findall(r"psnr_y:(\d+\.?\d*)", line) + floats[0] += 0 if len(item) == 0 else float(item[0]) + item = re.findall(r"psnr_u:(\d+\.?\d*)", line) + floats[1] += 0 if len(item) == 0 else float(item[0]) + item = re.findall(r"psnr_v:(\d+\.?\d*)", line) + floats[2] += 0 if len(item) == 0 else float(item[0]) + + floats = [float(i) / cnt for i in floats] + + print_str = "FFMPEG quality metrics: " + for metrics, idx in zip(FFMPEGMetricsFullList, range(len(FFMPEGMetricsFullList))): + print_str += "%s = %2.5f, " % (metrics, floats[idx]) + logger.info(print_str) + + return floats[0:len(FFMPEGMetricsFullList)] + + +def GetFfmpegLogFile(recfile, path): + filename = GetShortContentName(recfile, False) + '_psnr.log' + file = os.path.join(path, filename) + return file + +################################################################################ +##################### Exposed Functions ######################################## +def FFMPEG_CalQualityMetrics(origfile, recfile, num, w, h, logfilePath): + #calculate psnr using ffmpeg filter to get psnr_u and psnr_v + #here we have to pass the psnr_log file name to FFMPEG without the target + #log path first, then copy the result psnr log to the target log path after + #the ffmpeg call. it doesn't work if the full path is directly passed to FFMPEG + psnr_log = GetFfmpegLogFile(recfile, BinPath) + psnr_log = os.path.basename(psnr_log) + args = " -s %dx%d -pix_fmt yuv420p -i %s -s %dx%d -pix_fmt yuv420p -i %s" \ + " -frames:v %d -lavfi psnr=%s -f null -" % \ + (w, h, origfile, w, h, recfile, num, psnr_log) + cmd = FFMPEG + args + ExecuteCmd(cmd, LogCmdOnly) + #move the psnr log to the target log path + target = os.path.join(logfilePath, psnr_log) + cmd = "move %s %s" % (psnr_log, target) + ExecuteCmd(cmd, LogCmdOnly) + +def FFMPEG_GatherQualityMetrics(recfile, logfilePath): + psnr_log = GetFfmpegLogFile(recfile, logfilePath) + results = ParseFfmpegLogFile(psnr_log) + return results
diff --git a/tools/convexhull_framework/src/CalcQtyWithHdrTools.py b/tools/convexhull_framework/src/CalcQtyWithHdrTools.py new file mode 100644 index 0000000..9593c87 --- /dev/null +++ b/tools/convexhull_framework/src/CalcQtyWithHdrTools.py
@@ -0,0 +1,88 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +from shutil import copyfile +import fileinput +import os +import re +from Utils import GetShortContentName, ExecuteCmd +from Config import BinPath, LogCmdOnly, LoggerName, HDRTool +import logging + +subloggername = "HDRToolsRun" +loggername = LoggerName + '.' + '%s' % subloggername +logger = logging.getLogger(loggername) + + +HDRToolsConfigFileTemplate = os.path.join(BinPath, 'HDRMetricsYUV420_template.cfg') +HDRToolsMetricsFullList = ['PSNR_Y', 'PSNR_U', 'PSNR_V', 'MS-SSIM_Y', 'MS-SSIM_U', + 'MS-SSIM_V', 'SSIM_Y', 'SSIM_U', 'SSIM_V'] + +def GenerateCfgFile(orig_file, rec_file, num, w, h, configpath): + filename = GetShortContentName(rec_file, False) + '_hdrtools.cfg' + cfgfile = os.path.join(configpath, filename) + copyfile(HDRToolsConfigFileTemplate, cfgfile) + fp = fileinput.input(cfgfile, inplace=1) + for line in fp: + if 'Input0File=' in line: + line = 'Input0File="%s"\n' % orig_file + if 'Input1File=' in line: + line = 'Input1File="%s"\n' % rec_file + if 'NumberOfFrames=' in line: + line = 'NumberOfFrames=%d\n' % num + if 'Input0Width=' in line: + line = 'Input0Width=%d\n' % w + if 'Input1Width=' in line: + line = 'Input1Width=%d\n' % w + if 'Input0Height=' in line: + line = 'Input0Height=%d\n' % h + if 'Input1Height=' in line: + line = 'Input1Height=%d\n' % h + print(line, end='') + fp.close() + return cfgfile + +def ParseHDRToolLogFile(logfile): + flog = open(logfile, 'r') + pattern = re.compile(r'\d+\.?\d*') + floats = len(HDRToolsMetricsFullList) * [0.0] + for line in flog: + if 'D_Avg' in line: + floats = [float(i) for i in pattern.findall(line)] + break + + print_str = "HDRTools qty metrics: " + for metrics, idx in zip(HDRToolsMetricsFullList, + range(len(HDRToolsMetricsFullList))): + print_str += "%s = %2.5f, " % (metrics, floats[idx]) + logger.info(print_str) + return floats[0:len(HDRToolsMetricsFullList)] + +def GetHDRLogFile(recfile, path): + filename = GetShortContentName(recfile, False) + '_hdrtools.log' + file = os.path.join(path, filename) + return file + +################################################################################ +##################### Exposed Functions ######################################## +def HDRTool_CalQualityMetrics(origfile, recfile, num, w, h, logfilepath, + cfgfilepath): + cfgFile = GenerateCfgFile(origfile, recfile, num, w, h, cfgfilepath) + logfile = GetHDRLogFile(recfile, logfilepath) + args = " -f %s > %s" % (cfgFile, logfile) + cmd = HDRTool + args + ExecuteCmd(cmd, LogCmdOnly) + +def HDRTool_GatherQualityMetrics(recfile, logfilepath): + logfile = GetHDRLogFile(recfile, logfilepath) + results = ParseHDRToolLogFile(logfile) + return results
diff --git a/tools/convexhull_framework/src/CalcQtyWithVmafTool.py b/tools/convexhull_framework/src/CalcQtyWithVmafTool.py new file mode 100644 index 0000000..46efc1e --- /dev/null +++ b/tools/convexhull_framework/src/CalcQtyWithVmafTool.py
@@ -0,0 +1,69 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os +import re +import logging +from Config import BinPath, LoggerName, LogCmdOnly, VMAF +from Utils import GetShortContentName, ExecuteCmd + +subloggername = "CalcQtyMetrics_VMAFTool" +loggername = LoggerName + '.' + '%s' % subloggername +logger = logging.getLogger(loggername) + +Model_Pkg_File = os.path.join(BinPath, 'vmaf_v0.6.1.pkl') +VMAFMetricsFullList = ['VMAF_Y', 'PSNR_Y', 'SSIM_Y', 'MS-SSIM_Y'] + +def ParseVMAFLogFile(vmaf_log): + floats = len(VMAFMetricsFullList) * [0.0] + flog = open(vmaf_log, 'r') + for line in flog: + if 'aggregateVMAF' in line: + item = re.findall(r"aggregateVMAF=\"(\d+\.?\d*)\"", line) + floats[0] = 0 if len(item) == 0 else item[0] + item = re.findall(r"aggregatePSNR=\"(\d+\.?\d*)\"", line) + floats[1] = 0 if len(item) == 0 else item[0] + item = re.findall(r"aggregateSSIM=\"(\d+\.?\d*)\"", line) + floats[2] = 0 if len(item) == 0 else item[0] + item = re.findall(r"aggregateMS_SSIM=\"(\d+\.?\d*)\"", line) + floats[3] = 0 if len(item) == 0 else item[0] + break + flog.close() + + floats = [float(i) for i in floats] + + print_str = "VMAF quality metrics: " + for metrics, idx in zip(VMAFMetricsFullList, range(len(VMAFMetricsFullList))): + print_str += "%s = %2.5f, " % (metrics, floats[idx]) + logger.info(print_str) + + return floats[0:len(VMAFMetricsFullList)] + + +def GetVMAFLogFile(recfile, path): + filename = GetShortContentName(recfile, False) + '_vmaf.log' + file = os.path.join(path, filename) + return file + +################################################################################ +##################### Exposed Functions ######################################## +def VMAF_CalQualityMetrics(origfile, recfile, num, w, h, logfilePath): + vmaf_log = GetVMAFLogFile(recfile, logfilePath) + args = " yuv420p %d %d %s %s %s --log %s --psnr --ssim --ms-ssim "\ + % (w, h, origfile, recfile, Model_Pkg_File, vmaf_log) + cmd = VMAF + args + ExecuteCmd(cmd, LogCmdOnly) + +def VMAF_GatherQualityMetrics(recfile, logfilePath): + vmaf_log = GetVMAFLogFile(recfile, logfilePath) + results = ParseVMAFLogFile(vmaf_log) + return results
diff --git a/tools/convexhull_framework/src/CalculateQualityMetrics.py b/tools/convexhull_framework/src/CalculateQualityMetrics.py new file mode 100644 index 0000000..4f61fa2 --- /dev/null +++ b/tools/convexhull_framework/src/CalculateQualityMetrics.py
@@ -0,0 +1,73 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import logging +from Config import QualityList, LoggerName, QualityEvalMethods +import Utils +from CalcQtyWithVmafTool import VMAF_CalQualityMetrics, VMAF_GatherQualityMetrics,\ + VMAFMetricsFullList +from CalcQtyWithHdrTools import HDRTool_CalQualityMetrics, HDRToolsMetricsFullList,\ + HDRTool_GatherQualityMetrics +from CalcQtyWithFfmpeg import FFMPEG_GatherQualityMetrics, FFMPEGMetricsFullList,\ + FFMPEG_CalQualityMetrics + +subloggername = "CalcQtyMetrics" +loggername = LoggerName + '.' + '%s' % subloggername +logger = logging.getLogger(loggername) + +MetricsFullDict = {'VMAF': VMAFMetricsFullList, 'HDRTools': HDRToolsMetricsFullList, + 'FFMPEG': FFMPEGMetricsFullList} + +def CalculateQualityMetric(content, framenum, reconYUV, width, height, logfilePath, + cfgfilePath): + Utils.CmdLogger.write("::Quality Metrics\n") + + methods_torun = list(set(QualityEvalMethods)) # remove duplicate items + for method in methods_torun: + if method == 'VMAF': + VMAF_CalQualityMetrics(content, reconYUV, framenum, width, height, + logfilePath) + elif method == 'HDRTools': + HDRTool_CalQualityMetrics(content, reconYUV, framenum, width, height, + logfilePath, cfgfilePath) + elif method == 'FFMPEG': + FFMPEG_CalQualityMetrics(content, reconYUV, framenum, width, height, + logfilePath) + else: + logger.error("invalid quality evaluation method: %s !" % method) + return + +def GatherQualityMetrics(reconYUV, logfilePath): + methods_torun = list(set(QualityEvalMethods)) # remove duplicate items + qresult_dict = {} + for method in methods_torun: + if method == 'VMAF': + qresult_dict[method] = VMAF_GatherQualityMetrics(reconYUV, logfilePath) + elif method == 'HDRTools': + qresult_dict[method] = HDRTool_GatherQualityMetrics(reconYUV, logfilePath) + elif method == 'FFMPEG': + qresult_dict[method] = FFMPEG_GatherQualityMetrics(reconYUV, logfilePath) + else: + logger.error("invalid quality evaluation method: %s !" % method) + return + + results = [] + for metric, method in zip(QualityList, QualityEvalMethods): + mfullList = MetricsFullDict[method] + if metric in mfullList: + indx = mfullList.index(metric) + results.append(qresult_dict[method][indx]) + else: + logger.error("invalid quality metrics in QualityList") + results.append('none') + + return results
diff --git a/tools/convexhull_framework/src/Config.py b/tools/convexhull_framework/src/Config.py new file mode 100644 index 0000000..5a6ebb0 --- /dev/null +++ b/tools/convexhull_framework/src/Config.py
@@ -0,0 +1,157 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os + +###################################### +# configuration settings +###################################### +RootPath = "..\\" +BinPath = os.path.join(RootPath, 'bin') +WorkPath = os.path.join(RootPath, 'test') +SMOKE_TEST = False # override some parameters to do a quick smoke test +FrameNum = 60 + +if SMOKE_TEST: + FrameNum = 2 + +############ test contents ####################################### +ContentPath = "..\\video" +# when Have_Class_Subfolder is set to True, test clips are put in subfolders +# under ContentPath, each subfolder name represents a class. Class name in the +# table of Clips is the subfolder name +Have_Class_Subfolder = False +Clips = { +# basename class width height framerate bitdepth fmt + #"CrowdRun": ["ClassB", 1920, 1080, 30, 8, "yuv420p"], + #"BasketballDrive": ["ClassB", 1920, 1080, 30, 8, "yuv420p"], + "NetflixCrosswalk_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080, + 30, 8, "yuv420p"], +} +''' + "aspen_1080p_60f": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], + "dark720p_60f": ["ClassB", 1280, 720, 30, 8, + "yuv420p"], + "DOTA2_60f_420": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], + "duckstakeoff_1080p50_60f": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], + "KristenAndSara_1280x720_60f": ["ClassB", 1280, 720, 30, 8, + "yuv420p"], + "life_1080p30_60f": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], + "MINECRAFT_60f_420": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], + "NetflixAerial_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080, + 30, 8, "yuv420p"], + "NetflixBoat_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080, + 30, 8, "yuv420p"], + "NetflixCrosswalk_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080, + 30, 8, "yuv420p"], + "NetflixDrivingPOV_1280x720_60fps_8bit_420_60f": ["ClassB", 1280, 720, + 30, 8, "yuv420p"], + "NetflixFoodMarket_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080, + 30, 8, "yuv420p"], + "NetflixPierSeaside_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, 1080, + 30, 8, "yuv420p"], + "NetflixRollerCoaster_1280x720_60fps_8bit_420_60f": ["ClassB", 1280, 720, + 30, 8, "yuv420p"], + "NetflixSquareAndTimelapse_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, + 1080, 30, 8, "yuv420p"], + "NetflixTunnelFlag_1920x1080_60fps_8bit_420_60f": ["ClassB", 1920, + 1080, 30, 8, "yuv420p"], + "rushhour_1080p25_60f": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], + "STARCRAFT_60f_420": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], + "touchdownpass_1080p_60f": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], + "vidyo1_720p_60fps_60f": ["ClassB", 1280, 720, 30, 8, + "yuv420p"], + "vidyo4_720p_60fps_60f": ["ClassB", 1280, 720, 30, 8, + "yuv420p"], + "wikipedia_420": ["ClassB", 1920, 1080, 30, 8, + "yuv420p"], +''' +############## Scaling settings ############################################ +# down scaling ratio +DnScaleRatio = [1.0, 1.5, 2.0, 3.0, 4.0] #, 6.0] # downscale ratio +#down and up scaling algorithm, the 2 lists should be of same size +DnScalingAlgos = ['bicubic', 'bilinear', 'gauss', 'lanczos', 'sinc'] +UpScalingAlgos = ['bicubic', 'bilinear', 'gauss', 'lanczos', 'sinc'] + +if SMOKE_TEST: + DnScalingAlgos = ['bicubic', 'lanczos', 'sinc'] + UpScalingAlgos = ['bicubic', 'lanczos', 'sinc'] + +##################### Encode Config ######################################## +EncodeMethods = ["ffmpeg", "aom", "svt"] +CodecNames = ["hevc", "av1"] +SUFFIX = {"hevc": ".265", "av1": ".ivf"} +FFMPEG = os.path.join(BinPath, 'ffmpeg.exe') +AOMENC = os.path.join(BinPath, 'aomenc.exe') +SVTAV1 = os.path.join(BinPath, 'SvtAv1EncApp.exe') +SVTHEVC = os.path.join(BinPath, 'SvtHevcEncApp.exe') +AOMDEC = os.path.join(BinPath, 'aomdec.exe') + +QPs = list(range(22, 51, 5)) # total 6 QPs +if SMOKE_TEST: + QPs = list(range(12, 45, 10)) # total 4 QPs + +######################## quality evalution config ############################# +QualityList = ['VMAF_Y', 'PSNR_Y', 'PSNR_U', 'PSNR_V', 'SSIM_Y', 'MS-SSIM_Y'] +# method should be one of 'VMAF', 'FFMPEG' or 'HDRTools' +QualityEvalMethods = ['VMAF', 'HDRTools', 'HDRTools', 'HDRTools', 'HDRTools', + 'HDRTools'] +VMAF = os.path.join(BinPath, 'vmafossexec.exe') +HDRTool = os.path.join(BinPath, 'HDRMetrics.exe') + +######################## config for exporting data to excel ################# +#https://xlsxwriter.readthedocs.io/working_with_colors.html#colors +# line color used, number of colors >= len(DnScaledRes) +LineColors = ['blue', 'red', 'green', 'orange', 'pink', 'yellow'] +ConvexHullColor = 'white' + +# format for exported excel of convexhull test +# if to modify below 3 variables, need to modify function +# SaveConvexHullResultsToExcel accordingly +CvxH_startCol = 1; CvxH_startRow = 2; CvxH_colInterval = 2 +CvxH_WtCols = [(CvxH_colInterval + 1 + len(QualityList)) * i + CvxH_startCol + for i in range(len(DnScaleRatio))] +CvxH_WtRows = [CvxH_startRow + i for i in range(len(QPs))] +CvxH_WtLastCol = CvxH_WtCols[-1] + len(QualityList) +CvxH_WtLastRow = CvxH_WtRows[-1] +######################## post analysis ######################################### +PostAnalysis_Path = os.path.join(RootPath, 'analysis') +Path_RDResults = os.path.join(PostAnalysis_Path, 'rdresult') +SummaryOutPath = os.path.join(PostAnalysis_Path, 'summary') +Path_ScalingResults = os.path.join(PostAnalysis_Path, 'scalingresult') +# vba file needed when to calculate bdrate +#VbaBinFile = os.path.join(BinPath, 'vbaProject_JVET-L0242.bin') +VbaBinFile = os.path.join(BinPath, 'vbaProject-AV2.bin') + +# format for exported excel of scaling quality test +# if to modify below 3 variables, need to modify function SaveScalingResultsToExcel +# accordingly +ScalQty_startCol = 6; ScalQty_startRow = 2; ScalQty_colInterval = 1 +ScalSumQty_startCol = 7 +ScalQty_WtCols = [(ScalQty_colInterval + + len(QualityList)) * i + ScalQty_startCol + for i in range(len(DnScalingAlgos))] +ScalSumQty_WtCols = [(ScalQty_colInterval + + len(QualityList)) * i + ScalQty_startCol + 1 + for i in range(len(DnScalingAlgos))] +######################## logging ######################################### +LoggerName = "ConvexHullTest" +LogLevels = ['NONE', 'CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'] +LogCmdOnly = False
diff --git a/tools/convexhull_framework/src/ConvexHullBDRate.py b/tools/convexhull_framework/src/ConvexHullBDRate.py new file mode 100644 index 0000000..26bc858 --- /dev/null +++ b/tools/convexhull_framework/src/ConvexHullBDRate.py
@@ -0,0 +1,227 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import sys +import xlsxwriter +import xlrd +import argparse +from Config import VbaBinFile, QualityList + +class ConvexHullData: + ContentName = "" + ContentClass = "" + NumRDPoints = 0 + RDPoints = {} + def __init__(self, Name="", Class="", num=0): + self.ContentName = Name + self.ContentClass = Class + self.NumRDPoints = num + self.RDPoints = {} + +def ParseArguments(raw_args): + parser = argparse.ArgumentParser(prog='ConvexHullBDRate.py', + usage='%(prog)s [options]', description='') + parser.add_argument('-i1', '--input1', dest='Input1', type=str, + required=True, metavar='', + help="convex hull summary excel file for base mode") + parser.add_argument('-i2', '--input2', dest='Input2', type=str, + required=True, metavar='', + help="convex hull summary excel file for target mode") + parser.add_argument('-o', '--output', dest='Output', type=str, + required=True, metavar='', + help="output excel file with BDRATE for base and target" + " modes") + if len(raw_args) == 1: + parser.print_help() + sys.exit(1) + args = parser.parse_args(raw_args[1:]) + + global InputBase, InputTarget, Output + InputBase = args.Input1 + InputTarget = args.Input2 + Output = args.Output + +def read_cell_as_str(sht, row, col): + cell_val = sht.cell(row, col).value + if cell_val == '': + return '' + else: + return str(cell_val) + +def read_cell_as_float(sht, row, col): + cell_val = sht.cell(row, col).value + if cell_val == '': + return '' + else: + return float(cell_val) + +def read_cell_as_int(sht, row, col): + cell_val = sht.cell(row, col).value + if cell_val == '': + return '' + else: + return int(cell_val) + +def ParseConvexHullRD(xls): + wb = xlrd.open_workbook(xls) + shts = wb.sheet_names() #list of sheet names + data = {} #dict of data, key is the sheet name + + for sht_name in shts: + sht = wb.sheet_by_name(sht_name) + #skip the title row + rows = sht.nrows + cols = sht.ncols + start_row = 1 + while start_row < rows: + row = start_row + cls = read_cell_as_str(sht, row, 0) + name = read_cell_as_str(sht, row, 1) + num = read_cell_as_int(sht, row, 2) + if (cls == '' or name == '' or num == ''): + print("Error: read empty cells") + exit() + + point = ConvexHullData(name, cls, num) + + rd_data = {} + for row in range(num): + col = 3 + for qty in QualityList: + br = read_cell_as_float(sht, start_row+row, col) + q = read_cell_as_float(sht, start_row+row, col + 1) + if (br != '' and q != ''): + if (qty in rd_data.keys()): + rd_data[qty].append((br, q)) + else: + rd_data.update({qty:[(br, q)]}) + col += 2 + start_row += num + point.RDPoints = rd_data + if (sht_name in data.keys()): + data[sht_name].append(point) + else: + data.update({sht_name: [point]}) + + #wb.close() + return shts, data + +def WriteOutputHeaderRow(sht): + sht.write(0, 0, 'Content Class') + sht.write(0, 1, 'Content Name') + sht.write(0, 2, 'Num RD Points') + col = 3 + for qty in QualityList: + sht.write(0, col, 'Bitrate(kbps)') + sht.write(0, col + 1, qty) + col += 2 + col += 1 + for qty in QualityList: + sht.write(0, col, 'Bitrate(kbps)') + sht.write(0, col + 1, qty) + col += 2 + col += 1 + for (idx, qty) in zip(range(len(QualityList)), QualityList): + sht.write(0, col + idx, "BDRATE-%s"%qty) + +def WriteRDData(sht, rd_data, start_row, start_col, format): + col = start_col + max_rows = 0 + for qty in QualityList: + row = start_row + for (line, point) in zip(range(len(rd_data.RDPoints[qty])), + rd_data.RDPoints[qty]): + sht.write_number(row + line, col, point[0], format) + sht.write_number(row + line, col + 1, point[1], format) + col += 2 + max_rows = max(max_rows, len(rd_data.RDPoints[qty])) + return max_rows + +def WriteRDRecord(sht, base_data, target_data, start_row, bdrate_fmt, float_fmt): + sht.write(start_row, 0, base_data.ContentClass) + sht.write(start_row, 1, base_data.ContentName) + + #write base data + base_start_col = 3 + base_max_rows = WriteRDData(sht, base_data, start_row, base_start_col, + float_fmt) + + #write target data + target_start_col = base_start_col + 2 * len(QualityList) + 1 + target_max_rows = WriteRDData(sht, target_data, start_row, target_start_col, + float_fmt) + + #write bdrate formula + bdrate_start_col = target_start_col + 2 * len(QualityList) + 1 + total_rows = max(base_max_rows, target_max_rows) + sht.write(start_row, 2, total_rows) + for (qty, col) in zip(QualityList, range(len(QualityList))): + refbr_b = xlrd.cellnameabs(start_row, base_start_col + col * 2) + refbr_e = xlrd.cellnameabs(start_row + total_rows - 1, + base_start_col + col * 2) + refq_b = xlrd.cellnameabs(start_row, base_start_col + col * 2 + 1) + refq_e = xlrd.cellnameabs(start_row + total_rows - 1, + base_start_col + col * 2 + 1) + + testbr_b = xlrd.cellnameabs(start_row, target_start_col + col * 2) + testbr_e = xlrd.cellnameabs(start_row + total_rows - 1, + target_start_col + col * 2) + testq_b = xlrd.cellnameabs(start_row, target_start_col + col * 2 + 1) + testq_e = xlrd.cellnameabs(start_row + total_rows - 1, + target_start_col + col * 2 + 1) + + # formula = '=-bdrate(%s:%s,%s:%s,%s:%s,%s:%s)' % ( + # refbr_b, refbr_e, refq_b, refq_e, testbr_b, testbr_e, testq_b, testq_e) + formula = '=bdRateExtend(%s:%s,%s:%s,%s:%s,%s:%s)'\ + % (refbr_b, refbr_e, refq_b, refq_e, testbr_b, testbr_e, testq_b, testq_e) + sht.write_formula(start_row, bdrate_start_col + col, formula, bdrate_fmt) + return total_rows + +def FindContent(name, rd_data): + for data in rd_data: + if (name == data.ContentName): + return data + return '' + +###################################### +# main +###################################### +if __name__ == "__main__": + sys.argv = ["","-i1","ConvexHullRD_ScaleAlgosNum_5_ffmpeg_hevc_medium.xlsx", + "-i2","ConvexHullRD_ScaleAlgosNum_5_ffmpeg_hevc_veryslow.xlsx", + "-o","ConvexHullBDRate.xlsm"] + ParseArguments(sys.argv) + + base_shts, base_rd_data = ParseConvexHullRD(InputBase) + target_shts, target_rd_data = ParseConvexHullRD(InputTarget) + + output_wb = xlsxwriter.Workbook(Output) + # vba file needed when to calculate bdrate + output_wb.add_vba_project(VbaBinFile) + bdrate_fmt = output_wb.add_format() + bdrate_fmt.set_num_format('0.00%') + float_fmt = output_wb.add_format() + float_fmt.set_num_format('0.00') + + for sht_name in base_shts: + if sht_name in target_shts: + sht = output_wb.add_worksheet(sht_name) + WriteOutputHeaderRow(sht) + start_row = 1 + for base_data in base_rd_data[sht_name]: + ContentName = base_data.ContentName + target_data = FindContent(ContentName, target_rd_data[sht_name]) + if (target_data != ''): + total_rows = WriteRDRecord(sht, base_data, target_data, + start_row, bdrate_fmt, float_fmt) + start_row += total_rows + output_wb.close()
diff --git a/tools/convexhull_framework/src/ConvexHullTest.py b/tools/convexhull_framework/src/ConvexHullTest.py new file mode 100644 index 0000000..327249b --- /dev/null +++ b/tools/convexhull_framework/src/ConvexHullTest.py
@@ -0,0 +1,400 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os +import sys +import xlsxwriter +import argparse +from EncDecUpscale import Run_EncDec_Upscale, GetBsReconFileName +from VideoScaler import GetDownScaledOutFile, DownScaling +from CalculateQualityMetrics import CalculateQualityMetric, GatherQualityMetrics +from Utils import GetShortContentName, GetVideoInfo, CreateChart_Scatter,\ + AddSeriesToChart_Scatter, InsertChartsToSheet, CreateNewSubfolder,\ + GetContents, SetupLogging, UpdateChart, AddSeriesToChart_Scatter_Rows,\ + Cleanfolder +from PostAnalysis_Summary import GenerateSummaryExcelFile,\ + GenerateSummaryConvexHullExcelFile +from ScalingTest import Run_Scaling_Test, SaveScalingResultsToExcel +import Utils +from Config import LogLevels, FrameNum, DnScaleRatio, QPs, CvxH_WtCols,\ + CvxH_WtRows, QualityList, LineColors, DnScalingAlgos, UpScalingAlgos,\ + ContentPath, SummaryOutPath, WorkPath, Path_RDResults, Clips, \ + ConvexHullColor, EncodeMethods, CodecNames, LoggerName, LogCmdOnly + +############################################################################### +##### Helper Functions ######################################################## +def CleanIntermediateFiles(): + folders = [Path_DecodedYuv, Path_CfgFiles] + if not KeepUpscaledOutput: + folders += [Path_DecUpScaleYuv, Path_UpScaleYuv] + + for folder in folders: + Cleanfolder(folder) + +def GetRDResultExcelFile(content): + contentBaseName = GetShortContentName(content) + filename = "RDResults_%s_%s_%s_%s.xlsx" % (contentBaseName, EncodeMethod, + CodecName, EncodePreset) + file = os.path.join(Path_RDResults, filename) + return file + +def setupWorkFolderStructure(): + global Path_Bitstreams, Path_DecodedYuv, Path_UpScaleYuv, Path_DnScaleYuv,\ + Path_QualityLog, Path_TestLog, Path_CfgFiles, Path_DecUpScaleYuv + Path_Bitstreams = CreateNewSubfolder(WorkPath, "bistreams") + Path_DecodedYuv = CreateNewSubfolder(WorkPath, "decodedYUVs") + Path_UpScaleYuv = CreateNewSubfolder(WorkPath, "upscaledYUVs") + Path_DecUpScaleYuv = CreateNewSubfolder(WorkPath, "decUpscaledYUVs") + Path_DnScaleYuv = CreateNewSubfolder(WorkPath, "downscaledYUVs") + Path_QualityLog = CreateNewSubfolder(WorkPath, "qualityLogs") + Path_TestLog = CreateNewSubfolder(WorkPath, 'testLogs') + Path_CfgFiles = CreateNewSubfolder(WorkPath, "configFiles") + +''' +The convex_hull function is adapted based on the original python implementation +from https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain +It is changed to return the lower and upper portions of the convex hull separately +to get the convex hull based on traditional rd curve, only the upper portion is +needed. +''' + +def convex_hull(points): + """Computes the convex hull of a set of 2D points. + Input: an iterable sequence of (x, y) pairs representing the points. + Output: a list of vertices of the convex hull in counter-clockwise order, + starting from the vertex with the lexicographically smallest coordinates. + Implements Andrew's monotone chain algorithm. O(n log n) complexity. + """ + + # Sort the points lexicographically (tuples are compared lexicographically). + # Remove duplicates to detect the case we have just one unique point. + points = sorted(set(points)) + + # Boring case: no points or a single point, possibly repeated multiple times. + if len(points) <= 1: + return points + + # 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross + # product. Returns a positive value, if OAB makes a counter-clockwise turn, + # negative for clockwise turn, and zero if the points are collinear. + def cross(o, a, b): + return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) + + # Build lower hull + lower = [] + for p in points: + while len(lower) >= 2 and cross(lower[-2], lower[-1], p) <= 0: + lower.pop() + lower.append(p) + + # Build upper hull + upper = [] + for p in reversed(points): + while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0: + upper.pop() + upper.append(p) + + return lower, upper + +def AddConvexHullCurveToCharts(sht, startrow, startcol, charts, rdPoints, + dnScaledRes, sum_sht, sum_start_row): + shtname = sht.get_name() + sht.write(startrow, startcol, "ConvexHull Data") + numitems = 5 # qty, bitrate, qp, resolution, 1 empty row as internal + rows = [startrow + 1 + numitems * i for i in range(len(QualityList))] + + hull = {} + max_len = 0 + + for qty, idx, row in zip(QualityList, range(len(QualityList)), rows): + lower, upper = convex_hull(rdPoints[idx]) + hull[qty] = upper + max_len = max(max_len, len(upper)) + sht.write(row, startcol, qty) + sht.write(row + 1, startcol, "Bitrate(kbps)") + sht.write(row + 2, startcol, "QP") + sht.write(row + 3, startcol, 'Resolution') + + brts = [h[0] for h in hull[qty]] + qtys = [h[1] for h in hull[qty]] + sht.write_row(row, startcol + 1, qtys) + sht.write_row(row + 1, startcol + 1, brts) + + rdpnts_qtys = [rd[1] for rd in rdPoints[idx]] + cvh_qidxs = [rdpnts_qtys.index(qty) for qty in qtys] + cvh_QPs = [QPs[i % len(QPs)] for i in cvh_qidxs] + cvh_Res = [dnScaledRes[i // len(QPs)] for i in cvh_qidxs] + cvh_Res_txt = ["%sx%s" % (x, y) for (x, y) in cvh_Res] + sht.write_row(row + 2, startcol + 1, cvh_QPs) + sht.write_row(row + 3, startcol + 1, cvh_Res_txt) + + cols = [startcol + 1 + i for i in range(len(hull[qty]))] + AddSeriesToChart_Scatter_Rows(shtname, cols, row, row + 1, charts[idx], + 'ConvexHull', ConvexHullColor) + + endrow = rows[-1] + numitems + + #add convex hull data into summary sheet. the length of each convex hull + #could be different + sum_row = sum_start_row + sum_sht.write(sum_row, 2, max_len) + sum_col = 3 + for qty in QualityList: + row = sum_row + for point in hull[qty]: + sum_sht.write(row, sum_col, point[0]) + sum_sht.write(row, sum_col + 1, point[1]) + row += 1 + sum_col += 2 + + return endrow, sum_start_row + max_len - 1 + +############################################################################### +######### Major Functions ##################################################### +def CleanUp_workfolders(): + folders = [Path_DnScaleYuv, Path_Bitstreams, Path_DecodedYuv, Path_QualityLog, + Path_TestLog, Path_CfgFiles] + if not KeepUpscaledOutput: + folders += [Path_UpScaleYuv, Path_DecUpScaleYuv] + + for folder in folders: + Cleanfolder(folder) + +def Run_ConvexHull_Test(content, dnScalAlgo, upScalAlgo): + Utils.Logger.info("%s %s start running xcode tests with %s" % + (EncodeMethod, CodecName, os.path.basename(content))) + cls, width, height, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips) + if totalnum < FrameNum: + Utils.Logger.error("content %s includes total %d frames < specified % frames!" + % (content, totalnum, FrameNum)) + return + + DnScaledRes = [(int(width / ratio), int(height / ratio)) for ratio in DnScaleRatio] + for i in range(len(DnScaledRes)): + if SaveMemory: + CleanIntermediateFiles() + DnScaledW = DnScaledRes[i][0] + DnScaledH = DnScaledRes[i][1] + #downscaling if the downscaled file does not exist + dnscalyuv = GetDownScaledOutFile(content, width, height, DnScaledW, + DnScaledH, Path_DnScaleYuv, dnScalAlgo) + if not os.path.isfile(dnscalyuv): + dnscalyuv = DownScaling(content, FrameNum, width, height, DnScaledW, + DnScaledH, Path_DnScaleYuv, dnScalAlgo) + + for QP in QPs: + Utils.Logger.info("start transcode and upscale for %dx%d and QP %d" + % (DnScaledW, DnScaledH, QP)) + #transcode and upscaling + reconyuv = Run_EncDec_Upscale(EncodeMethod, CodecName, EncodePreset, + dnscalyuv, QP, FrameNum, fr, DnScaledW, + DnScaledH, width, height, Path_Bitstreams, + Path_DecodedYuv, Path_DecUpScaleYuv, + upScalAlgo) + #calcualte quality distortion + Utils.Logger.info("start quality metric calculation for %dx%d and QP %d" + % (DnScaledW, DnScaledH, QP)) + CalculateQualityMetric(content, FrameNum, reconyuv, width, height, + Path_QualityLog, Path_CfgFiles) + + if SaveMemory: + Cleanfolder(Path_DnScaleYuv) + + Utils.Logger.info("finish running encode test.") + +def SaveConvexHullResultsToExcel(content, dnScAlgos, upScAlgos, sum_wb, + sum_start_row): + Utils.Logger.info("start saving RD results to excel file.......") + if not os.path.exists(Path_RDResults): + os.makedirs(Path_RDResults) + excFile = GetRDResultExcelFile(content) + wb = xlsxwriter.Workbook(excFile) + shts = [] + for i in range(len(dnScAlgos)): + shtname = dnScAlgos[i] + '--' + upScAlgos[i] + shts.append(wb.add_worksheet(shtname)) + + cls, width, height, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips) + DnScaledRes = [(int(width / ratio), int(height / ratio)) for ratio in DnScaleRatio] + contentname = GetShortContentName(content) + for sht, indx in zip(shts, list(range(len(dnScAlgos)))): + # write QP + sht.write(1, 0, "QP") + sht.write_column(CvxH_WtRows[0], 0, QPs) + shtname = sht.get_name() + sum_sht = sum_wb.get_worksheet_by_name(shtname) + + charts = []; y_mins = {}; y_maxs = {}; RDPoints = {} + for qty, x in zip(QualityList, range(len(QualityList))): + chart_title = 'RD Curves - %s with %s' % (contentname, shtname) + xaxis_name = 'Bitrate - Kbps' + chart = CreateChart_Scatter(wb, chart_title, xaxis_name, qty) + charts.append(chart) + y_mins[x] = []; y_maxs[x] = []; RDPoints[x] = [] + + # write RD data + for col, i in zip(CvxH_WtCols, range(len(DnScaledRes))): + DnScaledW = DnScaledRes[i][0] + DnScaledH = DnScaledRes[i][1] + sht.write(0, col, "resolution=%dx%d" % (DnScaledW, DnScaledH)) + sht.write(1, col, "Bitrate(kbps)") + sht.write_row(1, col + 1, QualityList) + + bitratesKbps = []; qualities = [] + for qp in QPs: + bs, reconyuv = GetBsReconFileName(EncodeMethod, CodecName, + EncodePreset, content, width, + height, DnScaledW, DnScaledH, + dnScAlgos[indx], upScAlgos[indx], + qp, Path_Bitstreams) + bitrate = (os.path.getsize(bs) * 8 * fr / FrameNum) / 1000.0 + bitratesKbps.append(bitrate) + quality = GatherQualityMetrics(reconyuv, Path_QualityLog) + qualities.append(quality) + + sht.write_column(CvxH_WtRows[0], col, bitratesKbps) + for qs, row in zip(qualities, CvxH_WtRows): + sht.write_row(row, col + 1, qs) + + seriname = "resolution %dx%d" % (DnScaledW, DnScaledH) + for x in range(len(QualityList)): + # add RD curves of current resolution to each quality chart + AddSeriesToChart_Scatter(shtname, CvxH_WtRows, col + 1 + x, col, + charts[x], seriname, LineColors[i]) + # get min and max of y-axis + qs = [row[x] for row in qualities] + y_mins[x].append(min(qs)) + y_maxs[x].append(max(qs)) + # get RD points - (bitrate, quality) for each quality metrics + rdpnts = [(brt, qty) for brt, qty in zip(bitratesKbps, qs)] + RDPoints[x] = RDPoints[x] + rdpnts + + # add convexhull curve to charts + startrow = CvxH_WtRows[-1] + 2; startcol = 0 + + sum_startrow = sum_start_row[shtname] + sum_sht.write(sum_startrow, 0, cls) + sum_sht.write(sum_startrow, 1, contentname) + endrow, sum_end_row = AddConvexHullCurveToCharts(sht, startrow, startcol, + charts, RDPoints, + DnScaledRes, sum_sht, + sum_startrow) + sum_start_row[shtname] = sum_end_row + 1 + + #update RD chart with approprate y axis range + for qty, x in zip(QualityList, range(len(QualityList))): + ymin = min(y_mins[x]) + ymax = max(y_maxs[x]) + margin = 0.1 # add 10% on min and max value for y_axis range + num_precsn = 5 if 'MS-SSIM' in qty else 3 + UpdateChart(charts[x], ymin, ymax, margin, qty, num_precsn) + + startrow = endrow + 2; startcol = 1 + InsertChartsToSheet(sht, startrow, startcol, charts) + + wb.close() + Utils.Logger.info("finish export convex hull results to excel file.") + +def ParseArguments(raw_args): + parser = argparse.ArgumentParser(prog='ConvexHullTest.py', + usage='%(prog)s [options]', + description='') + parser.add_argument('-f', '--function', dest='Function', type=str, + required=True, metavar='', + choices=["clean", "scaling", "sumscaling", "encode", + "convexhull", "summary"], + help="function to run: clean, scaling, sumscaling, encode," + " convexhull, summary") + parser.add_argument('-k', "--KeepUpscaleOutput", dest='KeepUpscaledOutput', + type=bool, default=False, metavar='', + help="in function clean, if keep upscaled yuv files. It" + " is false by default") + parser.add_argument('-s', "--SaveMemory", dest='SaveMemory', type=bool, + default=False, metavar='', + help="save memory mode will delete most files in" + " intermediate steps and keeps only necessary " + "ones for RD calculation. It is false by default") + parser.add_argument('-l', "--LoggingLevel", dest='LogLevel', type=int, + default=3, choices=range(len(LogLevels)), metavar='', + help="logging level: 0:No Logging, 1: Critical, 2: Error," + " 3: Warning, 4: Info, 5: Debug") + parser.add_argument('-c', "--CodecName", dest='CodecName', type=str, + choices=CodecNames, metavar='', + help="CodecName: av1 or hevc") + parser.add_argument('-m', "--EncodeMethod", dest='EncodeMethod', type=str, + choices=EncodeMethods, metavar='', + help="EncodeMethod: ffmpeg, aom, svt") + parser.add_argument('-p', "--EncodePreset", dest='EncodePreset', type=str, + metavar='', help="EncodePreset: medium, slow, fast, etc" + " for ffmpeg, 0,1,2... for aom and svt") + if len(raw_args) == 1: + parser.print_help() + sys.exit(1) + args = parser.parse_args(raw_args[1:]) + + global Function, KeepUpscaledOutput, SaveMemory, LogLevel, CodecName,\ + EncodeMethod, EncodePreset + Function = args.Function + KeepUpscaledOutput = args.KeepUpscaledOutput + SaveMemory = args.SaveMemory + LogLevel = args.LogLevel + CodecName = args.CodecName + EncodeMethod = args.EncodeMethod + EncodePreset = args.EncodePreset + + +###################################### +# main +###################################### +if __name__ == "__main__": + #sys.argv = ["","-f","convexhull","-c","hevc","-m","ffmpeg","-p","medium"] + ParseArguments(sys.argv) + + # preparation for executing functions + setupWorkFolderStructure() + if Function != 'clean': + SetupLogging(LogLevel, LogCmdOnly, LoggerName, Path_TestLog) + Contents = GetContents(ContentPath, Clips) + + # execute functions + if Function == 'clean': + CleanUp_workfolders() + elif Function == 'scaling': + for content in Contents: + for dnScaleAlgo, upScaleAlgo in zip(DnScalingAlgos, UpScalingAlgos): + Run_Scaling_Test(content, dnScaleAlgo, upScaleAlgo, + Path_DnScaleYuv, Path_UpScaleYuv, Path_QualityLog, + Path_CfgFiles, SaveMemory, KeepUpscaledOutput) + elif Function == 'sumscaling': + SaveScalingResultsToExcel(DnScalingAlgos, UpScalingAlgos, Path_QualityLog) + elif Function == 'encode': + for content in Contents: + for dnScalAlgo, upScalAlgo in zip(DnScalingAlgos, UpScalingAlgos): + Run_ConvexHull_Test(content, dnScalAlgo, upScalAlgo) + elif Function == 'convexhull': + sum_wb, sum_start_row = GenerateSummaryConvexHullExcelFile(EncodeMethod, + CodecName, + EncodePreset, + SummaryOutPath, + DnScalingAlgos, + UpScalingAlgos) + for content in Contents: + SaveConvexHullResultsToExcel(content, DnScalingAlgos, UpScalingAlgos, + sum_wb, sum_start_row) + sum_wb.close() + elif Function == 'summary': + smfile = GenerateSummaryExcelFile(EncodeMethod, CodecName, EncodePreset, + SummaryOutPath, Path_RDResults, + ContentPath, Clips) + Utils.Logger.info("summary file generated: %s" % smfile) + else: + Utils.Logger.error("invalid parameter value of Function")
diff --git a/tools/convexhull_framework/src/EncDecUpscale.py b/tools/convexhull_framework/src/EncDecUpscale.py new file mode 100644 index 0000000..812eade --- /dev/null +++ b/tools/convexhull_framework/src/EncDecUpscale.py
@@ -0,0 +1,85 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os +from VideoEncoder import VideoEncode +from VideoDecoder import VideoDecode +from VideoScaler import UpScaling, GetDownScaledOutFile, GetUpScaledOutFile +from Config import SUFFIX, LoggerName +from Utils import GetShortContentName +import logging + +subloggername = "EncDecUpscale" +loggername = LoggerName + '.' + '%s' % subloggername +logger = logging.getLogger(loggername) + +################################################################################ +##################### Internal Helper Functions ################################ +def GetBitstreamFile(method, codec, preset, yuvfile, qp, outpath): + bs_suffix = SUFFIX[codec] + Prefix_EncodeCfg = '_%s_%s_Preset_%s' % (method, codec, preset) + filename = GetShortContentName(yuvfile, False) + Prefix_EncodeCfg + "_QP_"\ + + str(qp) + bs_suffix + filename = os.path.join(outpath, filename) + return filename + +def GetDecodedFile(bsfile, outpath): + filename = GetShortContentName(bsfile, False) + '_Decoded.yuv' + decodedfile = os.path.join(outpath, filename) + return decodedfile + +################################################################################ +##################### Major Functions ########################################## +def Encode(method, codec, preset, input, qp, num, framerate, width, height, path): + bsfile = GetBitstreamFile(method, codec, preset, input, qp, path) + # call VideoEncoder to do the encoding + VideoEncode(method, codec, input, qp, num, framerate, width, height, bsfile, + preset) + return bsfile + + +def Decode(codec, bsfile, path): + decodedfile = GetDecodedFile(bsfile, path) + #call VideoDecoder to do the decoding + VideoDecode(codec, bsfile, decodedfile) + return decodedfile + + +def Run_EncDec_Upscale(method, codec, preset, input, QP, num, framerate, inw, + inh, outw, outh, path_bs, path_decoded, + path_upscaled, algo): + logger.info("%s %s start encode file %s with QP = %d" + % (method, codec, os.path.basename(input), QP)) + bsFile = Encode(method, codec, preset, input, QP, num, framerate, inw, inh, + path_bs) + logger.info("start decode file %s" % os.path.basename(bsFile)) + decodedYUV = Decode(codec, bsFile, path_decoded) + logger.info("start upscale file %s" % os.path.basename(decodedYUV)) + upscaledYUV = UpScaling(decodedYUV, num, inw, inh, outw, outh, path_upscaled, + algo) + logger.info("finish Run Encode, Decode and Upscale") + return upscaledYUV + + +def GetBsReconFileName(encmethod, codecname, preset, content, width, height, + dnwidth, dnheight, dnScAlgo, + upScAlgo, qp, path_bs): + dsyuv_name = GetDownScaledOutFile(content, width, height, dnwidth, dnheight, + path_bs, dnScAlgo) + # return bitstream file with absolute path + bs = GetBitstreamFile(encmethod, codecname, preset, dsyuv_name, qp, path_bs) + decoded = GetDecodedFile(bs, path_bs) + reconfilename = GetUpScaledOutFile(decoded, dnwidth, dnheight, width, height, + path_bs, upScAlgo) + # return only Recon yuv file name w/o path + reconfilename = GetShortContentName(reconfilename, False) + return bs, reconfilename
diff --git a/tools/convexhull_framework/src/PostAnalysis_Summary.py b/tools/convexhull_framework/src/PostAnalysis_Summary.py new file mode 100644 index 0000000..1d711e9 --- /dev/null +++ b/tools/convexhull_framework/src/PostAnalysis_Summary.py
@@ -0,0 +1,389 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os +import xlsxwriter +import xlrd +from Config import QPs, DnScaleRatio, QualityList, VbaBinFile, CvxH_WtRows,\ + CvxH_WtLastCol, LoggerName +from Utils import GetShortContentName, CalcRowsClassAndContentDict,\ + SweepScalingAlgosInOneResultFile +import logging + +subloggername = "PostAnalysisSummary" +loggername = LoggerName + '.' + '%s' % subloggername +logger = logging.getLogger(loggername) + +# give all paths including convex hull result file (only one file for each +# content) to generate summary file for all contents in Input path +# assume all content's result has same test settings + +################################################################################ +### Helper Functions ########################################################### +def GetSummaryFileName(encMethod, codecName, preset, path): + name = 'ConvexHullSummary_ScaleAlgosNum_%d_%s_%s_%s.xlsm'\ + % (len(DnScaleRatio), encMethod, codecName, preset) + return os.path.join(path, name) + +def GetConvexHullRDFileName(encMethod, codecName, preset, path): + name = 'ConvexHullRD_ScaleAlgosNum_%d_%s_%s_%s.xlsx'\ + % (len(DnScaleRatio), encMethod, codecName, preset) + return os.path.join(path, name) + +def CopyResultDataToSummaryFile_Onesheet(sht, wt_cols, contentsdict, rows_class, + infile_path): + rdrows = CvxH_WtRows + rd_endcol = CvxH_WtLastCol + + shtname = sht.get_name() + sht.write(1, 0, 'Content Class') + sht.write(1, 1, 'Content Name') + sht.write(1, 2, 'QP') + for residx, col in zip(range(len(DnScaleRatio)), wt_cols): + sht.write(0, col, 'Scaling Ratio = %.2f' % (DnScaleRatio[residx])) + sht.write(1, col, 'Bitrate(kbps)') + qtynames = ['%s' % qty for qty in QualityList] + sht.write_row(1, col + 1, qtynames) + + # copy the results data from each content's result file to corresponding + # location in summary excel file + resultfiles = os.listdir(infile_path) + for (cls, contents), row_class in zip(contentsdict.items(), rows_class): + sht.write(row_class, 0, cls) + rows_content = [i * len(QPs) for i in range(len(contents))] + for content, row_cont in zip(contents, rows_content): + key = GetShortContentName(content) + sht.write(row_class + row_cont, 1, key) + rdwb = None + for resfile in resultfiles: + if key in resfile: + rdwb = xlrd.open_workbook(os.path.join(infile_path, resfile)) + rdsht = rdwb.sheet_by_name(shtname) + for i, rdrow in zip(range(len(QPs)), rdrows): + data = rdsht.row_values(rdrow, 0, rd_endcol + 1) + sht.write_row(row_class + row_cont + i, 2, data) + break + assert rdwb is not None + if rdwb is None: + logger.warning("not find convex hull result file for content:%s" + % content) + +def CalBDRate_OneSheet(sht, cols, contentsdict, rows_class, cols_bdmtrs, cellformat): + row_refst = 0 + bdstep = 3 + for cols_bd, residx in zip(cols_bdmtrs, range(1, len(DnScaleRatio))): + sht.write(0, cols_bd, 'BD-Rate %.2f vs. %.2f' % (DnScaleRatio[residx], + DnScaleRatio[0])) + sht.write_row(1, cols_bd, QualityList) + for (cls, contents), row_class in zip(contentsdict.items(), rows_class): + rows_content = [i * len(QPs) for i in range(len(contents))] + for row_cont in rows_content: + for y in range(len(QualityList)): + refbr_b = xlrd.cellnameabs(row_class + row_cont + row_refst, + cols[0]) + refbr_e = xlrd.cellnameabs(row_class + row_cont + row_refst + + bdstep, cols[0]) + refq_b = xlrd.cellnameabs(row_class + row_cont + row_refst, + cols[0] + 1 + y) + refq_e = xlrd.cellnameabs(row_class + row_cont + row_refst + + bdstep, cols[0] + 1 + y) + + testbr_b = xlrd.cellnameabs(row_class + row_cont, + cols[residx]) + testbr_e = xlrd.cellnameabs(row_class + row_cont + bdstep, + cols[residx]) + testq_b = xlrd.cellnameabs(row_class + row_cont, + cols[residx] + 1 + y) + testq_e = xlrd.cellnameabs(row_class + row_cont + bdstep, + cols[residx] + 1 + y) + + #formula = '=-bdrate(%s:%s,%s:%s,%s:%s,%s:%s)' % ( + #refbr_b, refbr_e, refq_b, refq_e, testbr_b, testbr_e, + # testq_b, testq_e) + formula = '=bdRateExtend(%s:%s,%s:%s,%s:%s,%s:%s)'\ + % (refbr_b, refbr_e, refq_b, refq_e, testbr_b, + testbr_e, testq_b, testq_e) + sht.write_formula(row_class + row_cont, cols_bd + y, formula, + cellformat) + +def GenerateFormula_SumRows(shtname, rows, col): + cells = '' + for row in rows: + location = xlrd.cellnameabs(row, col) + cells = cells + '\'%s\'!%s,' % (shtname, location) + cells = cells[:-1] # remove the last , + formula = '=SUM(%s)/%d' % (cells, len(rows)) + return formula + +def GenerateFormula_SumRows_Weighted(rows, col, weight_rows, weight_col, num): + cells = '' + for row, wtrow in zip(rows, weight_rows): + location = xlrd.cellnameabs(row, col) + weight = xlrd.cellnameabs(wtrow, weight_col) + cells = cells + '%s * %s,' % (location, weight) + cells = cells[:-1] # remove the last , + formula = '=SUM(%s)/%d' % (cells, num) + return formula + +def WriteBitrateQtyAverageSheet(wb, rdshts, contentsdict, rd_rows_class, rdcols): + avg_sht = wb.add_worksheet('Average') + avg_sht.write(2, 0, 'Content Class') + avg_sht.write(2, 1, 'Content Number') + avg_sht.write(2, 2, 'QP') + + colstart = 3 + cols_res = [colstart] + step = len(QualityList) + 1 + 1 # 1 for bitrate, 1 for interval + colres_2nd_start = colstart + step + step = len(upScalAlgos) * (len(QualityList) + 1) + 1 # + 1 for interval + cols_res += [step * i + colres_2nd_start for i in range(len(DnScaleRatio) - 1)] + step = len(QualityList) + 1 # + 1 for bitrate + cols_upscl = [step * i for i in range(len(upScalAlgos))] + for residx, col_res in zip(range(len(DnScaleRatio)), cols_res): + avg_sht.write(0, col_res, 'ScalingRatio = %.2f' % (DnScaleRatio[residx])) + if residx == 0: + avg_sht.write(1, col_res + 1, 'None') + avg_sht.write(2, col_res, 'Bitrate(kbps)') + avg_sht.write_row(2, col_res + 1, QualityList) + else: + for dnsc, upsc, col_upscl in zip(dnScalAlgos, upScalAlgos, cols_upscl): + avg_sht.write(1, col_res + col_upscl + 1, '%s--%s' % (dnsc, upsc)) + avg_sht.write(2, col_res + col_upscl, 'Bitrate(kbps)') + avg_sht.write_row(2, col_res + col_upscl + 1, QualityList) + + startrow = 3 + step = len(QPs) + rows_class_avg = [startrow + step * i for i in range(len(contentsdict))] + totalnum_content = 0 + for (cls, contents), row_class, rdclassrow in zip(contentsdict.items(), + rows_class_avg, + rd_rows_class): + avg_sht.write(row_class, 0, cls) + totalnum_content = totalnum_content + len(contents) + avg_sht.write(row_class, 1, len(contents)) + avg_sht.write_column(row_class, 2, QPs) + rows_content = [i * len(QPs) for i in range(len(contents))] + + for rdcol, col_res, residx in zip(rdcols, cols_res, range(len(DnScaleRatio))): + for i in range(len(QPs)): + sum_rows = [rdclassrow + row_cont + i for row_cont in rows_content] + for col_upscl, sht in zip(cols_upscl, rdshts): + shtname = sht.get_name() + # write bitrate average formula. + formula = GenerateFormula_SumRows(shtname, sum_rows, rdcol) + avg_sht.write_formula(row_class + i, col_res + col_upscl, + formula) + # write quality average formula + for j in range(len(QualityList)): + formula = GenerateFormula_SumRows(shtname, sum_rows, + rdcol + 1 + j) + avg_sht.write_formula(row_class + i, + col_res + col_upscl + 1 + j, + formula) + + # for first resolution, no down and up scaling. only need + # one set of bitrate/quality data + if residx == 0: + break + + # write total average + last_class_row = rows_class_avg[-1] + len(QPs) + 1 # 1 for 1 row of interval + avg_sht.write(last_class_row, 0, 'Total') + avg_sht.write(last_class_row, 1, totalnum_content) + avg_sht.write_column(last_class_row, 2, QPs) + weight_rows = [row_class for row_class in rows_class_avg] + for col_res, residx in zip(cols_res, range(len(DnScaleRatio))): + for i in range(len(QPs)): + sum_rows = [row_class + i for row_class in rows_class_avg] + for col_upscl in cols_upscl: + # bitrate average + formula = GenerateFormula_SumRows_Weighted(sum_rows, + col_res + col_upscl, + weight_rows, 1, + totalnum_content) + avg_sht.write_formula(last_class_row + i, col_res + col_upscl, + formula) + # quality average + for j in range(len(QualityList)): + formula = GenerateFormula_SumRows_Weighted(sum_rows, + col_res + + col_upscl + 1 + j, + weight_rows, 1, + totalnum_content) + avg_sht.write_formula(last_class_row + i, + col_res + col_upscl + 1 + j, formula) + # for first resolution, no down and up scaling. only need one + # set of bitrate/quality data + if residx == 0: + break + +def WriteBDRateAverageSheet(wb, rdshts, contentsdict, rd_rows_class, + rd_cols_bdmtrs, cellformat): + # write bdrate average sheet + bdavg_sht = wb.add_worksheet('Average_BDRate') + bdavg_sht.write(2, 0, 'Content Class') + bdavg_sht.write(2, 1, 'Content Number') + + startcol = 2 + startrow = 3 + colintval_scalalgo = 1 + colintval_dnscalres = 1 + + step_upscl = len(QualityList) + colintval_scalalgo + cols_upscl_bd = [step_upscl * i for i in range(len(upScalAlgos))] + step_res = len(upScalAlgos) * step_upscl + colintval_dnscalres + cols_res_bd = [step_res * i + startcol for i in range(len(DnScaleRatio) - 1)] + rows_class_rdavg = [startrow + i for i in range(len(contentsdict))] + + for residx, col_res_bd in zip(range(1, len(DnScaleRatio)), cols_res_bd): + bdavg_sht.write(0, col_res_bd, 'BD-Rate %.2f vs. %.2f' + % (DnScaleRatio[residx], DnScaleRatio[0])) + for dnsc, upsc, col_upscl_bd in zip(dnScalAlgos, upScalAlgos, cols_upscl_bd): + bdavg_sht.write(1, col_res_bd + col_upscl_bd, '%s--%s' % (dnsc, upsc)) + bdavg_sht.write_row(2, col_res_bd + col_upscl_bd, QualityList) + + totalnum_content = 0 + for (cls, contents), row_class, rdclassrow in zip(contentsdict.items(), + rows_class_rdavg, + rd_rows_class): + bdavg_sht.write(row_class, 0, cls) + totalnum_content = totalnum_content + len(contents) + bdavg_sht.write(row_class, 1, len(contents)) + rows_content = [i * len(QPs) for i in range(len(contents))] + sum_rows = [rdclassrow + row_cont for row_cont in rows_content] + for rdcol, col_res in zip(rd_cols_bdmtrs, cols_res_bd): + # write average bd rate + for col_upscl, sht in zip(cols_upscl_bd, rdshts): + shtname = sht.get_name() + for j in range(len(QualityList)): + formula = GenerateFormula_SumRows(shtname, sum_rows, rdcol + j) + bdavg_sht.write_formula(row_class, col_res + col_upscl + j, + formula, cellformat) + + # write total average + last_row = rows_class_rdavg[-1] + 1 + bdavg_sht.write(last_row, 0, 'Total') + bdavg_sht.write(last_row, 1, totalnum_content) + sum_rows = [row_class for row_class in rows_class_rdavg] + for col_res in cols_res_bd: + for col_upscl in cols_upscl_bd: + for j in range(len(QualityList)): + formula = GenerateFormula_SumRows_Weighted(sum_rows, + col_res + col_upscl + j, + sum_rows, 1, + totalnum_content) + bdavg_sht.write_formula(last_row, col_res + col_upscl + j, + formula, cellformat) + +####################################################################### +####################################################################### +# GenerateSummaryExcelFile is to +# 1. summarize all contents convexhull results into one file +# 2. calculate average of bitrate and quality metrics for each content class +# 3. calculate BD rate across different scaling ratios for all scaling +# algorithms in convex hull test +# 4. calcualte average BD rate for each content class +# Arguments description: +# content_paths is where test contents located, which used for generating convex +# hull results. +# infile_path is where convex hull results excel files located. +# classes is the content classes and here it requires contents are located +# in corresponding subfolder named with its belonged class +# summary_outpath is the folder where output summary file will be +# note: all results files under infile_path should have exactly same test items +# before running this summary script +def GenerateSummaryExcelFile(encMethod, codecName, preset, summary_outpath, + infile_path, content_path, clips): + global dnScalAlgos, upScalAlgos + # find all scaling algos tested in results file, expect they are the same + # for every content + dnScalAlgos, upScalAlgos = SweepScalingAlgosInOneResultFile(infile_path) + + if not os.path.exists(summary_outpath): + os.makedirs(summary_outpath) + smfile = GetSummaryFileName(encMethod, codecName, preset, summary_outpath) + wb = xlsxwriter.Workbook(smfile) + + # shts is for all scaling algorithms' convex hull test results + shts = [] + for dnsc, upsc in zip(dnScalAlgos, upScalAlgos): + shtname = dnsc + '--' + upsc + sht = wb.add_worksheet(shtname) + shts.append(sht) + + # below variables define summary file data layout format. + # if to change them, modify CopyResultsDataToSummaryFile_Onesheet() and + # CalcRowsCategAndContentDict() accordingly + colstart = 3 + colInterval = 2 + rowstart = 2 + + # cols is column number of results files + step = colInterval + 1 + len(QualityList) # 1 is for bitrate + sum_wtcols = [step * i + colstart for i in range(len(DnScaleRatio))] + # to generate rows number of starting of each class: rows_class + contentsdict, rows_class = CalcRowsClassAndContentDict(rowstart, + content_path, + clips, len(QPs)) + + wb.add_vba_project(VbaBinFile) + cellformat = wb.add_format() + cellformat.set_num_format('0.00%') + #cols_bdmtrs is the column number to write the bdrate data + step = len(QualityList) + 1 + start_col_bd = sum_wtcols[-1] + step + 1 + cols_bdmtrs = [start_col_bd + i * step for i in range(len(DnScaleRatio) - 1)] + # -1 because first resolution is used as reference + + for sht in shts: + CopyResultDataToSummaryFile_Onesheet(sht, sum_wtcols, contentsdict, + rows_class, infile_path) + # calculate bd rate in each scaling sheet + CalBDRate_OneSheet(sht, sum_wtcols, contentsdict, rows_class, + cols_bdmtrs, cellformat) + + # calculate average bitrate and quality metrics for each category and + # write to "average" sheet + WriteBitrateQtyAverageSheet(wb, shts, contentsdict, rows_class, sum_wtcols) + + # calculate average bd metrics and write to a new sheet + WriteBDRateAverageSheet(wb, shts, contentsdict, rows_class, cols_bdmtrs, + cellformat) + + wb.close() + return smfile + +def GenerateSummaryConvexHullExcelFile(encMethod, codecName, preset, + summary_outpath, DnScalingAlgos, + UpScalingAlgos): + if not os.path.exists(summary_outpath): + os.makedirs(summary_outpath) + smfile = GetConvexHullRDFileName(encMethod, codecName, preset, + summary_outpath) + sum_wb = xlsxwriter.Workbook(smfile) + + # shts is for all scaling algorithms' convex hull test results + sum_start_row = {} + #write the header in each sheet + for dnsc, upsc in zip(DnScalingAlgos, UpScalingAlgos): + shtname = dnsc + '--' + upsc + sht = sum_wb.add_worksheet(shtname) + sht.write(0, 0, 'Content Class') + sht.write(0, 1, 'Content Name') + sht.write(0, 2, 'Num RD Points') + col = 3 + for qty in QualityList: + sht.write(0, col, 'Bitrate(kbps)') + sht.write(0, col + 1, qty) + col += 2 + sum_start_row[shtname] = 1 + return sum_wb, sum_start_row
diff --git a/tools/convexhull_framework/src/ScalingTest.py b/tools/convexhull_framework/src/ScalingTest.py new file mode 100644 index 0000000..a8f4a7a --- /dev/null +++ b/tools/convexhull_framework/src/ScalingTest.py
@@ -0,0 +1,366 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os +import xlsxwriter +import xlrd +import logging +from CalculateQualityMetrics import CalculateQualityMetric, GatherQualityMetrics +from VideoScaler import GetDownScaledOutFile, DownScaling, UpScaling, GetUpScaledOutFile +from Config import DnScaleRatio, FrameNum, Clips, QualityList, LoggerName, Path_ScalingResults, ScalQty_WtCols, \ + ScalQty_startRow, LineColors, ScalSumQty_WtCols, ContentPath +from Utils import GetVideoInfo, Cleanfolder, GetShortContentName, CreateChart_Scatter, AddSeriesToChart_Scatter, UpdateChart, \ + InsertChartsToSheet, CalcRowsClassAndContentDict, GetContents, CreateChart_Line, AddSeriesToChart_Line + +subloggername = "ScalingTest" +loggername = LoggerName + '.' + '%s' % subloggername +logger = logging.getLogger(loggername) + +StatsMetrics = ['Max', 'Std+', 'Average', 'Std-', 'Min'] + +def GetScalingResultExcelFile(rationum, scalAlgoNum): + filename = "ScalingResults_RatioNum_%d_AlgoNum_%d.xlsx"\ + % (rationum, scalAlgoNum) + file = os.path.join(Path_ScalingResults, filename) + return file + +def GetScalingResultExcelFile_PerContent(content): + filename = GetShortContentName(content) + filename = "ScalingResults_%s.xlsx" % filename + file = os.path.join(Path_ScalingResults, filename) + return file + +def Run_Scaling_Test(content, dnScalAlgo, upScalAlgo, path_dnscl, path_upscl, + path_log, path_cfg, savememory, keepupscaledyuv): + logger.info("start running scaling tests with content %s" + % os.path.basename(content)) + cls, width, height, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips) + if totalnum < FrameNum: + logger.error("content %s includes total %d frames < specified % frames!" + % (content, totalnum, FrameNum)) + return + + DnScaledRes = [(int(width / ratio), int(height / ratio)) + for ratio in DnScaleRatio] + for i in range(len(DnScaledRes)): + if savememory: + Cleanfolder(path_cfg) + if not keepupscaledyuv: + Cleanfolder(path_upscl) + + DnScaledW = DnScaledRes[i][0] + DnScaledH = DnScaledRes[i][1] + logger.info("start downscaling content to %dx%d" + % (DnScaledW, DnScaledH)) + # downscaling + dnscalyuv = GetDownScaledOutFile(content, width, height, DnScaledW, + DnScaledH, path_dnscl, dnScalAlgo) + if not os.path.isfile(dnscalyuv): + dnscalyuv = DownScaling(content, FrameNum, width, height, DnScaledW, + DnScaledH, path_dnscl, dnScalAlgo) + + upscaleyuv = UpScaling(dnscalyuv, FrameNum, DnScaledW, DnScaledH, width, + height, path_upscl, upScalAlgo) + + CalculateQualityMetric(content, FrameNum, upscaleyuv, width, height, + path_log, path_cfg) + + if savememory: + Cleanfolder(path_dnscl) + + logger.info("finish running scaling test.") + +def GeneratePerContentExcelFile(dnScalAlgos, upScalAlgos, content, scaleRatios, + path_log): + contshortname = GetShortContentName(content) + logger.info("start generate excel file for content :%s" % contshortname) + excFile = GetScalingResultExcelFile_PerContent(content) + wb = xlsxwriter.Workbook(excFile) + shtname = contshortname + sht = wb.add_worksheet(shtname) + + sht.write(1, 0, 'Content Name') + sht.write(2, 0, contshortname) + sht.write(1, 1, 'Scaling Ratio') + sht.write_column(2, 1, scaleRatios) + pre_title = ['Width', 'Height', 'DnScaledWidth', 'DnScaledHeight'] + sht.write_row(1, 2, pre_title) + for dn_algo, up_algo, col in zip(dnScalAlgos, upScalAlgos, ScalQty_WtCols): + algos = dn_algo + '--' + up_algo + sht.write(0, col, algos) + sht.write_row(1, col, QualityList) + + cls, w, h, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips) + rows = [ScalQty_startRow + i for i in range(len(scaleRatios))] + continfos = [] + for ratio, row in zip(scaleRatios, rows): + dw = int(w / ratio) + dh = int(h / ratio) + info = [w, h, dw, dh] + sht.write_row(row, 2, info) + continfos.append(info) + + charts = []; y_mins = {}; y_maxs = {} + for qty, x in zip(QualityList, range(len(QualityList))): + chart_title = 'Scaling Quality - %s' % qty + xaxis_name = 'scaling ratio' + chart = CreateChart_Scatter(wb, chart_title, xaxis_name, qty) + charts.append(chart) + y_mins[x] = []; y_maxs[x] = [] + + for dn_algo, up_algo, col, i in zip(dnScalAlgos, upScalAlgos, ScalQty_WtCols, + range(len(dnScalAlgos))): + qualities = [] + seriname = dn_algo + '--' + up_algo + for ratio, row, idx in zip(scaleRatios, rows, range(len(scaleRatios))): + w = continfos[idx][0] + h = continfos[idx][1] + dw = continfos[idx][2] + dh = continfos[idx][3] + dnScalOut = GetDownScaledOutFile(content, w, h, dw, dh, + path_log, dn_algo) + upScalOut = GetUpScaledOutFile(dnScalOut, dw, dh, w, h, + path_log, up_algo) + qtys = GatherQualityMetrics(upScalOut, path_log) + sht.write_row(row, col, qtys) + qualities.append(qtys) + for x in range(len(QualityList)): + AddSeriesToChart_Scatter(shtname, rows, col + x, 1, charts[x], + seriname, LineColors[i]) + + # get min and max of y-axis for a certain dn up scaling algo + for qty, x in zip(QualityList, range(len(QualityList))): + qs = [row[x] for row in qualities] + y_mins[x].append(min(qs)) + y_maxs[x].append(max(qs)) + + for qty, x in zip(QualityList, range(len(QualityList))): + ymin = min(y_mins[x]) + ymax = max(y_maxs[x]) + margin = 0.1 # add 10% on min and max value for y_axis range + num_precsn = 5 if 'MS-SSIM' in qty else 3 + UpdateChart(charts[x], ymin, ymax, margin, qty, num_precsn) + + startrow = rows[-1] + 2; startcol = 1 + InsertChartsToSheet(sht, startrow, startcol, charts) + + wb.close() + logger.info("finish export scaling quality results to excel file.") + +def GenerateSummarySheet(wb, dnScalAlgos, upScalAlgos, ratio, contentsdict, + rows_class, path_log): + logger.info("start generate summary sheet for ratio %2.2f" % ratio) + + shts = [] + shtname = "Ratio=%1.2f" % ratio + sht = wb.add_worksheet(shtname) + shts.append(sht) + sht.write(1, 0, 'Content Class') + sht.write(1, 1, 'Content NO.') + sht.write(1, 2, 'Content Name') + pre_title = ['Width', 'Height', 'DnScaledWidth', 'DnScaledHeight'] + sht.write_row(1, 3, pre_title) + + for dn_algo, up_algo, col in zip(dnScalAlgos, upScalAlgos, ScalSumQty_WtCols): + algos = dn_algo + '--' + up_algo + sht.write(0, col, algos) + sht.write_row(1, col, QualityList) + + content_infos = {}; totalnum_contents = 0 + for (clss, contents), row_clss in zip(contentsdict.items(), rows_class): + sht.write(row_clss, 0, clss) + totalnum_contents = totalnum_contents + len(contents) + for content, row_cont in zip(contents, range(len(contents))): + cl, w, h, fr, bitdepth, fmt, totalnum = GetVideoInfo(content, Clips) + dw = int(w / ratio) + dh = int(h / ratio) + shortcntname = GetShortContentName(content) + sht.write(row_clss + row_cont, 2, shortcntname) + infos = [w, h, dw, dh] + sht.write_row(row_clss + row_cont, 3, infos) + content_infos[shortcntname] = infos + + charts = []; y_mins = {}; y_maxs = {} + for qty, x in zip(QualityList, range(len(QualityList))): + chart_title = '%s of %s' % (qty, shtname) + chart = CreateChart_Scatter(wb, chart_title, 'Contents', qty) + charts.append(chart) + y_mins[x] = []; y_maxs[x] = [] + + rows_all = [ScalQty_startRow + i for i in range(totalnum_contents)] + sht.write_column(ScalQty_startRow, 1, range(totalnum_contents)) + for dn_algo, up_algo, col, i in zip(dnScalAlgos, upScalAlgos, + ScalSumQty_WtCols, + range(len(dnScalAlgos))): + qualities = [] + seriname = dn_algo + '--' + up_algo + for (clss, contents), row_clss in zip(contentsdict.items(), rows_class): + for content, row_cont in zip(contents, range(len(contents))): + key = GetShortContentName(content) + w = content_infos[key][0] + h = content_infos[key][1] + dw = content_infos[key][2] + dh = content_infos[key][3] + dnScalOut = GetDownScaledOutFile(content, w, h, dw, dh, + path_log, dn_algo) + upScalOut = GetUpScaledOutFile(dnScalOut, dw, dh, w, h, + path_log, up_algo) + qtys = GatherQualityMetrics(upScalOut, path_log) + sht.write_row(row_clss + row_cont, col, qtys) + qualities.append(qtys) + + for x in range(len(QualityList)): + AddSeriesToChart_Scatter(shtname, rows_all, col + x, 1, charts[x], + seriname, LineColors[i]) + + # get min and max of y-axis for a certain dn up scaling algo + for qty, x in zip(QualityList, range(len(QualityList))): + qs = [row[x] for row in qualities] + y_mins[x].append(min(qs)) + y_maxs[x].append(max(qs)) + + for qty, x in zip(QualityList, range(len(QualityList))): + ymin = min(y_mins[x]) + ymax = max(y_maxs[x]) + margin = 0.1 # add 10% on min and max value for y_axis range + num_precsn = 5 if 'MS-SSIM' in qty else 3 + UpdateChart(charts[x], ymin, ymax, margin, qty, num_precsn) + + startrow = rows_all[-1] + 2; startcol = 1 + InsertChartsToSheet(sht, startrow, startcol, charts) + logger.info("finish average sheet for ratio:%2.2f." % ratio) + + return sht + +def GenerateAverageSheet(wb, sumsht, dnScalAlgos, upScalAlgos, ratio, + contentsdict, rows_class): + logger.info("start generate average sheet for ratio %2.2f" % ratio) + + rdsht = sumsht + rdshtname = rdsht.get_name() + shtname = "AverageForRatio=%1.2f" % ratio + sht = wb.add_worksheet(shtname) + sht.write(1, 0, 'QualityMetrics') + sht.write(1, 1, 'Content Class') + sht.write(1, 2, 'Content Number') + + interval = 1 + step = len(StatsMetrics) + interval + startcol = 3 + cols_avg = [startcol + step * i for i in range(len(dnScalAlgos))] + for col, dn_algo, up_algo in zip(cols_avg, dnScalAlgos, upScalAlgos): + algos = dn_algo + '--' + up_algo + sht.write(0, col, algos) + sht.write_row(1, col, StatsMetrics) + + step = len(contentsdict) + 1 # 1 extra row for total of each class + startrow = 2 + rows_qtymtr = [startrow + step * i for i in range(len(QualityList))] + for qty, row_qm, y in zip(QualityList, rows_qtymtr, range(len(QualityList))): + sht.write(row_qm, 0, qty) + + #charts = [] + #titlename = 'Quality Statistics %s' % qty + #chart = CreateChart_Line(wb, titlename, qty) + #charts.append(chart) + + totalnum_contents = 0 + for (cls, contents), idx, rdrow_cls in zip(contentsdict.items(), + range(len(contentsdict)), + rows_class): + sht.write(row_qm + idx, 1, cls) + num_content = len(contents) + totalnum_contents = totalnum_contents + num_content + sht.write(row_qm + idx, 2, num_content) + for rdcol, wtcol in zip(ScalSumQty_WtCols, cols_avg): + startcell = xlrd.cellname(rdrow_cls, rdcol + y) + endcell = xlrd.cellname(rdrow_cls + num_content - 1, rdcol + y) + formula = '=MAX(\'%s\'!%s:%s)' % (rdshtname, startcell, endcell) + sht.write(row_qm + idx, wtcol, formula) + + formula = '=SUM(\'%s\'!%s:%s)/%d' % (rdshtname, startcell, + endcell, num_content) + sht.write(row_qm + idx, wtcol + 2, formula) + + formula = '=MIN(\'%s\'!%s:%s)' % (rdshtname, startcell, endcell) + sht.write(row_qm + idx, wtcol + 4, formula) + + avgcell = xlrd.cellname(row_qm + idx, wtcol + 2) + formula = '= %s + _xlfn.STDEV.P(\'%s\'!%s:%s)'\ + % (avgcell, rdshtname, startcell, endcell) + sht.write(row_qm + idx, wtcol + 1, formula) + + formula = '= %s - _xlfn.STDEV.P(\'%s\'!%s:%s)'\ + % (avgcell, rdshtname, startcell, endcell) + sht.write(row_qm + idx, wtcol + 3, formula) + + #write total contents statistics + wtrow = row_qm + len(contentsdict) + sht.write(wtrow, 1, 'Total') + sht.write(wtrow, 2, totalnum_contents) + for rdcol, wtcol in zip(ScalSumQty_WtCols, cols_avg): + startcell = xlrd.cellname(ScalQty_startRow, rdcol + y) + endcell = xlrd.cellname(ScalQty_startRow + totalnum_contents - 1, + rdcol + y) + formula = '=MAX(\'%s\'!%s:%s)' % (rdshtname, startcell, endcell) + sht.write(wtrow, wtcol, formula) + + formula = '=SUM(\'%s\'!%s:%s)/%d'\ + % (rdshtname, startcell, endcell, totalnum_contents) + sht.write(wtrow, wtcol + 2, formula) + + formula = '=MIN(\'%s\'!%s:%s)' % (rdshtname, startcell, endcell) + sht.write(wtrow, wtcol + 4, formula) + + avgcell = xlrd.cellname(wtrow, wtcol + 2) + formula = '= %s + _xlfn.STDEV.P(\'%s\'!%s:%s)'\ + % (avgcell, rdshtname, startcell, endcell) + sht.write(wtrow, wtcol + 1, formula) + + formula = '= %s - _xlfn.STDEV.P(\'%s\'!%s:%s)'\ + % (avgcell, rdshtname, startcell, endcell) + sht.write(wtrow, wtcol + 3, formula) + + logger.info("finish average sheet for ratio:%2.2f." % ratio) + + +def SaveScalingResultsToExcel(dnScalAlgos, upScalAlgos, path_log): + logger.info("start saving scaling quality results to excel files.......") + if not os.path.exists(Path_ScalingResults): + os.makedirs(Path_ScalingResults) + + logger.info("start generating per content scaling quality excel file.......") + contents = GetContents(ContentPath, Clips) + for content in contents: + GeneratePerContentExcelFile(dnScalAlgos, upScalAlgos, content, + DnScaleRatio, path_log) + + scaleRatios = DnScaleRatio + scaleRatios.remove(1.0) + logger.info("start generating scaling quality summary excel file.......") + sumexcFile = GetScalingResultExcelFile(len(scaleRatios), len(DnScaleRatio)) + wb = xlsxwriter.Workbook(sumexcFile) + # to generate rows number of starting of each class: rows_class + contentsdict, rows_class = CalcRowsClassAndContentDict(ScalQty_startRow, + ContentPath, Clips) + + sumShts = [] + for ratio in scaleRatios: + sht = GenerateSummarySheet(wb, dnScalAlgos, upScalAlgos, ratio, + contentsdict, rows_class, path_log) + sumShts.append(sht) + for ratio, sumsht in zip(scaleRatios, sumShts): + GenerateAverageSheet(wb, sumsht, dnScalAlgos, upScalAlgos, ratio, + contentsdict, rows_class) + + wb.close() + logger.info("finish saving scaling quality results to excel files.......")
diff --git a/tools/convexhull_framework/src/Utils.py b/tools/convexhull_framework/src/Utils.py new file mode 100644 index 0000000..632b1a9 --- /dev/null +++ b/tools/convexhull_framework/src/Utils.py
@@ -0,0 +1,266 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os +import re +import xlrd +import subprocess +import time +import logging +from Config import LogLevels, Have_Class_Subfolder + +def Cleanfolder(folder): + if os.path.isdir(folder): + for f in os.listdir(folder): + file = os.path.join(folder, f) + if os.path.isfile(file): + os.remove(file) + +def CreateNewSubfolder(parent, name): + if name == '' or name == None: + return None + folder = os.path.join(parent, name) + if not os.path.exists(folder): + os.makedirs(folder) + return folder + +def GetShortContentName(content, isshort=True): + basename = os.path.splitext(os.path.basename(content))[0] + if isshort: + item = re.findall(r"([a-zA-Z0-9]+)_", basename) + if len(item) == 0: + name = basename + else: + name = item[0] + else: + name = basename + return name + +def GetContents(contentpath, clips): + contents = [] + for key, val in clips.items(): + folder = contentpath + if Have_Class_Subfolder: + cls = val[0] + folder = os.path.join(contentpath, cls) + + file = os.path.join(folder, key) + ".yuv" + if os.path.isfile(file): + contents.append(file) + + return contents + +def GetVideoInfo(content, Clips): + basename = GetShortContentName(content, False) + cls = Clips[basename][0] + width = Clips[basename][1] + height = Clips[basename][2] + fr = Clips[basename][3] + bitdepth = Clips[basename][4] + fmt = Clips[basename][5] + + #default for 8 bit 420 + RatioForFrameSize = 3/2 + if fmt == 'yuv422p': + RatioForFrameSize = 2 + elif fmt == 'yuv444p': + RatioForFrameSize = 3 + if bitdepth > 8: + RatioForFrameSize *= 2 + + totalnum = os.path.getsize(content) / (width * height * RatioForFrameSize) + + return cls, width, height, fr, bitdepth, fmt, totalnum + +def GetContentDict(contentpath, clips): + dict = {} + + if Have_Class_Subfolder: + for key, val in clips.items(): + cls = val[0] + folder = os.path.join(contentpath, cls) + file = os.path.join(folder, key) + ".yuv" + if os.path.isfile(file): + if cls in dict: + if file not in dict[cls]: + dict[cls].append(file) + else: + dict[cls] = [file] + else: + # this is for case no subfolder/class. As * is forbidden for folder name, + # no folder will be same as this + cls = "*All" + dict[cls] = GetContents(contentpath, clips) + + return dict + +def CalcRowsClassAndContentDict(rowstart, content_path, clips, times=1): + contentsdict = GetContentDict(content_path, clips) + + ofstc = rowstart + rows_class = [] + for cls, contents in contentsdict.items(): + rows_class.append(ofstc) + ofstc = ofstc + len(contents) * times + + return contentsdict, rows_class + +def SweepScalingAlgosInOneResultFile(infile_path): + dnscls = [] + upscls = [] + resultfiles = os.listdir(infile_path) + # here assume all result files includes same combinations of dn and up + # scaling algos + file = os.path.join(infile_path, resultfiles[0]) + if os.path.isfile(file): + rdwb = xlrd.open_workbook(os.path.join(infile_path, resultfiles[0])) + else: + return dnscls, upscls + if rdwb is not None: + shtnms = rdwb.sheet_names() + for shtname in shtnms: + item = re.findall(r"(.+)\-\-(.+)", shtname) + dnsl = item[0][0] + upsl = item[0][1] + dnscls.append(dnsl) + upscls.append(upsl) + + return dnscls, upscls + +def CreateChart_Scatter(wb, title, xaxis_name, yaxis_name): + chart = wb.add_chart({'type': 'scatter', 'subtype': 'straight_with_markers'}) + chart.set_title({'name': title, 'name_font': {'color': 'white'}}) + chart.set_x_axis({'name': xaxis_name, + 'major_gridlines': {'visible': True, 'line': {'width': 0.25}}, + 'name_font': {'color': 'white'}, + 'num_font': {'color': 'white', 'transparency': 80}, + 'label_position' : 'low' + }) + chart.set_y_axis({'name': yaxis_name, 'name_font': {'color': 'white'}, + 'num_font': {'color': 'white'}}) + chart.set_style(12) + chart.set_size({'x_scale': 1.5, 'y_scale': 1.5}) + chart.set_chartarea({"fill": {'color': '#505050'}}) + chart.set_plotarea({"fill": {'color': '#505050'}}) + chart.set_legend({'position': 'bottom', 'font': {'color': 'white'}}) + return chart + +def CreateChart_Line(wb, titlename, yaxis_name): + chart = wb.add_chart({'type': 'line', 'name_font': {'size': 10.5}}) + chart.set_title({'name': titlename}) + chart.set_x_axis({'text_axis': True}) + chart.set_y_axis({'name': yaxis_name, 'name_font': {'size': 11}}) + chart.set_size({'x_scale': 1.4, 'y_scale': 1.5}) + chart.set_legend({'position': 'right', 'font': {'size': 10.5}}) + chart.set_high_low_lines( + {'line': {'color': 'black', 'size': 2}} + ) + return chart + +def AddSeriesToChart_Scatter(shtname, rows, coly, colx, chart, seriname, + linecolor): + yvalues = [shtname, rows[0], coly, rows[-1], coly] + xvalues = [shtname, rows[0], colx, rows[-1], colx] + + chart.add_series({ + 'name': seriname, + 'categories': xvalues, + 'values': yvalues, + 'line': {'color': linecolor, 'width': 1.5}, + 'marker': {'type': 'circle', 'size': 5, + 'border': {'color': linecolor, 'size': 0.75}, + 'fill': {'color': linecolor}}, + }) + +def AddSeriesToChart_Scatter_Rows(shtname, cols, rowy, rowx, chart, seriname, + linecolor): + yvalues = [shtname, rowy, cols[0], rowy, cols[-1]] + xvalues = [shtname, rowx, cols[0], rowx, cols[-1]] + + chart.add_series({ + 'name': seriname, + 'categories': xvalues, + 'values': yvalues, + 'line': {'color': linecolor, 'width': 1.0, 'dash_type': 'dash_dot'}, + 'marker': {'type': 'square', 'size': 5, + 'border': {'color': 'white', 'size': 0.75}} + }) + +def AddSeriesToChart_Line(shtname, rows, coly, colx, chart, seriname, shape, + ssize, linecolor): + yvalues = [shtname, rows[0], coly, rows[-1], coly] + xvalues = [shtname, rows[0], colx, rows[-1], colx] + chart.add_series({ + 'name': seriname, + 'categories': xvalues, + 'values': yvalues, + 'line': {'none': True}, + 'marker': {'type': shape, + 'size': ssize, + 'border': {'color': linecolor, 'size': 2}, + 'fill': {'color': linecolor}}, + }) + +def UpdateChart(chart, ymin, ymax, margin, yaxis_name, precsn): + interval = ymax - ymin + finalmax = ymax + interval * margin + finalmin = ymin - interval * margin + floatprecn = "{:.%df}" % precsn + finalmin = float(floatprecn.format(finalmin)) + finalmax = float(floatprecn.format(finalmax)) + chart.set_y_axis({'name': yaxis_name, + 'name_font': {'color': 'white'}, + 'num_font': {'color': 'white'}, + 'min': finalmin, 'max': finalmax}) + +def InsertChartsToSheet(sht, startrow, startcol, charts): + height = 22 + width = 12 + num = len(charts) + row = startrow + for i in range(1, num, 2): + sht.insert_chart(row, startcol, charts[i - 1]) + sht.insert_chart(row, startcol + width, charts[i]) + row = row + height + +def ExecuteCmd(cmd, LogCmdOnly): + CmdLogger.write(cmd + "\n") + ret = 0 + if not LogCmdOnly: + ret = subprocess.call(cmd, shell=True) + return ret + +def SetupLogging(level, logcmdonly, name, path): + global Logger + Logger = logging.getLogger(name) + + if logcmdonly or level != 0: + global CmdLogger + logfilename = os.path.join(path, 'ConvexHullTestCmd_%s.log' + % time.strftime("%Y%m%d-%H%M%S")) + CmdLogger = open(logfilename, 'w') + + if level != 0: + logfilename = os.path.join(path, 'ConvexHullTest_%s.log' + % time.strftime("%Y%m%d-%H%M%S")) + hdlr = logging.FileHandler(logfilename) + formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") + hdlr.setFormatter(formatter) + Logger.addHandler(hdlr) + if level in range(len(LogLevels)): + # valid level input parameter + lvl = LogLevels[level] + levelname = logging.getLevelName(lvl) + else: + # if not valid, default set to 'INFO' + levelname = logging.getLevelName('INFO') + Logger.setLevel(levelname)
diff --git a/tools/convexhull_framework/src/VideoDecoder.py b/tools/convexhull_framework/src/VideoDecoder.py new file mode 100644 index 0000000..84146bd --- /dev/null +++ b/tools/convexhull_framework/src/VideoDecoder.py
@@ -0,0 +1,33 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import Utils +from Config import BinPath, LogCmdOnly, FFMPEG, AOMDEC +from Utils import ExecuteCmd + +#use ffmpeg to decode bitstream +def DecodeWithFfmpeg(infile, outfile): + args = " -y -i %s -pix_fmt yuv420p -c:v rawvideo %s" % (infile, outfile) + cmd = FFMPEG + args + ExecuteCmd(cmd, LogCmdOnly) + +def DecodeWithAOM(infile, outfile): + args = " --codec=av1 --i420 --rawvideo --summary -o %s %s" % (outfile, infile) + cmd = AOMDEC + args + ExecuteCmd(cmd, LogCmdOnly) + +def VideoDecode(codec, infile, outfile): + Utils.CmdLogger.write("::Decode\n") + if codec == 'AV1': + DecodeWithAOM(infile, outfile) + else: + DecodeWithFfmpeg(infile, outfile)
diff --git a/tools/convexhull_framework/src/VideoEncoder.py b/tools/convexhull_framework/src/VideoEncoder.py new file mode 100644 index 0000000..8bbf32c --- /dev/null +++ b/tools/convexhull_framework/src/VideoEncoder.py
@@ -0,0 +1,80 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import Utils +from Config import BinPath, LogCmdOnly, FFMPEG, AOMENC, SVTAV1, SVTHEVC +from Utils import ExecuteCmd + +#use ffmpeg to encode video +def EncodeWithFfmpeg_HEVC(infile, QP, num,fr, width, height, outfile, preset): + EncodeProfile = 'main' + args = " -y -s %dx%d -pix_fmt yuv420p -r %s -i %s -frames:v %d -g %d -bf 7" \ + " -bsf:v hevc_mp4toannexb -c:v libx265 -preset %s -profile:v %s " \ + "-x265-params \"qp=%d:aq-mode=0:b-adapt=0:bframes=7:b-pyramid=1:" \ + "no-scenecut=1:no-open-gop=1:input-depth=8:output-depth=8\" %s" % ( + width, height, fr, infile, num, int(2 * fr), # gop size = 2 seconds + preset, EncodeProfile, (QP+3), outfile) + cmd = FFMPEG + args + ExecuteCmd(cmd, LogCmdOnly) + +def EncodeWithAOM_AV1(infile, QP, framenum, framerate, width, height, outfile, + preset): + args = " --codec=av1 -v --psnr --ivf --frame-parallel=0 --cpu-used=%s" \ + " --limit=%d --auto-alt-ref=1 --passes=2 " \ + "--threads=1 --lag-in-frames=25 --end-usage=q --cq-level=%d" \ + " -w %d -h %d -o %s %s"\ + % (preset, framenum, QP, width, height, outfile, infile) + cmd = AOMENC + args + ExecuteCmd(cmd, LogCmdOnly) + +def EncodeWithSVT_AV1(infile, QP, framenum, framerate, width, height, outfile, + preset): + args = " --preset %s --scm 2 --lookahead 0 --hierarchical-levels 3 -n %d" \ + " --keyint 255 -rc 0 -q %d -w %d -h %d -b %s -i %s"\ + % (str(preset), framenum, QP, width, height, outfile, infile) + cmd = SVTAV1 + args + ExecuteCmd(cmd, LogCmdOnly) + +def EncodeWithSVT_HEVC(infile, QP, framenum, framerate, width, height, outfile, + preset): + args = " -i %s -w %d -h %d -encMode %s -hierarchical-levels 3" \ + " -intra-period 100 -scd 0 -rc 0 -q %d -n %d -b %s"\ + % (infile, width, height, preset, QP, framenum, outfile) + cmd = SVTHEVC + args + ExecuteCmd(cmd, LogCmdOnly) + +def VideoEncode(EncodeMethod, CodecName, infile, QP, framenum, framerate, width, + height, outfile, preset): + Utils.CmdLogger.write("::Encode\n") + if EncodeMethod == "ffmpeg": + if CodecName == 'hevc': + EncodeWithFfmpeg_HEVC(infile, QP, framenum, framerate, width, height, + outfile, preset) + else: + raise ValueError("invalid parameter for encode.") + elif EncodeMethod == "aom": + if CodecName == 'av1': + EncodeWithAOM_AV1(infile, QP, framenum, framerate, width, height, + outfile, preset) + else: + raise ValueError("invalid parameter for encode.") + elif EncodeMethod == "svt": + if CodecName == 'av1': + EncodeWithSVT_AV1(infile, QP, framenum, framerate, width, height, + outfile, preset) + elif CodecName == 'hevc': + EncodeWithSVT_HEVC(infile, QP, framenum, framerate, width, height, + outfile, preset) + else: + raise ValueError("invalid parameter for encode.") + else: + raise ValueError("invalid parameter for encode.")
diff --git a/tools/convexhull_framework/src/VideoScaler.py b/tools/convexhull_framework/src/VideoScaler.py new file mode 100644 index 0000000..2420d1b --- /dev/null +++ b/tools/convexhull_framework/src/VideoScaler.py
@@ -0,0 +1,88 @@ +#!/usr/bin/env python +## Copyright (c) 2019, Alliance for Open Media. All rights reserved +## +## This source code is subject to the terms of the BSD 2 Clause License and +## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +## was not distributed with this source code in the LICENSE file, you can +## obtain it at www.aomedia.org/license/software. If the Alliance for Open +## Media Patent License 1.0 was not distributed with this source code in the +## PATENTS file, you can obtain it at www.aomedia.org/license/patent. +## +__author__ = "maggie.sun@intel.com, ryan.lei@intel.com" + +import os +import Utils +import logging +from Config import BinPath, LogCmdOnly, LoggerName, FFMPEG +from Utils import GetShortContentName, ExecuteCmd + +subloggername = "VideoScaler" +loggername = LoggerName + '.' + '%s' % subloggername +logger = logging.getLogger(loggername) + +def ValidAlgo_ffmpeg(algo): + if (algo == 'bicubic' or algo == 'lanczos' or algo == 'sinc' or + algo == 'bilinear' or algo == 'spline' or algo == 'gauss' or + algo == 'bicublin' or algo == 'neighbor'): + return True + else: + return False + +#use ffmpeg to do image rescaling for yuv420 8bit +def RescaleWithFfmpeg(infile, inw, inh, outw, outh, algo, outfile, num, app_path): + args = " -y -s:v %dx%d -i %s -vf scale=%dx%d -c:v rawvideo -pix_fmt yuv420p" \ + " -sws_flags %s+accurate_rnd+full_chroma_int -sws_dither none" \ + % (inw, inh, infile, outw, outh, algo) + if (algo == 'lanczos'): + args += " -param0 5 " + args += " -frames %d %s" % (num, outfile) + cmd = FFMPEG + args + ExecuteCmd(cmd, LogCmdOnly) + +def VideoRescaling(infile, num, inw, inh, outw, outh, outfile, algo): + if ValidAlgo_ffmpeg(algo): + RescaleWithFfmpeg(infile, inw, inh, outw, outh, algo, outfile, num, BinPath) + # add other tools for scaling here later + else: + logger.error("unsupported scaling algorithm.") + +#################################################################################### +##################### Major Functions ################################################ +def GetDownScaledOutFile(input, inw, inh, dnw, dnh, path, algo): + contentBaseName = GetShortContentName(input) + actual_algo = 'None' if inw == dnw and inh == dnh else algo + filename = contentBaseName + ('_DnScaled_%s_%dx%d.yuv' % (actual_algo, dnw, + dnh)) + dnscaledout = os.path.join(path, filename) + return dnscaledout + +def GetUpScaledOutFile(infile, inw, inh, outw, outh, path, algo): + actual_algo = 'None' if inw == outw and inh == outh else algo + filename = GetShortContentName(infile, False) + ('_UpScaled_%s_%dx%d.yuv' + % (actual_algo, outw, outh)) + upscaledout = os.path.join(path, filename) + return upscaledout + +def DownScaling(input, num, inw, inh, outw, outh, path, algo): + dnScalOut = GetDownScaledOutFile(input, inw, inh, outw, outh, path, algo) + + Utils.CmdLogger.write("::Downscaling\n") + if (inw == outw and inh == outh): + cmd = "copy %s %s" % (input, dnScalOut) + ExecuteCmd(cmd, LogCmdOnly) + else: + # call separate process to do the downscaling + VideoRescaling(input, num, inw, inh, outw, outh, dnScalOut, algo) + return dnScalOut + +def UpScaling(infile, num, inw, inh, outw, outh, path, algo): + upScaleOut = GetUpScaledOutFile(infile, inw, inh, outw, outh, path, algo) + + Utils.CmdLogger.write("::Upscaling\n") + if (inw == outw and inh == outh): + cmd = "copy %s %s" % (infile, upScaleOut) + ExecuteCmd(cmd, LogCmdOnly) + else: + # call separate process to do the upscaling + VideoRescaling(infile, num, inw, inh, outw, outh, upScaleOut, algo) + return upScaleOut