diff --git a/configure b/configure index dfc3ffd35..1894cb47d 100755 --- a/configure +++ b/configure @@ -34,10 +34,7 @@ Advanced options: ${toggle_internal_stats} output of encoder internal stats for debug, if supported (encoders) ${toggle_mem_tracker} track memory usage ${toggle_postproc} postprocessing - ${toggle_multithread} multithreaded encoding and decoding. ${toggle_spatial_resampling} spatial sampling (scaling) support - ${toggle_realtime_only} enable this option while building for real-time encoding - ${toggle_error_concealment} enable this option to get a decoder which is able to conceal losses ${toggle_runtime_cpu_detect} runtime cpu detection ${toggle_shared} shared library support ${toggle_static} static library support @@ -159,7 +156,6 @@ enable optimizations enable fast_unaligned #allow unaligned accesses, if supported by hw enable md5 enable spatial_resampling -enable multithread enable os_support [ -d ${source_path}/../include ] && enable alt_tree_layout @@ -217,7 +213,16 @@ HAVE_LIST=" unistd_h " EXPERIMENT_LIST=" - extend_qrange + t8x8 + csm + qimode + uvintra + compred + enhanced_interp + featureupdates + high_precision_mv + sixteenth_subpel_uv + comp_intra_pred " CONFIG_LIST=" external_build @@ -246,7 +251,6 @@ CONFIG_LIST=" dc_recon runtime_cpu_detect postproc - multithread internal_stats ${CODECS} ${CODEC_FAMILIES} @@ -254,8 +258,6 @@ CONFIG_LIST=" decoders static_msvcrt spatial_resampling - realtime_only - error_concealment shared static small @@ -292,15 +294,12 @@ CMDLINE_SELECT=" dequant_tokens dc_recon postproc - multithread internal_stats ${CODECS} ${CODEC_FAMILIES} static_msvcrt mem_tracker spatial_resampling - realtime_only - error_concealment shared static small @@ -393,7 +392,6 @@ process_targets() { enabled debug_libs && DIST_DIR="${DIST_DIR}-debug" enabled codec_srcs && DIST_DIR="${DIST_DIR}-src" ! enabled postproc && DIST_DIR="${DIST_DIR}-nopost" - ! enabled multithread && DIST_DIR="${DIST_DIR}-nomt" ! enabled install_docs && DIST_DIR="${DIST_DIR}-nodocs" DIST_DIR="${DIST_DIR}-${tgt_isa}-${tgt_os}" case "${tgt_os}" in diff --git a/examples.mk b/examples.mk index b6bf882e5..934e828df 100644 --- a/examples.mk +++ b/examples.mk @@ -16,7 +16,7 @@ UTILS-$(CONFIG_DECODERS) += vpxdec.c vpxdec.SRCS += md5_utils.c md5_utils.h vpxdec.SRCS += vpx_ports/vpx_timer.h vpxdec.SRCS += vpx/vpx_integer.h -vpxdec.SRCS += args.c args.h +vpxdec.SRCS += args.c args.h vpx_ports/config.h vpxdec.SRCS += tools_common.c tools_common.h vpxdec.SRCS += nestegg/halloc/halloc.h vpxdec.SRCS += nestegg/halloc/src/align.h @@ -30,7 +30,7 @@ vpxdec.DESCRIPTION = Full featured decoder UTILS-$(CONFIG_ENCODERS) += vpxenc.c vpxenc.SRCS += args.c args.h y4minput.c y4minput.h vpxenc.SRCS += tools_common.c tools_common.h -vpxenc.SRCS += vpx_ports/mem_ops.h +vpxenc.SRCS += vpx_ports/config.h vpx_ports/mem_ops.h vpxenc.SRCS += vpx_ports/mem_ops_aligned.h vpxenc.SRCS += libmkv/EbmlIDs.h vpxenc.SRCS += libmkv/EbmlWriter.c @@ -77,11 +77,6 @@ GEN_EXAMPLES-$(CONFIG_ENCODERS) += decode_with_drops.c endif decode_with_drops.GUID = CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26 decode_with_drops.DESCRIPTION = Drops frames while decoding -ifeq ($(CONFIG_DECODERS),yes) -GEN_EXAMPLES-$(CONFIG_ERROR_CONCEALMENT) += decode_with_partial_drops.c -endif -decode_with_partial_drops.GUID = 61C2D026-5754-46AC-916F-1343ECC5537E -decode_with_partial_drops.DESCRIPTION = Drops parts of frames while decoding GEN_EXAMPLES-$(CONFIG_ENCODERS) += error_resilient.c error_resilient.GUID = DF5837B9-4145-4F92-A031-44E4F832E00C error_resilient.DESCRIPTION = Error Resiliency Feature diff --git a/examples/decode_with_partial_drops.txt b/examples/decode_with_partial_drops.txt deleted file mode 100644 index 7b0d3d2ca..000000000 --- a/examples/decode_with_partial_drops.txt +++ /dev/null @@ -1,238 +0,0 @@ -@TEMPLATE decoder_tmpl.c -Decode With Partial Drops Example -========================= -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION -This is an example utility which drops a series of frames (or parts of frames), -as specified on the command line. This is useful for observing the error -recovery features of the codec. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES -#include -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS -struct parsed_header -{ - char key_frame; - int version; - char show_frame; - int first_part_size; -}; - -int next_packet(struct parsed_header* hdr, int pos, int length, int mtu) -{ - int size = 0; - int remaining = length - pos; - /* Uncompressed part is 3 bytes for P frames and 10 bytes for I frames */ - int uncomp_part_size = (hdr->key_frame ? 10 : 3); - /* number of bytes yet to send from header and the first partition */ - int remainFirst = uncomp_part_size + hdr->first_part_size - pos; - if (remainFirst > 0) - { - if (remainFirst <= mtu) - { - size = remainFirst; - } - else - { - size = mtu; - } - - return size; - } - - /* second partition; just slot it up according to MTU */ - if (remaining <= mtu) - { - size = remaining; - return size; - } - return mtu; -} - -void throw_packets(unsigned char* frame, int* size, int loss_rate, - int* thrown, int* kept) -{ - unsigned char loss_frame[256*1024]; - int pkg_size = 1; - int pos = 0; - int loss_pos = 0; - struct parsed_header hdr; - unsigned int tmp; - int mtu = 1500; - - if (*size < 3) - { - return; - } - putc('|', stdout); - /* parse uncompressed 3 bytes */ - tmp = (frame[2] << 16) | (frame[1] << 8) | frame[0]; - hdr.key_frame = !(tmp & 0x1); /* inverse logic */ - hdr.version = (tmp >> 1) & 0x7; - hdr.show_frame = (tmp >> 4) & 0x1; - hdr.first_part_size = (tmp >> 5) & 0x7FFFF; - - /* don't drop key frames */ - if (hdr.key_frame) - { - int i; - *kept = *size/mtu + ((*size % mtu > 0) ? 1 : 0); /* approximate */ - for (i=0; i < *kept; i++) - putc('.', stdout); - return; - } - - while ((pkg_size = next_packet(&hdr, pos, *size, mtu)) > 0) - { - int loss_event = ((rand() + 1.0)/(RAND_MAX + 1.0) < loss_rate/100.0); - if (*thrown == 0 && !loss_event) - { - memcpy(loss_frame + loss_pos, frame + pos, pkg_size); - loss_pos += pkg_size; - (*kept)++; - putc('.', stdout); - } - else - { - (*thrown)++; - putc('X', stdout); - } - pos += pkg_size; - } - memcpy(frame, loss_frame, loss_pos); - memset(frame + loss_pos, 0, *size - loss_pos); - *size = loss_pos; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT -/* Initialize codec */ -flags = VPX_CODEC_USE_ERROR_CONCEALMENT; -res = vpx_codec_dec_init(&codec, interface, &dec_cfg, flags); -if(res) - die_codec(&codec, "Failed to initialize decoder"); - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT - -Usage ------ -This example adds a single argument to the `simple_decoder` example, -which specifies the range or pattern of frames to drop. The parameter is -parsed as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE -if(argc < 4 || argc > 6) - die("Usage: %s [-t ] \n", - argv[0]); -{ - char *nptr; - int arg_num = 3; - if (argc == 6 && strncmp(argv[arg_num++], "-t", 2) == 0) - dec_cfg.threads = strtol(argv[arg_num++], NULL, 0); - n = strtol(argv[arg_num], &nptr, 0); - mode = (*nptr == '\0' || *nptr == ',') ? 2 : (*nptr == '-') ? 1 : 0; - - m = strtol(nptr+1, NULL, 0); - if((!n && !m) || (*nptr != '-' && *nptr != '/' && - *nptr != '\0' && *nptr != ',')) - die("Couldn't parse pattern %s\n", argv[3]); -} -seed = (m > 0) ? m : (unsigned int)time(NULL); -srand(seed);thrown_frame = 0; -printf("Seed: %u\n", seed); -printf("Threads: %d\n", dec_cfg.threads); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE - - -Dropping A Range Of Frames --------------------------- -To drop a range of frames, specify the starting frame and the ending -frame to drop, separated by a dash. The following command will drop -frames 5 through 10 (base 1). - - $ ./decode_with_partial_drops in.ivf out.i420 5-10 - - -Dropping A Pattern Of Frames ----------------------------- -To drop a pattern of frames, specify the number of frames to drop and -the number of frames after which to repeat the pattern, separated by -a forward-slash. The following command will drop 3 of 7 frames. -Specifically, it will decode 4 frames, then drop 3 frames, and then -repeat. - - $ ./decode_with_partial_drops in.ivf out.i420 3/7 - -Dropping Random Parts Of Frames -------------------------------- -A third argument tuple is available to split the frame into 1500 bytes pieces -and randomly drop pieces rather than frames. The frame will be split at -partition boundaries where possible. The following example will seed the RNG -with the seed 123 and drop approximately 5% of the pieces. Pieces which -are depending on an already dropped piece will also be dropped. - - $ ./decode_with_partial_drops in.ivf out.i420 5,123 - - -Extra Variables ---------------- -This example maintains the pattern passed on the command line in the -`n`, `m`, and `is_range` variables: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS -int n, m, mode; -unsigned int seed; -int thrown=0, kept=0; -int thrown_frame=0, kept_frame=0; -vpx_codec_dec_cfg_t dec_cfg = {0}; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS - - -Making The Drop Decision ------------------------- -The example decides whether to drop the frame based on the current -frame number, immediately before decoding the frame. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE -/* Decide whether to throw parts of the frame or the whole frame - depending on the drop mode */ -thrown_frame = 0; -kept_frame = 0; -switch (mode) -{ -case 0: - if (m - (frame_cnt-1)%m <= n) - { - frame_sz = 0; - } - break; -case 1: - if (frame_cnt >= n && frame_cnt <= m) - { - frame_sz = 0; - } - break; -case 2: - throw_packets(frame, &frame_sz, n, &thrown_frame, &kept_frame); - break; -default: break; -} -if (mode < 2) -{ - if (frame_sz == 0) - { - putc('X', stdout); - thrown_frame++; - } - else - { - putc('.', stdout); - kept_frame++; - } -} -thrown += thrown_frame; -kept += kept_frame; -fflush(stdout); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE diff --git a/vp8/common/alloccommon.c b/vp8/common/alloccommon.c index ee6e1cafe..5a7c79c8f 100644 --- a/vp8/common/alloccommon.c +++ b/vp8/common/alloccommon.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "blockd.h" #include "vpx_mem/vpx_mem.h" #include "onyxc_int.h" @@ -20,17 +20,37 @@ extern void vp8_init_scan_order_mask(); -static void update_mode_info_border(MODE_INFO *mi, int rows, int cols) +static void update_mode_info_border( VP8_COMMON *cpi, MODE_INFO *mi_base ) { + int stride = cpi->mode_info_stride; int i; - vpx_memset(mi - cols - 2, 0, sizeof(MODE_INFO) * (cols + 1)); - for (i = 0; i < rows; i++) + // Clear down top border row + vpx_memset(mi_base, 0, sizeof(MODE_INFO) * cpi->mode_info_stride); + + // Clear left border column + for (i = 1; i < cpi->mb_rows+1; i++) { - /* TODO(holmer): Bug? This updates the last element of each row - * rather than the border element! - */ - vpx_memset(&mi[i*cols-1], 0, sizeof(MODE_INFO)); + vpx_memset(&mi_base[i*stride], 0, sizeof(MODE_INFO)); + } +} +static void update_mode_info_in_image( VP8_COMMON *cpi, MODE_INFO *mi ) +{ + int stride = cpi->mode_info_stride; + int rows = cpi->mb_rows; + int cols = cpi->mb_cols; + int i, j; + + // For each in image mode_info element set the in image flag to 1 + for (i = 0; i < cpi->mb_rows; i++) + { + for (j = 0; j < cpi->mb_cols; j++) + { + mi->mbmi.mb_in_image = 1; + mi++; // Next element in the row + } + + mi++; // Step over border element at start of next row } } @@ -116,7 +136,7 @@ int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) oci->mi = oci->mip + oci->mode_info_stride + 1; /* allocate memory for last frame MODE_INFO array */ -#if CONFIG_ERROR_CONCEALMENT + oci->prev_mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO)); if (!oci->prev_mip) @@ -126,10 +146,6 @@ int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) } oci->prev_mi = oci->prev_mip + oci->mode_info_stride + 1; -#else - oci->prev_mip = NULL; - oci->prev_mi = NULL; -#endif oci->above_context = vpx_calloc(sizeof(ENTROPY_CONTEXT_PLANES) * oci->mb_cols, 1); @@ -139,10 +155,8 @@ int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) return 1; } - update_mode_info_border(oci->mi, oci->mb_rows, oci->mb_cols); -#if CONFIG_ERROR_CONCEALMENT - update_mode_info_border(oci->prev_mi, oci->mb_rows, oci->mb_cols); -#endif + update_mode_info_border(oci, oci->mip); + update_mode_info_in_image(oci, oci->mi); return 0; } @@ -153,10 +167,10 @@ void vp8_setup_version(VP8_COMMON *cm) if (!CONFIG_EXPERIMENTAL) vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, "Bitstream was created by an experimental " - "encoder"); + "encoder"); cm->experimental = 1; } - + switch (cm->version & 0x3) { case 0: @@ -172,17 +186,19 @@ void vp8_setup_version(VP8_COMMON *cm) cm->full_pixel = 0; break; case 2: + case 3: cm->no_lpf = 1; cm->filter_type = NORMAL_LOOPFILTER; cm->use_bilinear_mc_filter = 1; cm->full_pixel = 0; break; - case 3: - cm->no_lpf = 1; - cm->filter_type = SIMPLE_LOOPFILTER; - cm->use_bilinear_mc_filter = 1; - cm->full_pixel = 1; - break; + // Full pel only code deprecated in experimental code base + //case 3: + // cm->no_lpf = 1; + // cm->filter_type = SIMPLE_LOOPFILTER; + // cm->use_bilinear_mc_filter = 1; + // cm->full_pixel = 1; + // break; } } void vp8_create_common(VP8_COMMON *oci) @@ -190,14 +206,16 @@ void vp8_create_common(VP8_COMMON *oci) vp8_machine_specific_config(oci); vp8_init_mbmode_probs(oci); + vp8_default_bmode_probs(oci->fc.bmode_prob); + oci->txfm_mode = ONLY_4X4; oci->mb_no_coeff_skip = 1; + oci->comp_pred_mode = HYBRID_PREDICTION; oci->no_lpf = 0; oci->filter_type = NORMAL_LOOPFILTER; oci->use_bilinear_mc_filter = 0; oci->full_pixel = 0; - oci->multi_token_partition = ONE_PARTITION; oci->clr_type = REG_YUV; oci->clamp_type = RECON_CLAMP_REQUIRED; @@ -207,6 +225,9 @@ void vp8_create_common(VP8_COMMON *oci) /* Default disable buffer to buffer copying */ oci->copy_buffer_to_gf = 0; oci->copy_buffer_to_arf = 0; +#if CONFIG_QIMODE + oci->kf_ymode_probs_update = 0; +#endif } void vp8_remove_common(VP8_COMMON *oci) diff --git a/vp8/common/arm/arm_systemdependent.c b/vp8/common/arm/arm_systemdependent.c index 2b45afe4b..c0467cd84 100644 --- a/vp8/common/arm/arm_systemdependent.c +++ b/vp8/common/arm/arm_systemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_ports/arm.h" #include "vp8/common/g_common.h" #include "vp8/common/pragmas.h" diff --git a/vp8/common/arm/filter_arm.c b/vp8/common/arm/filter_arm.c index 6d95eb8e3..6582fb29a 100644 --- a/vp8/common/arm/filter_arm.c +++ b/vp8/common/arm/filter_arm.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include #include "vp8/common/filter.h" #include "vp8/common/subpixel.h" diff --git a/vp8/common/arm/neon/recon_neon.c b/vp8/common/arm/neon/recon_neon.c index d2aafd51f..09fd2a56f 100644 --- a/vp8/common/arm/neon/recon_neon.c +++ b/vp8/common/arm/neon/recon_neon.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/recon.h" #include "vp8/common/blockd.h" diff --git a/vp8/common/arm/reconintra_arm.c b/vp8/common/arm/reconintra_arm.c index cd82baf7c..f8f4dca3e 100644 --- a/vp8/common/arm/reconintra_arm.c +++ b/vp8/common/arm/reconintra_arm.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/blockd.h" #include "vp8/common/reconintra.h" #include "vpx_mem/vpx_mem.h" diff --git a/vp8/common/blockd.c b/vp8/common/blockd.c index 1fc3cd0ca..60ef31217 100644 --- a/vp8/common/blockd.c +++ b/vp8/common/blockd.c @@ -12,6 +12,7 @@ #include "blockd.h" #include "vpx_mem/vpx_mem.h" + const unsigned char vp8_block2left[25] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 @@ -20,3 +21,13 @@ const unsigned char vp8_block2above[25] = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8 }; + +const unsigned char vp8_block2left_8x8[25] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 6, 6, 6, 6, 8 +}; +const unsigned char vp8_block2above_8x8[25] = +{ + 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 4, 4, 4, 4, 6, 6, 6, 6, 8 +}; + diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h index 6cb3fe1bb..89fe03516 100644 --- a/vp8/common/blockd.h +++ b/vp8/common/blockd.h @@ -14,21 +14,26 @@ void vpx_log(const char *format, ...); -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_scale/yv12config.h" #include "mv.h" #include "treecoder.h" #include "subpixel.h" #include "vpx_ports/mem.h" +#include "common.h" #define TRUE 1 #define FALSE 0 +//#define MODE_STATS + /*#define DCPRED 1*/ #define DCPREDSIMTHRESH 0 #define DCPREDCNTTHRESH 3 #define MB_FEATURE_TREE_PROBS 3 +#define PREDICTION_PROBS 3 + #define MAX_MB_SEGMENTS 4 #define MAX_REF_LF_DELTAS 4 @@ -60,11 +65,13 @@ typedef struct extern const unsigned char vp8_block2left[25]; extern const unsigned char vp8_block2above[25]; +extern const unsigned char vp8_block2left_8x8[25]; +extern const unsigned char vp8_block2above_8x8[25]; + #define VP8_COMBINEENTROPYCONTEXTS( Dest, A, B) \ Dest = ((A)!=0) + ((B)!=0); - typedef enum { KEY_FRAME = 0, @@ -77,6 +84,7 @@ typedef enum V_PRED, /* vertical prediction */ H_PRED, /* horizontal prediction */ TM_PRED, /* Truemotion prediction */ + I8X8_PRED, /* 8x8 based prediction, each 8x8 has its own prediction mode */ B_PRED, /* block based prediction, each block has its own prediction mode */ NEARESTMV, @@ -88,21 +96,32 @@ typedef enum MB_MODE_COUNT } MB_PREDICTION_MODE; -/* Macroblock level features */ +// Segment level features. typedef enum { - MB_LVL_ALT_Q = 0, /* Use alternate Quantizer .... */ - MB_LVL_ALT_LF = 1, /* Use alternate loop filter value... */ - MB_LVL_MAX = 2 /* Number of MB level features supported */ + SEG_LVL_ALT_Q = 0, // Use alternate Quantizer .... + SEG_LVL_ALT_LF = 1, // Use alternate loop filter value... + SEG_LVL_REF_FRAME = 2, // Optional Segment reference frame + SEG_LVL_MODE = 3, // Optional Segment mode + SEG_LVL_EOB = 4, // EOB end stop marker. + SEG_LVL_TRANSFORM = 5, // Block transform size. + SEG_LVL_MAX = 6 // Number of MB level features supported -} MB_LVL_FEATURES; +} SEG_LVL_FEATURES; -/* Segment Feature Masks */ -#define SEGMENT_ALTQ 0x01 -#define SEGMENT_ALT_LF 0x02 +// Segment level features. +typedef enum +{ + TX_4X4 = 0, // 4x4 dct transform + TX_8X8 = 1, // 8x8 dct transform + + TX_SIZE_MAX = 2 // Number of differnt transforms avaialble + +} TX_SIZE; #define VP8_YMODES (B_PRED + 1) #define VP8_UV_MODES (TM_PRED + 1) +#define VP8_I8X8_MODES (TM_PRED + 1) #define VP8_MVREFS (1 + SPLITMV - NEARESTMV) @@ -139,7 +158,12 @@ typedef enum union b_mode_info { - B_PREDICTION_MODE as_mode; + struct { + B_PREDICTION_MODE first; +#if CONFIG_COMP_INTRA_PRED + B_PREDICTION_MODE second; +#endif + } as_mode; int_mv mv; }; @@ -155,13 +179,26 @@ typedef enum typedef struct { MB_PREDICTION_MODE mode, uv_mode; - MV_REFERENCE_FRAME ref_frame; - int_mv mv; - +#if CONFIG_COMP_INTRA_PRED + MB_PREDICTION_MODE second_mode, second_uv_mode; +#endif + MV_REFERENCE_FRAME ref_frame, second_ref_frame; + TX_SIZE txfm_size; + int_mv mv, second_mv; unsigned char partitioning; unsigned char mb_skip_coeff; /* does this mb has coefficients at all, 1=no coefficients, 0=need decode tokens */ unsigned char need_to_clamp_mvs; unsigned char segment_id; /* Which set of segmentation parameters should be used for this MB */ + + // Flags used for prediction status of various bistream signals + unsigned char seg_id_predicted; + unsigned char ref_predicted; + + // Indicates if the mb is part of the image (1) vs border (0) + // This can be useful in determining whether the MB provides + // a valid predictor + unsigned char mb_in_image; + } MB_MODE_INFO; typedef struct @@ -205,8 +242,12 @@ typedef struct MacroBlockD int fullpixel_mask; YV12_BUFFER_CONFIG pre; /* Filtered copy of previous frame reconstruction */ + struct { + uint8_t *y_buffer, *u_buffer, *v_buffer; + } second_pre; YV12_BUFFER_CONFIG dst; + MODE_INFO *prev_mode_info_context; MODE_INFO *mode_info_context; int mode_info_stride; @@ -229,13 +270,24 @@ typedef struct MacroBlockD unsigned char update_mb_segmentation_data; /* 0 (do not update) 1 (update) the macroblock segmentation feature data. */ - unsigned char mb_segement_abs_delta; + unsigned char mb_segment_abs_delta; /* Per frame flags that define which MB level features (such as quantizer or loop filter level) */ /* are enabled and when enabled the proabilities used to decode the per MB flags in MB_MODE_INFO */ - vp8_prob mb_segment_tree_probs[MB_FEATURE_TREE_PROBS]; /* Probability Tree used to code Segment number */ - signed char segment_feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; /* Segment parameters */ + // Probability Tree used to code Segment number + vp8_prob mb_segment_tree_probs[MB_FEATURE_TREE_PROBS]; + + + // Segment features + signed char segment_feature_data[MAX_MB_SEGMENTS][SEG_LVL_MAX]; + unsigned int segment_feature_mask[MAX_MB_SEGMENTS]; + +#if CONFIG_FEATUREUPDATES + // keep around the last set so we can figure out what updates... + unsigned int old_segment_feature_mask[MAX_MB_SEGMENTS]; + signed char old_segment_feature_data[MAX_MB_SEGMENTS][SEG_LVL_MAX]; +#endif /* mode_based Loop filter adjustment */ unsigned char mode_ref_lf_delta_enabled; @@ -244,8 +296,8 @@ typedef struct MacroBlockD /* Delta values have the range +/- MAX_LOOP_FILTER */ signed char last_ref_lf_deltas[MAX_REF_LF_DELTAS]; /* 0 = Intra, Last, GF, ARF */ signed char ref_lf_deltas[MAX_REF_LF_DELTAS]; /* 0 = Intra, Last, GF, ARF */ - signed char last_mode_lf_deltas[MAX_MODE_LF_DELTAS]; /* 0 = BPRED, ZERO_MV, MV, SPLIT */ - signed char mode_lf_deltas[MAX_MODE_LF_DELTAS]; /* 0 = BPRED, ZERO_MV, MV, SPLIT */ + signed char last_mode_lf_deltas[MAX_MODE_LF_DELTAS]; /* 0 = BPRED, ZERO_MV, MV, SPLIT */ + signed char mode_lf_deltas[MAX_MODE_LF_DELTAS]; /* 0 = BPRED, ZERO_MV, MV, SPLIT */ /* Distance of MB away from frame edges */ int mb_to_left_edge; @@ -253,15 +305,17 @@ typedef struct MacroBlockD int mb_to_top_edge; int mb_to_bottom_edge; - int ref_frame_cost[MAX_REF_FRAMES]; - - unsigned int frames_since_golden; unsigned int frames_till_alt_ref_frame; vp8_subpix_fn_t subpixel_predict; vp8_subpix_fn_t subpixel_predict8x4; vp8_subpix_fn_t subpixel_predict8x8; vp8_subpix_fn_t subpixel_predict16x16; + vp8_subpix_fn_t subpixel_predict_avg8x8; + vp8_subpix_fn_t subpixel_predict_avg16x16; +#if CONFIG_HIGH_PRECISION_MV + int allow_high_precision_mv; +#endif /* CONFIG_HIGH_PRECISION_MV */ void *current_bc; @@ -284,4 +338,20 @@ typedef struct MacroBlockD extern void vp8_build_block_doffsets(MACROBLOCKD *x); extern void vp8_setup_block_dptrs(MACROBLOCKD *x); +static void update_blockd_bmi(MACROBLOCKD *xd) +{ + int i; + int is_4x4; + is_4x4 = (xd->mode_info_context->mbmi.mode == SPLITMV) || + (xd->mode_info_context->mbmi.mode == I8X8_PRED) || + (xd->mode_info_context->mbmi.mode == B_PRED); + + if (is_4x4) + { + for (i = 0; i < 16; i++) + { + xd->block[i].bmi = xd->mode_info_context->bmi[i]; + } + } +} #endif /* __INC_BLOCKD_H */ diff --git a/vp8/common/coefupdateprobs.h b/vp8/common/coefupdateprobs.h index 9e194dc9a..05e456393 100644 --- a/vp8/common/coefupdateprobs.h +++ b/vp8/common/coefupdateprobs.h @@ -183,3 +183,178 @@ const vp8_prob vp8_coef_update_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTE }, }, }; +const vp8_prob vp8_coef_update_probs_8x8 [BLOCK_TYPES] + [COEF_BANDS] + [PREV_COEF_CONTEXTS] + [ENTROPY_NODES] = +{ + { + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 229, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {219, 234, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {239, 204, 229, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 209, 229, 255, 255, 255, 255, 255, 255, 255, 255, }, + {239, 219, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 204, 229, 255, 255, 255, 255, 255, 255, 255, 255, }, + {229, 209, 234, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 193, 209, 255, 255, 255, 255, 255, 255, 255, 255, }, + {229, 198, 239, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 204, 204, 255, 255, 255, 255, 255, 255, 255, 255, }, + {219, 198, 229, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 198, 204, 255, 255, 255, 255, 255, 255, 255, 255, }, + {209, 193, 234, 249, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 214, 214, 255, 255, 255, 255, 255, 255, 255, 255, }, + {173, 193, 234, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {255, 255, 234, 255, 255, 255, 255, 255, 255, 255, 255, }, + {224, 224, 219, 255, 255, 255, 255, 255, 255, 255, 255, }, + {229, 239, 234, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 234, 224, 255, 255, 255, 255, 255, 255, 255, 255, }, + {224, 234, 234, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 229, 255, 255, 255, 255, 255, 255, 255, 255, }, + {229, 255, 234, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 229, 255, 255, 255, 255, 255, 255, 255, 255, }, + {224, 255, 239, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {224, 219, 234, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 183, 214, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 193, 229, 255, 249, 255, 255, 255, 255, 255, 255, }, + {229, 214, 234, 249, 255, 255, 255, 255, 255, 255, 255, }, + {255, 249, 255, 255, 249, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 198, 229, 255, 255, 255, 255, 255, 255, 255, 255, }, + {229, 219, 249, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 193, 224, 255, 255, 255, 255, 255, 255, 255, 255, }, + {229, 204, 234, 249, 249, 255, 255, 255, 255, 255, 255, }, + {255, 249, 249, 255, 244, 249, 255, 255, 255, 255, 255, }, + }, + { + {255, 178, 224, 255, 249, 255, 255, 255, 255, 255, 255, }, + {234, 224, 234, 249, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 183, 229, 255, 249, 255, 255, 255, 255, 255, 255, }, + {234, 219, 234, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 249, 249, 255, 249, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 193, 224, 249, 255, 244, 255, 255, 255, 255, 255, }, + {219, 224, 229, 255, 255, 249, 255, 255, 255, 255, 255, }, + {255, 255, 255, 249, 249, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 193, 229, 255, 255, 255, 255, 255, 255, 255, 255, }, + {224, 224, 239, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 244, 249, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 239, 234, 244, 239, 244, 249, 255, 255, 255, 255, }, + }, + { + {255, 249, 239, 239, 244, 255, 255, 255, 255, 255, 255, }, + {255, 249, 244, 255, 249, 255, 255, 255, 255, 255, 255, }, + {255, 255, 239, 255, 255, 249, 255, 255, 255, 255, 255, }, + }, + { + {255, 244, 239, 239, 244, 255, 255, 255, 255, 255, 255, }, + {255, 234, 239, 234, 249, 255, 255, 255, 255, 255, 255, }, + {255, 255, 229, 239, 234, 249, 244, 255, 255, 255, 255, }, + }, + { + {255, 239, 229, 239, 234, 234, 255, 255, 255, 255, 255, }, + {255, 239, 234, 229, 244, 239, 255, 234, 255, 255, 255, }, + {255, 229, 209, 229, 239, 234, 244, 229, 255, 249, 255, }, + }, + { + {255, 239, 234, 229, 244, 249, 255, 249, 255, 255, 255, }, + {255, 234, 229, 244, 234, 249, 255, 249, 255, 255, 255, }, + {255, 229, 239, 229, 249, 255, 255, 244, 255, 255, 255, }, + }, + { + {255, 239, 234, 239, 234, 239, 255, 249, 255, 255, 255, }, + {255, 229, 234, 239, 239, 239, 255, 244, 255, 255, 255, }, + {255, 229, 234, 239, 239, 244, 255, 255, 255, 255, 255, }, + }, + { + {255, 219, 224, 229, 229, 234, 239, 224, 255, 255, 255, }, + {255, 229, 229, 224, 234, 229, 239, 239, 255, 255, 255, }, + {255, 229, 224, 239, 234, 239, 224, 224, 255, 249, 255, }, + }, + { + {255, 234, 229, 244, 229, 229, 255, 214, 255, 255, 255, }, + {255, 239, 234, 239, 214, 239, 255, 209, 255, 255, 255, }, + {249, 239, 219, 209, 219, 224, 239, 204, 255, 255, 255, }, + }, + }, + +}; diff --git a/vp8/common/common.h b/vp8/common/common.h index 9a93da991..999f79f2f 100644 --- a/vp8/common/common.h +++ b/vp8/common/common.h @@ -13,7 +13,7 @@ #define common_h 1 #include - +#include "vpx_config.h" /* Interface header for common constant data structures and lookup tables */ #include "vpx_mem/vpx_mem.h" @@ -38,5 +38,4 @@ #define vp8_zero_array( Dest, N) vpx_memset( Dest, 0, N * sizeof( *Dest)); - #endif /* common_h */ diff --git a/vp8/common/debugmodes.c b/vp8/common/debugmodes.c index 46064e61d..6d306578b 100644 --- a/vp8/common/debugmodes.c +++ b/vp8/common/debugmodes.c @@ -97,7 +97,12 @@ void vp8_print_modes_and_motion_vectors(MODE_INFO *mi, int rows, int cols, int f bindex = (b_row & 3) * 4 + (b_col & 3); if (mi[mb_index].mbmi.mode == B_PRED) - fprintf(mvs, "%2d ", mi[mb_index].bmi[bindex].as_mode); + { + fprintf(mvs, "%2d ", mi[mb_index].bmi[bindex].as_mode.first); +#if CONFIG_COMP_INTRA_PRED + fprintf(mvs, "%2d ", mi[mb_index].bmi[bindex].as_mode.second); +#endif + } else fprintf(mvs, "xx "); diff --git a/vp8/common/defaultcoefcounts.h b/vp8/common/defaultcoefcounts.h new file mode 100644 index 000000000..d84361bf9 --- /dev/null +++ b/vp8/common/defaultcoefcounts.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* Generated file, included by entropy.c */ + +static const unsigned int vp8_default_coef_counts_8x8[BLOCK_TYPES] + [COEF_BANDS] + [PREV_COEF_CONTEXTS] + [MAX_ENTROPY_TOKENS] = +{ + + { /* block Type 0 */ + { /* Coeff Band 0 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }, + { /* Coeff Band 1 */ + { 21041, 13314, 3420, 592, 117, 0, 0, 0, 0, 0, 0, 11783}, + { 48236, 6918, 586, 153, 0, 0, 0, 0, 0, 0, 0, 23137}, + { 676112, 106685, 24701, 6003, 1426, 429, 165, 0, 0, 0, 0, 28910} + }, + { /* Coeff Band 2 */ + { 660107, 75227, 8451, 1345, 259, 0, 0, 0, 0, 0, 0, 0}, + { 79164, 36835, 6865, 1185, 246, 47, 0, 0, 0, 0, 0, 2575}, + { 19469, 14330, 3070, 579, 94, 6, 0, 0, 0, 0, 0, 44} + }, + { /* Coeff Band 3 */ + { 1978004, 235343, 28485, 3242, 271, 0, 0, 0, 0, 0, 0, 0}, + { 228684, 106736, 21431, 2842, 272, 46, 0, 0, 0, 0, 0, 9266}, + { 32470, 27496, 6852, 1386, 45, 93, 0, 0, 0, 0, 0, 0} + }, + { /* Coeff Band 4 */ + { 1911212, 224613, 49653, 13748, 2541, 568, 48, 0, 0, 0, 0, 0}, + { 196670, 103472, 44473, 11490, 2432, 977, 72, 0, 0, 0, 0, 9447}, + { 37876, 40417, 19142, 6069, 1799, 727, 51, 0, 0, 0, 0, 0} + }, + { /* Coeff Band 5 */ + { 3813399, 437714, 64387, 11312, 695, 219, 0, 0, 0, 0, 0, 0}, + { 438288, 215917, 61905, 10194, 674, 107, 0, 0, 0, 0, 0, 17808}, + { 99139, 93643, 30054, 5758, 802, 171, 0, 0, 0, 0, 0, 0} + }, + { /* Coeff Band 6 */ + { 12259383, 1625505, 234927, 46306, 8417, 1456, 151, 0, 0, 0, 0, 0}, + { 1518161, 734287, 204240, 44228, 9462, 2240, 65, 0, 0, 0, 0, 107630}, + { 292470, 258894, 94925, 25864, 6662, 2055, 170, 0, 0, 0, 0, 0} + }, + { /* Coeff Band 7 */ + { 9791308, 2118949, 169439, 16735, 1122, 0, 0, 0, 0, 0, 0, 0}, + { 1500281, 752410, 123259, 13065, 1168, 47, 0, 0, 0, 0, 0, 707182}, + { 193067, 142638, 31018, 4719, 516, 138, 0, 0, 0, 0, 0, 12439} + } + }, + { /* block Type 1 */ + { /* Coeff Band 0 */ + { 16925, 10553, 852, 16, 63, 87, 47, 0, 0, 0, 0, 31232}, + { 39777, 26839, 6822, 1908, 678, 456, 227, 168, 35, 0, 0, 46825}, + { 17300, 16666, 4168, 1209, 492, 154, 118, 207, 0, 0, 0, 19608} + }, + { /* Coeff Band 1 */ + { 35882, 31722, 4625, 1270, 266, 237, 0, 0, 0, 0, 0, 0}, + { 15426, 13894, 4482, 1305, 281, 43, 0, 0, 0, 0, 0, 18627}, + { 3900, 6552, 3472, 1723, 746, 366, 115, 35, 0, 0, 0, 798} + }, + { /* Coeff Band 2 */ + { 21998, 29132, 3353, 679, 46, 0, 0, 0, 0, 0, 0, 0}, + { 9098, 15767, 3794, 792, 268, 47, 0, 0, 0, 0, 0, 22402}, + { 4007, 8472, 2844, 687, 217, 0, 0, 0, 0, 0, 0, 2739} + }, + { /* Coeff Band 3 */ + { 0, 31414, 2911, 682, 96, 0, 0, 0, 0, 0, 0, 0}, + { 0, 16515, 4425, 938, 124, 0, 0, 0, 0, 0, 0, 31369}, + { 0, 4833, 2787, 1213, 150, 0, 0, 0, 0, 0, 0, 3744} + }, + { /* Coeff Band 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, 0, 0, 0, 0, 0} + }, + { /* Coeff Band 5 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }, + { /* Coeff Band 6 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52762}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13326} + }, + { /* Coeff Band 7 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + } + }, + { /* block Type 2 */ + { /* Coeff Band 0 */ + { 4444, 1614, 120, 48, 0, 48, 0, 0, 0, 0, 0, 278}, + { 192436, 103730, 24494, 9845, 4122, 1193, 102, 0, 0, 0, 0, 2577}, + { 3473446, 2308716, 815510, 370374, 167797, 92152, 12073, 86, 0, 0, 0, 6801} + }, + { /* Coeff Band 1 */ + { 2150616, 1136388, 250011, 86888, 31434, 13746, 1243, 0, 0, 0, 0, 0}, + { 1179945, 799802, 266012, 106787, 40809, 16486, 1546, 0, 0, 0, 0, 2673}, + { 465128, 504130, 286989, 146259, 62380, 30192, 2866, 20, 0, 0, 0, 0} + }, + { /* Coeff Band 2 */ + { 2157762, 1177519, 282665, 108499, 43389, 23224, 2597, 34, 0, 0, 0, 0}, + { 1135685, 813705, 278079, 123255, 53935, 29492, 3152, 39, 0, 0, 0, 2978}, + { 391894, 428037, 264216, 144306, 69326, 40281, 5541, 29, 0, 0, 0, 38} + }, + { /* Coeff Band 3 */ + { 6669109, 3468471, 782161, 288484, 115500, 51083, 4943, 41, 0, 0, 0, 0}, + { 3454493, 2361636, 809524, 337663, 141343, 65036, 6361, 0, 0, 0, 0, 8730}, + { 1231825, 1359522, 824686, 420784, 185517, 98731, 10973, 72, 0, 0, 0, 20} + }, + { /* Coeff Band 4 */ + { 7606203, 3452846, 659856, 191703, 49335, 14336, 450, 0, 0, 0, 0, 0}, + { 3806506, 2379332, 691697, 224938, 61966, 18324, 766, 0, 0, 0, 0, 8193}, + { 1270110, 1283728, 628775, 243378, 72617, 24897, 1087, 0, 0, 0, 0, 0} + }, + { /* Coeff Band 5 */ + { 15314169, 7436809, 1579928, 515790, 167453, 58305, 3502, 19, 0, 0, 0, 0}, + { 7021286, 4667922, 1545706, 574463, 191793, 68748, 4048, 1, 0, 0, 0, 17222}, + { 2011989, 2145878, 1185336, 534879, 195719, 79103, 5343, 4, 0, 0, 0, 37} + }, + { /* Coeff Band 6 */ + { 63458382, 25384462, 4208045, 1091050, 299011, 95242, 5238, 33, 0, 0, 0, 0}, + { 25638401, 14694085, 3945978, 1195420, 344813, 117355, 6703, 0, 0, 0, 0, 216811}, + { 5988177, 5824044, 2754413, 1077350, 370739, 139710, 9693, 38, 0, 0, 0, 1835} + }, + { /* Coeff Band 7 */ + { 74998348, 29342158, 2955001, 452912, 69631, 9516, 37, 0, 0, 0, 0, 0}, + { 24762356, 13281085, 2409883, 436787, 68948, 10658, 36, 0, 0, 0, 0, 6614989}, + { 3882867, 3224489, 1052289, 252890, 46967, 8548, 154, 0, 0, 0, 0, 194354} + } + }, + { /* block Type 3 */ + { /* Coeff Band 0 */ + { 10583, 12059, 3155, 1041, 248, 175, 24, 2, 0, 0, 0, 5717}, + { 42461, 41782, 13553, 4966, 1352, 855, 89, 0, 0, 0, 0, 15000}, + { 4691125, 5045589, 2673566, 1089317, 378161, 160268, 18252, 813, 69, 13, 0, 49} + }, + { /* Coeff Band 1 */ + { 1535203, 1685686, 924565, 390329, 141709, 60523, 5983, 171, 0, 0, 0, 0}, + { 1594021, 1793276, 1016078, 441332, 164159, 70843, 8098, 311, 0, 0, 0, 11312}, + { 1225223, 1430184, 888492, 460713, 203286, 115149, 22061, 804, 7, 0, 0, 0} + }, + { /* Coeff Band 2 */ + { 1522386, 1590366, 799910, 303691, 96625, 37608, 3637, 180, 33, 11, 0, 0}, + { 1682184, 1793869, 913649, 353520, 113674, 46309, 4736, 221, 18, 3, 0, 963}, + { 1574580, 1740474, 954392, 417994, 151400, 67091, 8000, 536, 73, 10, 0, 63} + }, + { /* Coeff Band 3 */ + { 4963672, 5197790, 2585383, 982161, 313333, 118498, 16014, 536, 62, 0, 0, 0}, + { 5223913, 5569803, 2845858, 1107384, 364949, 147841, 18296, 658, 11, 11, 0, 1866}, + { 4042207, 4548894, 2608767, 1154993, 446290, 221295, 41054, 2438, 124, 20, 0, 0} + }, + { /* Coeff Band 4 */ + { 3857216, 4431325, 2670447, 1330169, 553301, 286825, 46763, 1917, 0, 0, 0, 0}, + { 4226215, 4963701, 3046198, 1523923, 644670, 355519, 58792, 2525, 0, 0, 0, 1298}, + { 3831873, 4580350, 3018580, 1660048, 797298, 502983, 123906, 7172, 16, 0, 0, 0} + }, + { /* Coeff Band 5 */ + { 8524543, 9285149, 4979435, 2039330, 683458, 266032, 22628, 270, 0, 0, 0, 0}, + { 9432163, 10428088, 5715661, 2385738, 838389, 326264, 29981, 361, 0, 0, 0, 884}, + { 9039066, 10368964, 6136765, 2862030, 1098269, 511668, 63105, 945, 14, 0, 0, 0} + }, + { /* Coeff Band 6 */ + { 33222872, 34748297, 17701695, 7214933, 2602336, 1191859, 187873, 12667, 390, 3, 0, 0}, + { 34765051, 37140719, 19525578, 8268934, 3085012, 1473864, 246743, 15258, 736, 3, 0, 8403}, + { 28591289, 32252393, 19037068, 9213729, 4020653, 2372354, 586420, 67428, 3920, 92, 7, 3} + }, + { /* Coeff Band 7 */ + { 68604786, 60777665, 19712887, 5656955, 1520443, 507166, 51829, 2466, 10, 0, 0, 0}, + { 55447403, 51682540, 19008774, 5928582, 1706884, 595531, 65998, 3661, 101, 0, 0, 8468343}, + { 28321970, 29149398, 13565882, 5258675, 1868588, 898041, 192023, 21497, 672, 17, 0, 1884921} + } + } + }; diff --git a/vp8/common/entropy.c b/vp8/common/entropy.c index 652450c78..2c1667225 100644 --- a/vp8/common/entropy.c +++ b/vp8/common/entropy.c @@ -60,6 +60,22 @@ DECLARE_ALIGNED(16, const int, vp8_default_zig_zag1d[16]) = 9, 12, 13, 10, 7, 11, 14, 15, }; +DECLARE_ALIGNED(64, cuchar, vp8_coef_bands_8x8[64]) = { 0, 1, 2, 3, 5, 4, 4, 5, + 5, 3, 6, 3, 5, 4, 6, 6, + 6, 5, 5, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 +}; +DECLARE_ALIGNED(64, const int, vp8_default_zig_zag1d_8x8[64]) = +{ + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, +}; DECLARE_ALIGNED(16, const short, vp8_default_inv_zig_zag[16]) = { @@ -70,8 +86,7 @@ DECLARE_ALIGNED(16, const short, vp8_default_inv_zig_zag[16]) = }; DECLARE_ALIGNED(16, short, vp8_default_zig_zag_mask[16]); - -const int vp8_mb_feature_data_bits[MB_LVL_MAX] = {7, 6}; +DECLARE_ALIGNED(64, short, vp8_default_zig_zag_mask_8x8[64]);//int64_t /* Array indices are identical to previously-existing CONTEXT_NODE indices */ @@ -113,7 +128,10 @@ void vp8_init_scan_order_mask() { vp8_default_zig_zag_mask[vp8_default_zig_zag1d[i]] = 1 << i; } - + for (i = 0; i < 64; i++) + { + vp8_default_zig_zag_mask_8x8[vp8_default_zig_zag1d_8x8[i]] = 1 << i; + } } static void init_bit_tree(vp8_tree_index *p, int n) @@ -156,11 +174,37 @@ vp8_extra_bit_struct vp8_extra_bits[12] = }; #include "default_coef_probs.h" +#include "defaultcoefcounts.h" void vp8_default_coef_probs(VP8_COMMON *pc) { + int h; vpx_memcpy(pc->fc.coef_probs, default_coef_probs, sizeof(default_coef_probs)); + h = 0; + do + { + int i = 0; + + do + { + int k = 0; + + do + { + unsigned int branch_ct [ENTROPY_NODES] [2]; + vp8_tree_probs_from_distribution( + MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, + pc->fc.coef_probs_8x8 [h][i][k], branch_ct, vp8_default_coef_counts_8x8 [h][i][k], + 256, 1); + + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++i < COEF_BANDS); + } + while (++h < BLOCK_TYPES); + } void vp8_coef_tree_initialize() diff --git a/vp8/common/entropy.h b/vp8/common/entropy.h index 3c25453a7..c7a41f58b 100644 --- a/vp8/common/entropy.h +++ b/vp8/common/entropy.h @@ -14,7 +14,7 @@ #include "treecoder.h" #include "blockd.h" - +#include "common.h" /* Coefficient token alphabet */ #define ZERO_TOKEN 0 /* 0 Extra Bits 0+0 */ @@ -52,7 +52,6 @@ extern vp8_extra_bit_struct vp8_extra_bits[12]; /* indexed by token value */ #define MAX_PROB 255 #define DCT_MAX_VALUE 8192 - /* Coefficients are predicted via a 3-dimensional probability table. */ /* Outside dimension. 0 = Y no DC, 1 = Y2, 2 = UV, 3 = Y with DC */ @@ -64,6 +63,7 @@ extern vp8_extra_bit_struct vp8_extra_bits[12]; /* indexed by token value */ #define COEF_BANDS 8 extern DECLARE_ALIGNED(16, const unsigned char, vp8_coef_bands[16]); +extern DECLARE_ALIGNED(64, const unsigned char, vp8_coef_bands_8x8[64]); /* Inside dimension is 3-valued measure of nearby complexity, that is, the extent to which nearby coefficients are nonzero. For the first @@ -87,15 +87,14 @@ extern DECLARE_ALIGNED(16, const unsigned char, vp8_coef_bands[16]); extern DECLARE_ALIGNED(16, const unsigned char, vp8_prev_token_class[MAX_ENTROPY_TOKENS]); extern const vp8_prob vp8_coef_update_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES]; - +extern const vp8_prob vp8_coef_update_probs_8x8 [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES]; struct VP8Common; void vp8_default_coef_probs(struct VP8Common *); - extern DECLARE_ALIGNED(16, const int, vp8_default_zig_zag1d[16]); extern DECLARE_ALIGNED(16, const short, vp8_default_inv_zig_zag[16]); extern short vp8_default_zig_zag_mask[16]; -extern const int vp8_mb_feature_data_bits[MB_LVL_MAX]; - +extern DECLARE_ALIGNED(64, const int, vp8_default_zig_zag1d_8x8[64]); +extern short vp8_default_zig_zag_mask_8x8[64];//int64_t void vp8_coef_tree_initialize(void); #endif diff --git a/vp8/common/entropymode.c b/vp8/common/entropymode.c index 930e896ce..f220a6ba0 100644 --- a/vp8/common/entropymode.c +++ b/vp8/common/entropymode.c @@ -9,15 +9,59 @@ */ +#include "modecont.h" #include "entropymode.h" #include "entropy.h" #include "vpx_mem/vpx_mem.h" -static const unsigned int kf_y_mode_cts[VP8_YMODES] = { 1607, 915, 812, 811, 5455}; -static const unsigned int y_mode_cts [VP8_YMODES] = { 8080, 1908, 1582, 1007, 5874}; +#if CONFIG_QIMODE +const unsigned int kf_y_mode_cts[8][VP8_YMODES] = +{ + {17, 6, 5, 2, 22, 203}, + {27, 13, 13, 6, 27, 170}, + {35, 17, 18, 9, 26, 152}, + {45, 22, 24, 12, 27, 126}, + {58, 26, 29, 13, 26, 104}, + {73, 33, 36, 17, 20, 78}, + {88, 38, 39, 19, 16, 57}, + {99, 42, 43, 21, 12, 39}, +}; +#else +static const unsigned int kf_y_mode_cts[VP8_YMODES] = { + 49, 22, 23, 11, 23, 128}; +#endif + +static const unsigned int y_mode_cts [VP8_YMODES] = { + 106, 25, 21, 13, 16, 74}; + +#if CONFIG_UVINTRA +static const unsigned int uv_mode_cts [VP8_YMODES] [VP8_UV_MODES] ={ + { 210, 20, 20, 6}, + { 180, 60, 10, 6}, + { 150, 20, 80, 6}, + { 170, 35, 35, 16}, + { 142, 51, 45, 18}, /* never used */ + { 160, 40, 46, 10}, +}; +#else static const unsigned int uv_mode_cts [VP8_UV_MODES] = { 59483, 13605, 16492, 4230}; +#endif + +static const unsigned int i8x8_mode_cts [VP8_UV_MODES] = {93, 69, 81, 13}; + +#if CONFIG_UVINTRA +static const unsigned int kf_uv_mode_cts [VP8_YMODES] [VP8_UV_MODES] ={ + { 180, 34, 34, 8}, + { 132, 74, 40, 10}, + { 132, 40, 74, 10}, + { 152, 46, 40, 18}, + { 142, 51, 45, 18}, /* never used */ + { 142, 51, 45, 18}, +}; +#else static const unsigned int kf_uv_mode_cts[VP8_UV_MODES] = { 5319, 1904, 1703, 674}; +#endif static const unsigned int bmode_cts[VP8_BINTRAMODES] = { @@ -117,23 +161,30 @@ const vp8_tree_index vp8_bmode_tree[18] = /* INTRAMODECONTEXTNODE value */ /* Again, these trees use the same probability indices as their explicitly-programmed predecessors. */ - -const vp8_tree_index vp8_ymode_tree[8] = +const vp8_tree_index vp8_ymode_tree[10] = { -DC_PRED, 2, 4, 6, -V_PRED, -H_PRED, - -TM_PRED, -B_PRED + -TM_PRED, 8, + -B_PRED, -I8X8_PRED }; -const vp8_tree_index vp8_kf_ymode_tree[8] = +const vp8_tree_index vp8_kf_ymode_tree[10] = { -B_PRED, 2, 4, 6, -DC_PRED, -V_PRED, - -H_PRED, -TM_PRED + -H_PRED, 8, + -TM_PRED, -I8X8_PRED }; +const vp8_tree_index vp8_i8x8_mode_tree[6] = +{ + -DC_PRED, 2, + -V_PRED, 4, + -H_PRED, -TM_PRED +}; const vp8_tree_index vp8_uv_mode_tree[6] = { -DC_PRED, 2, @@ -168,11 +219,33 @@ struct vp8_token_struct vp8_bmode_encodings [VP8_BINTRAMODES]; struct vp8_token_struct vp8_ymode_encodings [VP8_YMODES]; struct vp8_token_struct vp8_kf_ymode_encodings [VP8_YMODES]; struct vp8_token_struct vp8_uv_mode_encodings [VP8_UV_MODES]; +struct vp8_token_struct vp8_i8x8_mode_encodings [VP8_UV_MODES]; struct vp8_token_struct vp8_mbsplit_encodings [VP8_NUMMBSPLITS]; struct vp8_token_struct vp8_mv_ref_encoding_array [VP8_MVREFS]; struct vp8_token_struct vp8_sub_mv_ref_encoding_array [VP8_SUBMVREFS]; +#if CONFIG_HIGH_PRECISION_MV +const vp8_tree_index vp8_small_mvtree_hp [30] = +{ + 2, 16, + 4, 10, + 6, 8, + -0, -1, + -2, -3, + 12, 14, + -4, -5, + -6, -7, + 18, 24, + 20, 22, + -8, -9, + -10, -11, + 26, 28, + -12, -13, + -14, -15 +}; +struct vp8_token_struct vp8_small_mvencodings_hp [16]; +#endif /* CONFIG_HIGH_PRECISION_MV */ const vp8_tree_index vp8_small_mvtree [14] = { @@ -184,9 +257,10 @@ const vp8_tree_index vp8_small_mvtree [14] = -4, -5, -6, -7 }; - struct vp8_token_struct vp8_small_mvencodings [8]; + + void vp8_init_mbmode_probs(VP8_COMMON *x) { unsigned int bct [VP8_YMODES] [2]; /* num Ymodes > num UV modes */ @@ -196,22 +270,56 @@ void vp8_init_mbmode_probs(VP8_COMMON *x) x->fc.ymode_prob, bct, y_mode_cts, 256, 1 ); +#if CONFIG_QIMODE + { + int i; + for (i=0;i<8;i++) + vp8_tree_probs_from_distribution( + VP8_YMODES, vp8_kf_ymode_encodings, vp8_kf_ymode_tree, + x->kf_ymode_prob[i], bct, kf_y_mode_cts[i], + 256, 1 + ); + } +#else vp8_tree_probs_from_distribution( VP8_YMODES, vp8_kf_ymode_encodings, vp8_kf_ymode_tree, x->kf_ymode_prob, bct, kf_y_mode_cts, 256, 1 ); +#endif +#if CONFIG_UVINTRA + { + int i; + for (i=0;ikf_uv_mode_prob[i], bct, kf_uv_mode_cts[i], + 256, 1); + vp8_tree_probs_from_distribution( + VP8_UV_MODES, vp8_uv_mode_encodings, vp8_uv_mode_tree, + x->fc.uv_mode_prob[i], bct, uv_mode_cts[i], + 256, 1); + } + } +#else vp8_tree_probs_from_distribution( VP8_UV_MODES, vp8_uv_mode_encodings, vp8_uv_mode_tree, x->fc.uv_mode_prob, bct, uv_mode_cts, - 256, 1 - ); + 256, 1); + vp8_tree_probs_from_distribution( VP8_UV_MODES, vp8_uv_mode_encodings, vp8_uv_mode_tree, x->kf_uv_mode_prob, bct, kf_uv_mode_cts, + 256, 1); +#endif + vp8_tree_probs_from_distribution( + VP8_UV_MODES, vp8_i8x8_mode_encodings, vp8_i8x8_mode_tree, + x->i8x8_mode_prob, bct, i8x8_mode_cts, 256, 1 - ); + ); vpx_memcpy(x->fc.sub_mv_ref_prob, sub_mv_ref_prob, sizeof(sub_mv_ref_prob)); + } @@ -262,6 +370,7 @@ void vp8_entropy_mode_init() vp8_tokens_from_tree(vp8_ymode_encodings, vp8_ymode_tree); vp8_tokens_from_tree(vp8_kf_ymode_encodings, vp8_kf_ymode_tree); vp8_tokens_from_tree(vp8_uv_mode_encodings, vp8_uv_mode_tree); + vp8_tokens_from_tree(vp8_i8x8_mode_encodings, vp8_i8x8_mode_tree); vp8_tokens_from_tree(vp8_mbsplit_encodings, vp8_mbsplit_tree); vp8_tokens_from_tree_offset(vp8_mv_ref_encoding_array, @@ -270,4 +379,138 @@ void vp8_entropy_mode_init() vp8_sub_mv_ref_tree, LEFT4X4); vp8_tokens_from_tree(vp8_small_mvencodings, vp8_small_mvtree); +#if CONFIG_HIGH_PRECISION_MV + vp8_tokens_from_tree(vp8_small_mvencodings_hp, vp8_small_mvtree_hp); +#endif +} + +void vp8_init_mode_contexts(VP8_COMMON *pc) +{ + vpx_memset(pc->mv_ref_ct, 0, sizeof(pc->mv_ref_ct)); + vpx_memset(pc->mv_ref_ct_a, 0, sizeof(pc->mv_ref_ct_a)); + + vpx_memcpy( pc->mode_context, + default_vp8_mode_contexts, + sizeof (pc->mode_context)); + vpx_memcpy( pc->mode_context_a, + default_vp8_mode_contexts, + sizeof (pc->mode_context_a)); + +} + +void vp8_accum_mv_refs(VP8_COMMON *pc, + MB_PREDICTION_MODE m, + const int ct[4]) +{ + int (*mv_ref_ct)[4][2]; + + if(pc->refresh_alt_ref_frame) + mv_ref_ct = pc->mv_ref_ct_a; + else + mv_ref_ct = pc->mv_ref_ct; + + if (m == ZEROMV) + { + ++mv_ref_ct [ct[0]] [0] [0]; + } + else + { + ++mv_ref_ct [ct[0]] [0] [1]; + if (m == NEARESTMV) + { + ++mv_ref_ct [ct[1]] [1] [0]; + } + else + { + ++mv_ref_ct [ct[1]] [1] [1]; + if (m == NEARMV) + { + ++mv_ref_ct [ct[2]] [2] [0]; + } + else + { + ++mv_ref_ct [ct[2]] [2] [1]; + if (m == NEWMV) + { + ++mv_ref_ct [ct[3]] [3] [0]; + } + else + { + ++mv_ref_ct [ct[3]] [3] [1]; + } + } + } + } +} + +void vp8_update_mode_context(VP8_COMMON *pc) +{ + int i, j; + int (*mv_ref_ct)[4][2]; + int (*mode_context)[4]; + + if(pc->refresh_alt_ref_frame) + { + mv_ref_ct = pc->mv_ref_ct_a; + mode_context = pc->mode_context_a; + } + else + { + mv_ref_ct = pc->mv_ref_ct; + mode_context = pc->mode_context; + } + + for (j = 0; j < 6; j++) + { + for (i = 0; i < 4; i++) + { + int this_prob; + int count = mv_ref_ct[j][i][0] + mv_ref_ct[j][i][1]; + /* preventing rare occurances from skewing the probs */ + if (count>=4) + { + this_prob = 256 * mv_ref_ct[j][i][0] / count; + this_prob = this_prob? (this_prob<255?this_prob:255):1; + mode_context[j][i] = this_prob; + } + } + } +} +#include "vp8/common/modecont.h" +void print_mode_contexts(VP8_COMMON *pc) +{ + int j, i; + printf("====================\n"); + for(j=0; j<6; j++) + { + for (i = 0; i < 4; i++) + { + printf( "%4d ", pc->mode_context[j][i]); + } + printf("\n"); + } + printf("====================\n"); + for(j=0; j<6; j++) + { + for (i = 0; i < 4; i++) + { + printf( "%4d ", pc->mode_context_a[j][i]); + } + printf("\n"); + } + +} +void print_mv_ref_cts(VP8_COMMON *pc) +{ + int j, i; + for(j=0; j<6; j++) + { + for (i = 0; i < 4; i++) + { + printf("(%4d:%4d) ", + pc->mv_ref_ct[j][i][0], + pc->mv_ref_ct[j][i][1]); + } + printf("\n"); + } } diff --git a/vp8/common/entropymode.h b/vp8/common/entropymode.h index fdb170df3..09d5c7704 100644 --- a/vp8/common/entropymode.h +++ b/vp8/common/entropymode.h @@ -38,7 +38,7 @@ extern const vp8_tree_index vp8_bmode_tree[]; extern const vp8_tree_index vp8_ymode_tree[]; extern const vp8_tree_index vp8_kf_ymode_tree[]; extern const vp8_tree_index vp8_uv_mode_tree[]; - +extern const vp8_tree_index vp8_i8x8_mode_tree[]; extern const vp8_tree_index vp8_mbsplit_tree[]; extern const vp8_tree_index vp8_mv_ref_tree[]; extern const vp8_tree_index vp8_sub_mv_ref_tree[]; @@ -46,6 +46,7 @@ extern const vp8_tree_index vp8_sub_mv_ref_tree[]; extern struct vp8_token_struct vp8_bmode_encodings [VP8_BINTRAMODES]; extern struct vp8_token_struct vp8_ymode_encodings [VP8_YMODES]; extern struct vp8_token_struct vp8_kf_ymode_encodings [VP8_YMODES]; +extern struct vp8_token_struct vp8_i8x8_mode_encodings [VP8_UV_MODES]; extern struct vp8_token_struct vp8_uv_mode_encodings [VP8_UV_MODES]; extern struct vp8_token_struct vp8_mbsplit_encodings [VP8_NUMMBSPLITS]; @@ -55,12 +56,20 @@ extern struct vp8_token_struct vp8_mv_ref_encoding_array [VP8_MVREFS]; extern struct vp8_token_struct vp8_sub_mv_ref_encoding_array [VP8_SUBMVREFS]; extern const vp8_tree_index vp8_small_mvtree[]; - extern struct vp8_token_struct vp8_small_mvencodings [8]; +#if CONFIG_HIGH_PRECISION_MV +extern const vp8_tree_index vp8_small_mvtree_hp[]; +extern struct vp8_token_struct vp8_small_mvencodings_hp [16]; +#endif void vp8_entropy_mode_init(void); void vp8_init_mbmode_probs(VP8_COMMON *x); +extern void vp8_init_mode_contexts(VP8_COMMON *pc); +extern void vp8_update_mode_context(VP8_COMMON *pc);; +extern void vp8_accum_mv_refs(VP8_COMMON *pc, + MB_PREDICTION_MODE m, + const int ct[4]); void vp8_default_bmode_probs(vp8_prob dest [VP8_BINTRAMODES-1]); void vp8_kf_default_bmode_probs(vp8_prob dest [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES-1]); diff --git a/vp8/common/entropymv.c b/vp8/common/entropymv.c index e5df1f095..90195f7bc 100644 --- a/vp8/common/entropymv.c +++ b/vp8/common/entropymv.c @@ -11,6 +11,41 @@ #include "entropymv.h" +#if CONFIG_HIGH_PRECISION_MV +const MV_CONTEXT_HP vp8_mv_update_probs_hp[2] = +{ + {{ + 237, + 246, + 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 250, 250, 252, 254, 254, 254 + }}, + {{ + 231, + 243, + 245, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 251, 251, 254, 254, 254, 254 + }} +}; +const MV_CONTEXT_HP vp8_default_mv_context_hp[2] = +{ + {{ + /* row */ + 162, /* is short */ + 128, /* sign */ + 220, 204, 180, 192, 192, 119, 192, 192, 180, 140, 192, 192, 224, 224, 224, /* short tree */ + 128, 129, 132, 75, 145, 178, 206, 239, 254, 254, 254 /* long bits */ + }}, + {{ + /* same for column */ + 164, /* is short */ + 128, + 220, 204, 180, 192, 192, 119, 192, 192, 180, 140, 192, 192, 224, 224, 224, /* short tree */ + 128, 130, 130, 74, 148, 180, 203, 236, 254, 254, 254 /* long bits */ + }} +}; +#endif /* CONFIG_HIGH_PRECISION_MV */ + const MV_CONTEXT vp8_mv_update_probs[2] = { {{ @@ -35,15 +70,11 @@ const MV_CONTEXT vp8_default_mv_context[2] = 225, 146, 172, 147, 214, 39, 156, /* short tree */ 128, 129, 132, 75, 145, 178, 206, 239, 254, 254 /* long bits */ }}, - - - {{ /* same for column */ 164, /* is short */ 128, 204, 170, 119, 235, 140, 230, 228, 128, 130, 130, 74, 148, 180, 203, 236, 254, 254 /* long bits */ - }} }; diff --git a/vp8/common/entropymv.h b/vp8/common/entropymv.h index 2db1e385b..d97c12eab 100644 --- a/vp8/common/entropymv.h +++ b/vp8/common/entropymv.h @@ -13,16 +13,18 @@ #define __INC_ENTROPYMV_H #include "treecoder.h" +#include "vpx_config.h" enum { mv_max = 1023, /* max absolute value of a MV component */ MVvals = (2 * mv_max) + 1, /* # possible values "" */ - mvfp_max = 255, /* max absolute value of a full pixel MV component */ - MVfpvals = (2 * mvfp_max) +1, /* # possible full pixel MV values */ - mvlong_width = 10, /* Large MVs have 9 bit magnitudes */ mvnum_short = 8, /* magnitudes 0 through 7 */ + mvnum_short_bits = 3, /* number of bits for short mvs */ + + mvfp_max = 255, /* max absolute value of a full pixel MV component */ + MVfpvals = (2 * mvfp_max) + 1, /* # possible full pixel MV values */ /* probability offsets for coding each MV component */ @@ -41,4 +43,34 @@ typedef struct mv_context extern const MV_CONTEXT vp8_mv_update_probs[2], vp8_default_mv_context[2]; +#if CONFIG_HIGH_PRECISION_MV +enum +{ + mv_max_hp = 2047, /* max absolute value of a MV component */ + MVvals_hp = (2 * mv_max_hp) + 1, /* # possible values "" */ + mvlong_width_hp = 11, /* Large MVs have 9 bit magnitudes */ + mvnum_short_hp = 16, /* magnitudes 0 through 15 */ + mvnum_short_bits_hp = 4, /* number of bits for short mvs */ + + mvfp_max_hp = 255, /* max absolute value of a full pixel MV component */ + MVfpvals_hp = (2 * mvfp_max_hp) + 1, /* # possible full pixel MV values */ + + /* probability offsets for coding each MV component */ + + mvpis_short_hp = 0, /* short (<= 7) vs long (>= 8) */ + MVPsign_hp, /* sign for non-zero */ + MVPshort_hp, /* 8 short values = 7-position tree */ + + MVPbits_hp = MVPshort_hp + mvnum_short_hp - 1, /* mvlong_width long value bits */ + MVPcount_hp = MVPbits_hp + mvlong_width_hp /* (with independent probabilities) */ +}; + +typedef struct mv_context_hp +{ + vp8_prob prob[MVPcount_hp]; /* often come in row, col pairs */ +} MV_CONTEXT_HP; + +extern const MV_CONTEXT_HP vp8_mv_update_probs_hp[2], vp8_default_mv_context_hp[2]; +#endif /* CONFIG_HIGH_PRECISION_MV */ + #endif diff --git a/vp8/common/filter.c b/vp8/common/filter.c index ae5952952..d1ef79666 100644 --- a/vp8/common/filter.c +++ b/vp8/common/filter.c @@ -13,8 +13,26 @@ #include "filter.h" #include "vpx_ports/mem.h" -DECLARE_ALIGNED(16, const short, vp8_bilinear_filters[8][2]) = +DECLARE_ALIGNED(16, const short, vp8_bilinear_filters[SUBPEL_SHIFTS][2]) = { +#if SUBPEL_SHIFTS==16 + { 128, 0 }, + { 120, 8 }, + { 112, 16 }, + { 104, 24 }, + { 96, 32 }, + { 88, 40 }, + { 80, 48 }, + { 72, 56 }, + { 64, 64 }, + { 56, 72 }, + { 48, 80 }, + { 40, 88 }, + { 32, 96 }, + { 24, 104 }, + { 16, 112 }, + { 8, 120 } +#else { 128, 0 }, { 112, 16 }, { 96, 32 }, @@ -23,8 +41,197 @@ DECLARE_ALIGNED(16, const short, vp8_bilinear_filters[8][2]) = { 48, 80 }, { 32, 96 }, { 16, 112 } +#endif /* SUBPEL_SHIFTS==16 */ }; +#if CONFIG_ENHANCED_INTERP +#define FILTER_ALPHA 60 +DECLARE_ALIGNED(16, const short, vp8_sub_pel_filters[SUBPEL_SHIFTS][2*INTERP_EXTEND]) = +{ + /* Generated using MATLAB: + * alpha = 0.6; + * b=intfilt(8,4,alpha); + * bi=round(128*b); + * ba=flipud(reshape([bi 0], 8, 8)); + * disp(num2str(ba, '%d,')) + */ +#if SUBPEL_SHIFTS==16 +#if FILTER_ALPHA == 70 + /* alpha = 0.70 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + { 0, 2, -6, 126, 8, -3, 1, 0}, + {-1, 4, -11, 123, 18, -7, 3, -1}, + {-1, 5, -15, 119, 27, -10, 4, -1}, + {-2, 6, -18, 113, 38, -13, 5, -1}, + {-2, 7, -20, 106, 49, -16, 6, -2}, + {-2, 8, -22, 98, 59, -18, 7, -2}, + {-2, 8, -22, 89, 69, -20, 8, -2}, + {-2, 8, -21, 79, 79, -21, 8, -2}, + {-2, 8, -20, 69, 89, -22, 8, -2}, + {-2, 7, -18, 59, 98, -22, 8, -2}, + {-2, 6, -16, 49, 106, -20, 7, -2}, + {-1, 5, -13, 38, 113, -18, 6, -2}, + {-1, 4, -10, 27, 119, -15, 5, -1}, + {-1, 3, -7, 18, 123, -11, 4, -1}, + { 0, 1, -3, 8, 126, -6, 2, 0} +#elif FILTER_ALPHA == 65 + /* alpha = 0.65 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + { 0, 2, -6, 126, 8, -3, 1, 0}, + {-1, 3, -10, 123, 18, -6, 2, -1}, + {-1, 5, -14, 118, 27, -10, 4, -1}, + {-1, 5, -17, 112, 38, -13, 5, -1}, + {-2, 6, -19, 106, 48, -15, 5, -1}, + {-2, 7, -21, 98, 59, -17, 6, -2}, + {-2, 7, -21, 89, 69, -19, 7, -2}, + {-2, 7, -20, 79, 79, -20, 7, -2}, + {-2, 7, -19, 69, 89, -21, 7, -2}, + {-2, 6, -17, 59, 98, -21, 7, -2}, + {-1, 5, -15, 48, 106, -19, 6, -2}, + {-1, 5, -13, 38, 112, -17, 5, -1}, + {-1, 4, -10, 27, 118, -14, 5, -1}, + {-1, 2, -6, 18, 123, -10, 3, -1}, + { 0, 1, -3, 8, 126, -6, 2, 0} +#elif FILTER_ALPHA == 60 + /* alpha = 0.60 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + { 0, 2, -6, 126, 8, -3, 1, 0}, + {-1, 3, -10, 123, 18, -6, 2, -1}, + {-1, 4, -14, 118, 28, -9, 3, -1}, + {-1, 5, -17, 112, 38, -12, 4, -1}, + {-1, 6, -19, 105, 48, -15, 5, -1}, + {-1, 6, -20, 97, 58, -17, 6, -1}, + {-1, 6, -20, 88, 69, -19, 6, -1}, + {-1, 6, -20, 79, 79, -20, 6, -1}, + {-1, 6, -19, 69, 88, -20, 6, -1}, + {-1, 6, -17, 58, 97, -20, 6, -1}, + {-1, 5, -15, 48, 105, -19, 6, -1}, + {-1, 4, -12, 38, 112, -17, 5, -1}, + {-1, 3, -9, 28, 118, -14, 4, -1}, + {-1, 2, -6, 18, 123, -10, 3, -1}, + { 0, 1, -3, 8, 126, -6, 2, 0} +#elif FILTER_ALPHA == 55 + /* alpha = 0.55 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + { 0, 1, -5, 126, 8, -3, 1, 0}, + {-1, 2, -10, 123, 18, -6, 2, 0}, + {-1, 4, -13, 118, 27, -9, 3, -1}, + {-1, 5, -16, 112, 37, -12, 4, -1}, + {-1, 5, -18, 105, 48, -14, 4, -1}, + {-1, 5, -19, 97, 58, -16, 5, -1}, + {-1, 6, -19, 88, 68, -18, 5, -1}, + {-1, 6, -19, 78, 78, -19, 6, -1}, + {-1, 5, -18, 68, 88, -19, 6, -1}, + {-1, 5, -16, 58, 97, -19, 5, -1}, + {-1, 4, -14, 48, 105, -18, 5, -1}, + {-1, 4, -12, 37, 112, -16, 5, -1}, + {-1, 3, -9, 27, 118, -13, 4, -1}, + { 0, 2, -6, 18, 123, -10, 2, -1}, + { 0, 1, -3, 8, 126, -5, 1, 0} +#elif FILTER_ALPHA == 50 + /* alpha = 0.50 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + { 0, 1, -5, 126, 8, -3, 1, 0}, + { 0, 2, -10, 122, 18, -6, 2, 0}, + {-1, 3, -13, 118, 27, -9, 3, 0}, + {-1, 4, -16, 112, 37, -11, 3, 0}, + {-1, 5, -17, 104, 48, -14, 4, -1}, + {-1, 5, -18, 96, 58, -16, 5, -1}, + {-1, 5, -19, 88, 68, -17, 5, -1}, + {-1, 5, -18, 78, 78, -18, 5, -1}, + {-1, 5, -17, 68, 88, -19, 5, -1}, + {-1, 5, -16, 58, 96, -18, 5, -1}, + {-1, 4, -14, 48, 104, -17, 5, -1}, + { 0, 3, -11, 37, 112, -16, 4, -1}, + { 0, 3, -9, 27, 118, -13, 3, -1}, + { 0, 2, -6, 18, 122, -10, 2, 0}, + { 0, 1, -3, 8, 126, -5, 1, 0} +#elif FILTER_ALPHA == 0 + /* Lagrangian interpolation filter */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + { 0, 1, -5, 126, 8, -3, 1, 0}, + {-1, 3, -10, 122, 18, -6, 2, 0}, + {-1, 4, -13, 118, 27, -9, 3, -1}, + {-1, 4, -16, 112, 37, -11, 4, -1}, + {-1, 5, -18, 105, 48, -14, 4, -1}, + {-1, 5, -19, 97, 58, -16, 5, -1}, + {-1, 6, -19, 88, 68, -18, 5, -1}, + {-1, 6, -19, 78, 78, -19, 6, -1}, + {-1, 5, -18, 68, 88, -19, 6, -1}, + {-1, 5, -16, 58, 97, -19, 5, -1}, + {-1, 4, -14, 48, 105, -18, 5, -1}, + {-1, 4, -11, 37, 112, -16, 4, -1}, + {-1, 3, -9, 27, 118, -13, 4, -1}, + { 0, 2, -6, 18, 122, -10, 3, -1}, + { 0, 1, -3, 8, 126, -5, 1, 0} +#endif /* FILTER_ALPHA */ +#else /* SUBPEL_SHIFTS==16 */ +#if FILTER_ALPHA == 70 + /* alpha = 0.70 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + {-1, 4, -11, 123, 18, -7, 3, -1}, + {-2, 6, -18, 113, 38, -13, 5, -1}, + {-2, 8, -22, 98, 59, -18, 7, -2}, + {-2, 8, -21, 79, 79, -21, 8, -2}, + {-2, 7, -18, 59, 98, -22, 8, -2}, + {-1, 5, -13, 38, 113, -18, 6, -2}, + {-1, 3, -7, 18, 123, -11, 4, -1} +#elif FILTER_ALPHA == 65 + /* alpha = 0.65 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + {-1, 3, -10, 123, 18, -6, 2, -1}, + {-1, 5, -17, 112, 38, -13, 5, -1}, + {-2, 7, -21, 98, 59, -17, 6, -2}, + {-2, 7, -20, 79, 79, -20, 7, -2}, + {-2, 6, -17, 59, 98, -21, 7, -2}, + {-1, 5, -13, 38, 112, -17, 5, -1}, + {-1, 2, -6, 18, 123, -10, 3, -1} +#elif FILTER_ALPHA == 60 + /* alpha = 0.60 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + {-1, 3, -10, 123, 18, -6, 2, -1}, + {-1, 5, -17, 112, 38, -12, 4, -1}, + {-1, 6, -20, 97, 58, -17, 6, -1}, + {-1, 6, -20, 79, 79, -20, 6, -1}, + {-1, 6, -17, 58, 97, -20, 6, -1}, + {-1, 4, -12, 38, 112, -17, 5, -1}, + {-1, 2, -6, 18, 123, -10, 3, -1} +#elif FILTER_ALPHA == 55 + /* alpha = 0.55 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + {-1, 2, -10, 123, 18, -6, 2, 0}, + {-1, 5, -16, 112, 37, -12, 4, -1}, + {-1, 5, -19, 97, 58, -16, 5, -1}, + {-1, 6, -19, 78, 78, -19, 6, -1}, + {-1, 5, -16, 58, 97, -19, 5, -1}, + {-1, 4, -12, 37, 112, -16, 5, -1}, + { 0, 2, -6, 18, 123, -10, 2, -1} +#elif FILTER_ALPHA == 50 + /* alpha = 0.50 */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + { 0, 2, -10, 122, 18, -6, 2, 0}, + {-1, 4, -16, 112, 37, -11, 3, 0}, + {-1, 5, -18, 96, 58, -16, 5, -1}, + {-1, 5, -18, 78, 78, -18, 5, -1}, + {-1, 5, -16, 58, 96, -18, 5, -1}, + { 0, 3, -11, 37, 112, -16, 4, -1}, + { 0, 2, -6, 18, 122, -10, 2, 0} +#elif FILTER_ALPHA == 0 + /* Lagrangian interpolation filter */ + { 0, 0, 0, 128, 0, 0, 0, 0}, + {-1, 3, -10, 122, 18, -6, 2, 0}, + {-1, 4, -16, 112, 37, -11, 4, -1}, + {-1, 5, -19, 97, 58, -16, 5, -1}, + {-1, 6, -19, 78, 78, -19, 6, -1}, + {-1, 5, -16, 58, 97, -19, 5, -1}, + {-1, 4, -11, 37, 112, -16, 4, -1}, + { 0, 2, -6, 18, 122, -10, 3, -1}, +#endif /* FILTER_ALPHA */ +#endif /* SUBPEL_SHIFTS==16 */ +}; + +#else // CONFIG_ENHANCED_INTERP + DECLARE_ALIGNED(16, const short, vp8_sub_pel_filters[8][6]) = { @@ -38,6 +245,8 @@ DECLARE_ALIGNED(16, const short, vp8_sub_pel_filters[8][6]) = { 0, -1, 12, 123, -6, 0 }, }; +#endif // CONFIG_ENHANCED_INTERP + static void filter_block2d_first_pass ( unsigned char *src_ptr, @@ -56,13 +265,37 @@ static void filter_block2d_first_pass { for (j = 0; j < output_width; j++) { +#if INTERP_EXTEND == 3 Temp = ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[0]) + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[1]) + - ((int)src_ptr[0] * vp8_filter[2]) + - ((int)src_ptr[pixel_step] * vp8_filter[3]) + - ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + - ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + + ((int)src_ptr[0] * vp8_filter[2]) + + ((int)src_ptr[pixel_step] * vp8_filter[3]) + + ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + + ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#elif INTERP_EXTEND == 4 + Temp = ((int)src_ptr[-3 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[2]) + + ((int)src_ptr[0] * vp8_filter[3]) + + ((int)src_ptr[pixel_step] * vp8_filter[4]) + + ((int)src_ptr[2 * pixel_step] * vp8_filter[5]) + + ((int)src_ptr[3 * pixel_step] * vp8_filter[6]) + + ((int)src_ptr[4 * pixel_step] * vp8_filter[7]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#elif INTERP_EXTEND == 5 + Temp = ((int)src_ptr[-4 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-3 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[2]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[3]) + + ((int)src_ptr[0] * vp8_filter[4]) + + ((int)src_ptr[pixel_step] * vp8_filter[5]) + + ((int)src_ptr[2 * pixel_step] * vp8_filter[6]) + + ((int)src_ptr[3 * pixel_step] * vp8_filter[7]) + + ((int)src_ptr[4 * pixel_step] * vp8_filter[8]) + + ((int)src_ptr[5 * pixel_step] * vp8_filter[9]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#endif /* Normalize back to 0-255 */ Temp = Temp >> VP8_FILTER_SHIFT; @@ -102,13 +335,37 @@ static void filter_block2d_second_pass for (j = 0; j < output_width; j++) { /* Apply filter */ +#if INTERP_EXTEND == 3 Temp = ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[0]) + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[1]) + - ((int)src_ptr[0] * vp8_filter[2]) + - ((int)src_ptr[pixel_step] * vp8_filter[3]) + - ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + - ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + + ((int)src_ptr[0] * vp8_filter[2]) + + ((int)src_ptr[pixel_step] * vp8_filter[3]) + + ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + + ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#elif INTERP_EXTEND == 4 + Temp = ((int)src_ptr[-3 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[2]) + + ((int)src_ptr[0] * vp8_filter[3]) + + ((int)src_ptr[pixel_step] * vp8_filter[4]) + + ((int)src_ptr[2 * pixel_step] * vp8_filter[5]) + + ((int)src_ptr[3 * pixel_step] * vp8_filter[6]) + + ((int)src_ptr[4 * pixel_step] * vp8_filter[7]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#elif INTERP_EXTEND == 5 + Temp = ((int)src_ptr[-4 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-3 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[2]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[3]) + + ((int)src_ptr[0] * vp8_filter[4]) + + ((int)src_ptr[pixel_step] * vp8_filter[5]) + + ((int)src_ptr[2 * pixel_step] * vp8_filter[6]) + + ((int)src_ptr[3 * pixel_step] * vp8_filter[7]) + + ((int)src_ptr[4 * pixel_step] * vp8_filter[8]) + + ((int)src_ptr[5 * pixel_step] * vp8_filter[9]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#endif /* Normalize back to 0-255 */ Temp = Temp >> VP8_FILTER_SHIFT; @@ -128,6 +385,83 @@ static void filter_block2d_second_pass } } +/* + * The only functional difference between filter_block2d_second_pass() + * and this function is that filter_block2d_second_pass() does a sixtap + * filter on the input and stores it in the output. This function + * (filter_block2d_second_pass_avg()) does a sixtap filter on the input, + * and then averages that with the content already present in the output + * ((filter_result + dest + 1) >> 1) and stores that in the output. + */ +static void filter_block2d_second_pass_avg +( + int *src_ptr, + unsigned char *output_ptr, + int output_pitch, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + /* Apply filter */ +#if INTERP_EXTEND == 3 + Temp = ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[0] * vp8_filter[2]) + + ((int)src_ptr[pixel_step] * vp8_filter[3]) + + ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + + ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#elif INTERP_EXTEND == 4 + Temp = ((int)src_ptr[-3 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[2]) + + ((int)src_ptr[0] * vp8_filter[3]) + + ((int)src_ptr[pixel_step] * vp8_filter[4]) + + ((int)src_ptr[2 * pixel_step] * vp8_filter[5]) + + ((int)src_ptr[3 * pixel_step] * vp8_filter[6]) + + ((int)src_ptr[4 * pixel_step] * vp8_filter[7]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#elif INTERP_EXTEND == 5 + Temp = ((int)src_ptr[-4 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-3 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[2]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[3]) + + ((int)src_ptr[0] * vp8_filter[4]) + + ((int)src_ptr[pixel_step] * vp8_filter[5]) + + ((int)src_ptr[2 * pixel_step] * vp8_filter[6]) + + ((int)src_ptr[3 * pixel_step] * vp8_filter[7]) + + ((int)src_ptr[4 * pixel_step] * vp8_filter[8]) + + ((int)src_ptr[5 * pixel_step] * vp8_filter[9]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ +#endif + + /* Normalize back to 0-255 */ + Temp = Temp >> VP8_FILTER_SHIFT; + + if (Temp < 0) + Temp = 0; + else if (Temp > 255) + Temp = 255; + + output_ptr[j] = (unsigned char) ((output_ptr[j] + Temp + 1) >> 1); + src_ptr++; + } + + /* Start next row */ + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_pitch; + } +} static void filter_block2d ( @@ -139,13 +473,14 @@ static void filter_block2d const short *VFilter ) { - int FData[9*4]; /* Temp data buffer used in filtering */ + int FData[(3+INTERP_EXTEND*2)*4]; /* Temp data buffer used in filtering */ /* First filter 1-D horizontally... */ - filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 9, 4, HFilter); + filter_block2d_first_pass(src_ptr - ((INTERP_EXTEND-1) * src_pixels_per_line), FData, src_pixels_per_line, 1, + 3+INTERP_EXTEND*2, 4, HFilter); /* then filter verticaly... */ - filter_block2d_second_pass(FData + 8, output_ptr, output_pitch, 4, 4, 4, 4, VFilter); + filter_block2d_second_pass(FData + 4*(INTERP_EXTEND-1), output_ptr, output_pitch, 4, 4, 4, 4, VFilter); } @@ -179,20 +514,48 @@ void vp8_sixtap_predict8x8_c { const short *HFilter; const short *VFilter; - int FData[13*16]; /* Temp data buffer used in filtering */ + // int FData[(7+INTERP_EXTEND*2)*16]; /* Temp data buffer used in filtering */ + int FData[(7+INTERP_EXTEND*2)*8]; /* Temp data buffer used in filtering */ HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ /* First filter 1-D horizontally... */ - filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 13, 8, HFilter); + filter_block2d_first_pass(src_ptr - ((INTERP_EXTEND-1) * src_pixels_per_line), FData, src_pixels_per_line, 1, + 7+INTERP_EXTEND*2, 8, HFilter); /* then filter verticaly... */ - filter_block2d_second_pass(FData + 16, dst_ptr, dst_pitch, 8, 8, 8, 8, VFilter); + filter_block2d_second_pass(FData + 8*(INTERP_EXTEND-1), dst_ptr, dst_pitch, 8, 8, 8, 8, VFilter); } +void vp8_sixtap_predict_avg8x8_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + // int FData[(7+INTERP_EXTEND*2)*16]; /* Temp data buffer used in filtering */ + int FData[(7+INTERP_EXTEND*2)*8]; /* Temp data buffer used in filtering */ + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + /* First filter 1-D horizontally... */ + filter_block2d_first_pass(src_ptr - ((INTERP_EXTEND-1) * src_pixels_per_line), FData, src_pixels_per_line, 1, + 7+INTERP_EXTEND*2, 8, HFilter); + + /* then filter verticaly... */ + filter_block2d_second_pass_avg(FData + 8*(INTERP_EXTEND-1), dst_ptr, dst_pitch, 8, 8, 8, 8, VFilter); +} + void vp8_sixtap_predict8x4_c ( unsigned char *src_ptr, @@ -205,17 +568,19 @@ void vp8_sixtap_predict8x4_c { const short *HFilter; const short *VFilter; - int FData[13*16]; /* Temp data buffer used in filtering */ + // int FData[(7+INTERP_EXTEND*2)*16]; /* Temp data buffer used in filtering */ + int FData[(3+INTERP_EXTEND*2)*8]; /* Temp data buffer used in filtering */ HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ /* First filter 1-D horizontally... */ - filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 9, 8, HFilter); + filter_block2d_first_pass(src_ptr - ((INTERP_EXTEND-1) * src_pixels_per_line), FData, src_pixels_per_line, 1, + 3+INTERP_EXTEND*2, 8, HFilter); /* then filter verticaly... */ - filter_block2d_second_pass(FData + 16, dst_ptr, dst_pitch, 8, 8, 4, 8, VFilter); + filter_block2d_second_pass(FData + 8*(INTERP_EXTEND-1), dst_ptr, dst_pitch, 8, 8, 4, 8, VFilter); } @@ -231,20 +596,48 @@ void vp8_sixtap_predict16x16_c { const short *HFilter; const short *VFilter; - int FData[21*24]; /* Temp data buffer used in filtering */ + // int FData[(15+INTERP_EXTEND*2)*24]; /* Temp data buffer used in filtering */ + int FData[(15+INTERP_EXTEND*2)*16]; /* Temp data buffer used in filtering */ HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ /* First filter 1-D horizontally... */ - filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 21, 16, HFilter); + filter_block2d_first_pass(src_ptr - ((INTERP_EXTEND-1) * src_pixels_per_line), FData, src_pixels_per_line, 1, + 15+INTERP_EXTEND*2, 16, HFilter); /* then filter verticaly... */ - filter_block2d_second_pass(FData + 32, dst_ptr, dst_pitch, 16, 16, 16, 16, VFilter); + filter_block2d_second_pass(FData + 16*(INTERP_EXTEND-1), dst_ptr, dst_pitch, 16, 16, 16, 16, VFilter); } +void vp8_sixtap_predict_avg16x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + // int FData[(15+INTERP_EXTEND*2)*24]; /* Temp data buffer used in filtering */ + int FData[(15+INTERP_EXTEND*2)*16]; /* Temp data buffer used in filtering */ + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + /* First filter 1-D horizontally... */ + filter_block2d_first_pass(src_ptr - ((INTERP_EXTEND-1) * src_pixels_per_line), FData, + src_pixels_per_line, 1, 15+INTERP_EXTEND*2, 16, HFilter); + + /* then filter verticaly... */ + filter_block2d_second_pass_avg(FData + 16*(INTERP_EXTEND-1), dst_ptr, dst_pitch, + 16, 16, 16, 16, VFilter); +} /**************************************************************************** * @@ -349,6 +742,44 @@ static void filter_block2d_bil_second_pass } } +/* + * As before for filter_block2d_second_pass_avg(), the functional difference + * between filter_block2d_bil_second_pass() and filter_block2d_bil_second_pass_avg() + * is that filter_block2d_bil_second_pass() does a bilinear filter on input + * and stores the result in output; filter_block2d_bil_second_pass_avg(), + * instead, does a bilinear filter on input, averages the resulting value + * with the values already present in the output and stores the result of + * that back into the output ((filter_result + dest + 1) >> 1). + */ +static void filter_block2d_bil_second_pass_avg +( + unsigned short *src_ptr, + unsigned char *dst_ptr, + int dst_pitch, + unsigned int height, + unsigned int width, + const short *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + /* Apply filter */ + Temp = ((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[width] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2); + dst_ptr[j] = (unsigned int)(((Temp >> VP8_FILTER_SHIFT) + dst_ptr[j] + 1) >> 1); + src_ptr++; + } + + /* Next row... */ + dst_ptr += dst_pitch; + } +} /**************************************************************************** * @@ -395,6 +826,26 @@ static void filter_block2d_bil filter_block2d_bil_second_pass(FData, dst_ptr, dst_pitch, Height, Width, VFilter); } +static void filter_block2d_bil_avg +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + unsigned int src_pitch, + unsigned int dst_pitch, + const short *HFilter, + const short *VFilter, + int Width, + int Height +) +{ + unsigned short FData[17*16]; /* Temp data buffer used in filtering */ + + /* First filter 1-D horizontally... */ + filter_block2d_bil_first_pass(src_ptr, FData, src_pitch, Height + 1, Width, HFilter); + + /* then 1-D vertically... */ + filter_block2d_bil_second_pass_avg(FData, dst_ptr, dst_pitch, Height, Width, VFilter); +} void vp8_bilinear_predict4x4_c ( @@ -454,6 +905,26 @@ void vp8_bilinear_predict8x8_c } +void vp8_bilinear_predict_avg8x8_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + filter_block2d_bil_avg(src_ptr, dst_ptr, src_pixels_per_line, + dst_pitch, HFilter, VFilter, 8, 8); +} + void vp8_bilinear_predict8x4_c ( unsigned char *src_ptr, @@ -492,3 +963,23 @@ void vp8_bilinear_predict16x16_c filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 16, 16); } + +void vp8_bilinear_predict_avg16x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + filter_block2d_bil_avg(src_ptr, dst_ptr, src_pixels_per_line, + dst_pitch, HFilter, VFilter, 16, 16); +} diff --git a/vp8/common/filter.h b/vp8/common/filter.h index 0f225c25a..d502216d2 100644 --- a/vp8/common/filter.h +++ b/vp8/common/filter.h @@ -8,15 +8,23 @@ * be found in the AUTHORS file in the root of the source tree. */ - #ifndef FILTER_H #define FILTER_H +#include "vpx_config.h" +#include "vpx_scale/yv12config.h" + #define BLOCK_HEIGHT_WIDTH 4 #define VP8_FILTER_WEIGHT 128 #define VP8_FILTER_SHIFT 7 -extern const short vp8_bilinear_filters[8][2]; -extern const short vp8_sub_pel_filters[8][6]; +#if CONFIG_SIXTEENTH_SUBPEL_UV +#define SUBPEL_SHIFTS 16 +#else +#define SUBPEL_SHIFTS 8 +#endif + +extern const short vp8_bilinear_filters[SUBPEL_SHIFTS][2]; +extern const short vp8_sub_pel_filters[SUBPEL_SHIFTS][INTERP_EXTEND*2]; #endif //FILTER_H diff --git a/vp8/common/findnearmv.c b/vp8/common/findnearmv.c index c1022363e..a74147106 100644 --- a/vp8/common/findnearmv.c +++ b/vp8/common/findnearmv.c @@ -21,10 +21,12 @@ const unsigned char vp8_mbsplit_offset[4][16] = { /* Predict motion vectors using those from already-decoded nearby blocks. Note that we only consider one 4x4 subblock from each candidate 16x16 macroblock. */ + void vp8_find_near_mvs ( MACROBLOCKD *xd, const MODE_INFO *here, + const MODE_INFO *lf_here, int_mv *nearest, int_mv *nearby, int_mv *best_mv, @@ -36,6 +38,7 @@ void vp8_find_near_mvs const MODE_INFO *above = here - xd->mode_info_stride; const MODE_INFO *left = here - 1; const MODE_INFO *aboveleft = above - 1; + const MODE_INFO *third = NULL; int_mv near_mvs[4]; int_mv *mv = near_mvs; int *cntx = cnt; @@ -51,10 +54,10 @@ void vp8_find_near_mvs if (above->mbmi.mv.as_int) { (++mv)->as_int = above->mbmi.mv.as_int; - mv_bias(ref_frame_sign_bias[above->mbmi.ref_frame], refframe, mv, ref_frame_sign_bias); + mv_bias(ref_frame_sign_bias[above->mbmi.ref_frame], + refframe, mv, ref_frame_sign_bias); ++cntx; } - *cntx += 2; } @@ -64,38 +67,44 @@ void vp8_find_near_mvs if (left->mbmi.mv.as_int) { int_mv this_mv; - this_mv.as_int = left->mbmi.mv.as_int; - mv_bias(ref_frame_sign_bias[left->mbmi.ref_frame], refframe, &this_mv, ref_frame_sign_bias); + mv_bias(ref_frame_sign_bias[left->mbmi.ref_frame], + refframe, &this_mv, ref_frame_sign_bias); if (this_mv.as_int != mv->as_int) { (++mv)->as_int = this_mv.as_int; ++cntx; } - *cntx += 2; } else cnt[CNT_INTRA] += 2; } - - /* Process above left */ - if (aboveleft->mbmi.ref_frame != INTRA_FRAME) + /* Process above left or the one frome last frame */ + if ( aboveleft->mbmi.ref_frame != INTRA_FRAME|| + (lf_here->mbmi.ref_frame==LAST_FRAME && refframe == LAST_FRAME)) { if (aboveleft->mbmi.mv.as_int) + { + third = aboveleft; + } + else if(lf_here->mbmi.mv.as_int) + { + third = lf_here; + } + if(third) { int_mv this_mv; - - this_mv.as_int = aboveleft->mbmi.mv.as_int; - mv_bias(ref_frame_sign_bias[aboveleft->mbmi.ref_frame], refframe, &this_mv, ref_frame_sign_bias); + this_mv.as_int = third->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[third->mbmi.ref_frame], + refframe, &this_mv, ref_frame_sign_bias); if (this_mv.as_int != mv->as_int) { (++mv)->as_int = this_mv.as_int; ++cntx; } - *cntx += 1; } else @@ -105,14 +114,16 @@ void vp8_find_near_mvs /* If we have three distinct MV's ... */ if (cnt[CNT_SPLITMV]) { - /* See if above-left MV can be merged with NEAREST */ + /* See if the third MV can be merged with NEAREST */ if (mv->as_int == near_mvs[CNT_NEAREST].as_int) cnt[CNT_NEAREST] += 1; } cnt[CNT_SPLITMV] = ((above->mbmi.mode == SPLITMV) + (left->mbmi.mode == SPLITMV)) * 2 - + (aboveleft->mbmi.mode == SPLITMV); + + ( + lf_here->mbmi.mode == SPLITMV || + aboveleft->mbmi.mode == SPLITMV); /* Swap near and nearest if necessary */ if (cnt[CNT_NEAR] > cnt[CNT_NEAREST]) @@ -135,21 +146,40 @@ void vp8_find_near_mvs nearest->as_int = near_mvs[CNT_NEAREST].as_int; nearby->as_int = near_mvs[CNT_NEAR].as_int; + /* Make sure that the 1/8th bits of the Mvs are zero if high_precision + * is not being used, by truncating the last bit towards 0 + */ +#if CONFIG_HIGH_PRECISION_MV + if (!xd->allow_high_precision_mv) + { + if (best_mv->as_mv.row & 1) + best_mv->as_mv.row += (best_mv->as_mv.row > 0 ? -1 : 1); + if (best_mv->as_mv.col & 1) + best_mv->as_mv.col += (best_mv->as_mv.col > 0 ? -1 : 1); + if (nearest->as_mv.row & 1) + nearest->as_mv.row += (nearest->as_mv.row > 0 ? -1 : 1); + if (nearest->as_mv.col & 1) + nearest->as_mv.col += (nearest->as_mv.col > 0 ? -1 : 1); + if (nearby->as_mv.row & 1) + nearby->as_mv.row += (nearby->as_mv.row > 0 ? -1 : 1); + if (nearby->as_mv.col & 1) + nearby->as_mv.col += (nearby->as_mv.col > 0 ? -1 : 1); + } +#endif + //TODO: move clamp outside findnearmv vp8_clamp_mv2(nearest, xd); vp8_clamp_mv2(nearby, xd); vp8_clamp_mv2(best_mv, xd); } -vp8_prob *vp8_mv_ref_probs( +vp8_prob *vp8_mv_ref_probs(VP8_COMMON *pc, vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4] ) { - p[0] = vp8_mode_contexts [near_mv_ref_ct[0]] [0]; - p[1] = vp8_mode_contexts [near_mv_ref_ct[1]] [1]; - p[2] = vp8_mode_contexts [near_mv_ref_ct[2]] [2]; - p[3] = vp8_mode_contexts [near_mv_ref_ct[3]] [3]; - /*p[3] = vp8_mode_contexts [near_mv_ref_ct[1] + near_mv_ref_ct[2] + near_mv_ref_ct[3]] [3];*/ + p[0] = pc->vp8_mode_contexts [near_mv_ref_ct[0]] [0]; + p[1] = pc->vp8_mode_contexts [near_mv_ref_ct[1]] [1]; + p[2] = pc->vp8_mode_contexts [near_mv_ref_ct[2]] [2]; + p[3] = pc->vp8_mode_contexts [near_mv_ref_ct[3]] [3]; return p; } - diff --git a/vp8/common/findnearmv.h b/vp8/common/findnearmv.h index c142a0415..523000b55 100644 --- a/vp8/common/findnearmv.h +++ b/vp8/common/findnearmv.h @@ -16,6 +16,7 @@ #include "blockd.h" #include "modecont.h" #include "treecoder.h" +#include "onyxc_int.h" static void mv_bias(int refmb_ref_frame_sign_bias, int refframe, int_mv *mvp, const int *ref_frame_sign_bias) @@ -75,13 +76,14 @@ void vp8_find_near_mvs ( MACROBLOCKD *xd, const MODE_INFO *here, + const MODE_INFO *lfhere, int_mv *nearest, int_mv *nearby, int_mv *best, int near_mv_ref_cts[4], int refframe, int *ref_frame_sign_bias ); -vp8_prob *vp8_mv_ref_probs( +vp8_prob *vp8_mv_ref_probs(VP8_COMMON *pc, vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4] ); @@ -125,8 +127,6 @@ static B_PREDICTION_MODE left_block_mode(const MODE_INFO *cur_mb, int b) --cur_mb; switch (cur_mb->mbmi.mode) { - case B_PRED: - return (cur_mb->bmi + b + 3)->as_mode; case DC_PRED: return B_DC_PRED; case V_PRED: @@ -135,15 +135,18 @@ static B_PREDICTION_MODE left_block_mode(const MODE_INFO *cur_mb, int b) return B_HE_PRED; case TM_PRED: return B_TM_PRED; + case I8X8_PRED: + case B_PRED: + return (cur_mb->bmi + b + 3)->as_mode.first; default: return B_DC_PRED; } } - - return (cur_mb->bmi + b - 1)->as_mode; + return (cur_mb->bmi + b - 1)->as_mode.first; } -static B_PREDICTION_MODE above_block_mode(const MODE_INFO *cur_mb, int b, int mi_stride) +static B_PREDICTION_MODE above_block_mode(const MODE_INFO + *cur_mb, int b, int mi_stride) { if (!(b >> 2)) { @@ -152,8 +155,6 @@ static B_PREDICTION_MODE above_block_mode(const MODE_INFO *cur_mb, int b, int mi switch (cur_mb->mbmi.mode) { - case B_PRED: - return (cur_mb->bmi + b + 12)->as_mode; case DC_PRED: return B_DC_PRED; case V_PRED: @@ -162,12 +163,15 @@ static B_PREDICTION_MODE above_block_mode(const MODE_INFO *cur_mb, int b, int mi return B_HE_PRED; case TM_PRED: return B_TM_PRED; + case I8X8_PRED: + case B_PRED: + return (cur_mb->bmi + b + 12)->as_mode.first; default: return B_DC_PRED; } } - return (cur_mb->bmi + b - 4)->as_mode; + return (cur_mb->bmi + b - 4)->as_mode.first; } #endif diff --git a/vp8/common/generic/systemdependent.c b/vp8/common/generic/systemdependent.c index 75b0984bb..6168dc5ef 100644 --- a/vp8/common/generic/systemdependent.c +++ b/vp8/common/generic/systemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/g_common.h" #include "vp8/common/subpixel.h" #include "vp8/common/loopfilter.h" @@ -17,54 +17,9 @@ #include "vp8/common/idct.h" #include "vp8/common/onyxc_int.h" -#if CONFIG_MULTITHREAD -#if HAVE_UNISTD_H -#include -#elif defined(_WIN32) -#include -typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); -#endif -#endif - extern void vp8_arch_x86_common_init(VP8_COMMON *ctx); extern void vp8_arch_arm_common_init(VP8_COMMON *ctx); -#if CONFIG_MULTITHREAD -static int get_cpu_count() -{ - int core_count = 16; - -#if HAVE_UNISTD_H -#if defined(_SC_NPROCESSORS_ONLN) - core_count = sysconf(_SC_NPROCESSORS_ONLN); -#elif defined(_SC_NPROC_ONLN) - core_count = sysconf(_SC_NPROC_ONLN); -#endif -#elif defined(_WIN32) - { - PGNSI pGNSI; - SYSTEM_INFO sysinfo; - - /* Call GetNativeSystemInfo if supported or - * GetSystemInfo otherwise. */ - - pGNSI = (PGNSI) GetProcAddress( - GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); - if (pGNSI != NULL) - pGNSI(&sysinfo); - else - GetSystemInfo(&sysinfo); - - core_count = sysinfo.dwNumberOfProcessors; - } -#else - /* other platforms */ -#endif - - return core_count > 0 ? core_count : 1; -} -#endif - void vp8_machine_specific_config(VP8_COMMON *ctx) { #if CONFIG_RUNTIME_CPU_DETECT @@ -75,34 +30,67 @@ void vp8_machine_specific_config(VP8_COMMON *ctx) rtcd->idct.idct1_scalar_add = vp8_dc_only_idct_add_c; rtcd->idct.iwalsh1 = vp8_short_inv_walsh4x4_1_c; rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_c; - + rtcd->idct.idct8 = vp8_short_idct8x8_c; + rtcd->idct.idct1_scalar_add_8x8 = vp8_dc_only_idct_add_8x8_c; + rtcd->idct.ihaar2 = vp8_short_ihaar2x2_c; rtcd->recon.copy16x16 = vp8_copy_mem16x16_c; rtcd->recon.copy8x8 = vp8_copy_mem8x8_c; + rtcd->recon.avg16x16 = vp8_avg_mem16x16_c; + rtcd->recon.avg8x8 = vp8_avg_mem8x8_c; rtcd->recon.copy8x4 = vp8_copy_mem8x4_c; rtcd->recon.recon = vp8_recon_b_c; + rtcd->recon.recon_uv = vp8_recon_uv_b_c; rtcd->recon.recon2 = vp8_recon2b_c; rtcd->recon.recon4 = vp8_recon4b_c; rtcd->recon.recon_mb = vp8_recon_mb_c; rtcd->recon.recon_mby = vp8_recon_mby_c; rtcd->recon.build_intra_predictors_mby = vp8_build_intra_predictors_mby; +#if CONFIG_COMP_INTRA_PRED + rtcd->recon.build_comp_intra_predictors_mby = + vp8_build_comp_intra_predictors_mby; +#endif rtcd->recon.build_intra_predictors_mby_s = vp8_build_intra_predictors_mby_s; rtcd->recon.build_intra_predictors_mbuv = vp8_build_intra_predictors_mbuv; rtcd->recon.build_intra_predictors_mbuv_s = vp8_build_intra_predictors_mbuv_s; +#if CONFIG_COMP_INTRA_PRED + rtcd->recon.build_comp_intra_predictors_mbuv = + vp8_build_comp_intra_predictors_mbuv; +#endif rtcd->recon.intra4x4_predict = vp8_intra4x4_predict; +#if CONFIG_COMP_INTRA_PRED + rtcd->recon.comp_intra4x4_predict = + vp8_comp_intra4x4_predict; +#endif + rtcd->recon.intra8x8_predict = + vp8_intra8x8_predict; +#if CONFIG_COMP_INTRA_PRED + rtcd->recon.comp_intra8x8_predict = + vp8_comp_intra8x8_predict; +#endif + rtcd->recon.intra_uv4x4_predict = + vp8_intra_uv4x4_predict; +#if CONFIG_COMP_INTRA_PRED + rtcd->recon.comp_intra_uv4x4_predict = + vp8_comp_intra_uv4x4_predict; +#endif - rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_c; - rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_c; - rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_c; - rtcd->subpix.sixtap4x4 = vp8_sixtap_predict_c; - rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_c; - rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_c; - rtcd->subpix.bilinear8x4 = vp8_bilinear_predict8x4_c; - rtcd->subpix.bilinear4x4 = vp8_bilinear_predict4x4_c; + rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_c; + rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_c; + rtcd->subpix.sixtap_avg16x16 = vp8_sixtap_predict_avg16x16_c; + rtcd->subpix.sixtap_avg8x8 = vp8_sixtap_predict_avg8x8_c; + rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_c; + rtcd->subpix.sixtap4x4 = vp8_sixtap_predict_c; + rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_c; + rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_c; + rtcd->subpix.bilinear_avg16x16 = vp8_bilinear_predict_avg16x16_c; + rtcd->subpix.bilinear_avg8x8 = vp8_bilinear_predict_avg8x8_c; + rtcd->subpix.bilinear8x4 = vp8_bilinear_predict8x4_c; + rtcd->subpix.bilinear4x4 = vp8_bilinear_predict4x4_c; rtcd->loopfilter.normal_mb_v = vp8_loop_filter_mbv_c; rtcd->loopfilter.normal_b_v = vp8_loop_filter_bv_c; @@ -133,17 +121,10 @@ void vp8_machine_specific_config(VP8_COMMON *ctx) #if ARCH_ARM vp8_arch_arm_common_init(ctx); #endif -#if CONFIG_EXTEND_QRANGE rtcd->idct.idct1 = vp8_short_idct4x4llm_1_c; rtcd->idct.idct16 = vp8_short_idct4x4llm_c; rtcd->idct.idct1_scalar_add = vp8_dc_only_idct_add_c; rtcd->idct.iwalsh1 = vp8_short_inv_walsh4x4_1_c; rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_c; -#endif - - -#if CONFIG_MULTITHREAD - ctx->processor_core_count = get_cpu_count(); -#endif /* CONFIG_MULTITHREAD */ } diff --git a/vp8/common/idct.h b/vp8/common/idct.h index f5fd94dfd..e8ca23d66 100644 --- a/vp8/common/idct.h +++ b/vp8/common/idct.h @@ -31,6 +31,34 @@ #include "arm/idct_arm.h" #endif + +#ifndef vp8_idct_idct8 +#define vp8_idct_idct8 vp8_short_idct8x8_c +#endif +extern prototype_idct(vp8_idct_idct8); + +#ifndef vp8_idct_idct8_1 +#define vp8_idct_idct8_1 vp8_short_idct8x8_1_c +#endif +extern prototype_idct(vp8_idct_idct8_1); + +#ifndef vp8_idct_ihaar2 +#define vp8_idct_ihaar2 vp8_short_ihaar2x2_c +#endif +extern prototype_idct(vp8_idct_ihaar2); + +#ifndef vp8_idct_ihaar2_1 +#define vp8_idct_ihaar2_1 vp8_short_ihaar2x2_1_c +#endif +extern prototype_idct(vp8_idct_ihaar2_1); + +#ifndef vp8_idct_idct1_scalar_add_8x8 +#define vp8_idct_idct1_scalar_add_8x8 vp8_dc_only_idct_add_8x8_c +#endif +extern prototype_idct_scalar_add(vp8_idct_idct1_scalar_add_8x8); + + + #ifndef vp8_idct_idct1 #define vp8_idct_idct1 vp8_short_idct4x4llm_1_c #endif @@ -69,6 +97,12 @@ typedef struct vp8_second_order_fn_t iwalsh1; vp8_second_order_fn_t iwalsh16; + + vp8_idct_fn_t idct8; + vp8_idct_fn_t idct8_1; + vp8_idct_scalar_add_fn_t idct1_scalar_add_8x8; + vp8_idct_fn_t ihaar2; + vp8_idct_fn_t ihaar2_1; } vp8_idct_rtcd_vtable_t; #if CONFIG_RUNTIME_CPU_DETECT diff --git a/vp8/common/idctllm.c b/vp8/common/idctllm.c index a71e4be9c..f0536d5e4 100644 --- a/vp8/common/idctllm.c +++ b/vp8/common/idctllm.c @@ -22,11 +22,15 @@ * so * x * sqrt(2) * cos (pi/8) = x + x * (sqrt(2) *cos(pi/8)-1). **************************************************************************/ -#include "vpx_config.h" +#include "vpx_ports/config.h" + + +#include static const int cospi8sqrt2minus1 = 20091; static const int sinpi8sqrt2 = 35468; static const int rounding = 0; + void vp8_short_idct4x4llm_c(short *input, short *output, int pitch) { int i; @@ -76,20 +80,11 @@ void vp8_short_idct4x4llm_c(short *input, short *output, int pitch) temp2 = (ip[3] * sinpi8sqrt2 + rounding) >> 16; d1 = temp1 + temp2; - -#if !CONFIG_EXTEND_QRANGE - op[0] = (a1 + d1 + 4) >> 3; - op[3] = (a1 - d1 + 4) >> 3; - - op[1] = (b1 + c1 + 4) >> 3; - op[2] = (b1 - c1 + 4) >> 3; -#else op[0] = (a1 + d1 + 16) >> 5; op[3] = (a1 - d1 + 16) >> 5; op[1] = (b1 + c1 + 16) >> 5; op[2] = (b1 - c1 + 16) >> 5; -#endif ip += shortpitch; op += shortpitch; @@ -102,11 +97,7 @@ void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch) int a1; short *op = output; int shortpitch = pitch >> 1; -#if !CONFIG_EXTEND_QRANGE - a1 = ((input[0] + 4) >> 3); -#else a1 = ((input[0] + 16) >> 5); -#endif for (i = 0; i < 4; i++) { op[0] = a1; @@ -119,11 +110,7 @@ void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch) void vp8_dc_only_idct_add_c(short input_dc, unsigned char *pred_ptr, unsigned char *dst_ptr, int pitch, int stride) { -#if !CONFIG_EXTEND_QRANGE - int a1 = ((input_dc + 4) >> 3); -#else int a1 = ((input_dc + 16) >> 5); -#endif int r, c; for (r = 0; r < 4; r++) @@ -185,17 +172,11 @@ void vp8_short_inv_walsh4x4_c(short *input, short *output) c2 = a1 - b1; d2 = d1 - c1; -#if !CONFIG_EXTEND_QRANGE - op[0] = (a2 + 3) >> 3; - op[1] = (b2 + 3) >> 3; - op[2] = (c2 + 3) >> 3; - op[3] = (d2 + 3) >> 3; -#else op[0] = (a2 + 1) >> 2; op[1] = (b2 + 1) >> 2; op[2] = (c2 + 1) >> 2; op[3] = (d2 + 1) >> 2; -#endif + ip += 4; op += 4; } @@ -207,11 +188,7 @@ void vp8_short_inv_walsh4x4_1_c(short *input, short *output) int a1; short *op = output; -#if !CONFIG_EXTEND_QRANGE - a1 = (input[0] + 3 )>> 3; -#else a1 = (input[0] + 1 )>> 2; -#endif for (i = 0; i < 4; i++) { @@ -222,3 +199,212 @@ void vp8_short_inv_walsh4x4_1_c(short *input, short *output) op += 4; } } + + +void vp8_dc_only_idct_add_8x8_c(short input_dc, + unsigned char *pred_ptr, + unsigned char *dst_ptr, + int pitch, int stride) +{ + int a1 = ((input_dc + 16) >> 5); + int r, c, b; + unsigned char *orig_pred = pred_ptr; + unsigned char *orig_dst = dst_ptr; + for (b = 0; b < 4; b++) + { + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = a1 + pred_ptr[c] ; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dst_ptr[c] = (unsigned char) a ; + } + + dst_ptr += stride; + pred_ptr += pitch; + } + dst_ptr = orig_dst + (b+1)%2*4 + (b+1)/2*4*stride; + pred_ptr = orig_pred + (b+1)%2*4 + (b+1)/2*4*pitch; + } +} + +#define W1 2841 /* 2048*sqrt(2)*cos(1*pi/16) */ +#define W2 2676 /* 2048*sqrt(2)*cos(2*pi/16) */ +#define W3 2408 /* 2048*sqrt(2)*cos(3*pi/16) */ +#define W5 1609 /* 2048*sqrt(2)*cos(5*pi/16) */ +#define W6 1108 /* 2048*sqrt(2)*cos(6*pi/16) */ +#define W7 565 /* 2048*sqrt(2)*cos(7*pi/16) */ + +/* row (horizontal) IDCT + * + * 7 pi 1 dst[k] = sum c[l] * src[l] * cos( -- * + * ( k + - ) * l ) l=0 8 2 + * + * where: c[0] = 128 c[1..7] = 128*sqrt(2) */ + +static void idctrow (int *blk) +{ + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + /* shortcut */ + if (!((x1 = blk[4] << 11) | (x2 = blk[6]) | (x3 = blk[2]) | + (x4 = blk[1]) | (x5 = blk[7]) | (x6 = blk[5]) | (x7 = blk[3]))) + { + blk[0] = blk[1] = blk[2] = blk[3] = blk[4] + = blk[5] = blk[6] = blk[7] = blk[0] << 3; + return; + } + + x0 = (blk[0] << 11) + 128; /* for proper rounding in the fourth stage */ + /* first stage */ + x8 = W7 * (x4 + x5); + x4 = x8 + (W1 - W7) * x4; + x5 = x8 - (W1 + W7) * x5; + x8 = W3 * (x6 + x7); + x6 = x8 - (W3 - W5) * x6; + x7 = x8 - (W3 + W5) * x7; + + /* second stage */ + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2); + x2 = x1 - (W2 + W6) * x2; + x3 = x1 + (W2 - W6) * x3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + + /* third stage */ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + + /* fourth stage */ + blk[0] = (x7 + x1) >> 8; + blk[1] = (x3 + x2) >> 8; + blk[2] = (x0 + x4) >> 8; + blk[3] = (x8 + x6) >> 8; + blk[4] = (x8 - x6) >> 8; + blk[5] = (x0 - x4) >> 8; + blk[6] = (x3 - x2) >> 8; + blk[7] = (x7 - x1) >> 8; +} + +/* column (vertical) IDCT + * + * 7 pi 1 dst[8*k] = sum c[l] * src[8*l] * + * cos( -- * ( k + - ) * l ) l=0 8 2 + * + * where: c[0] = 1/1024 c[1..7] = (1/1024)*sqrt(2) */ +static void idctcol (int *blk) +{ + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + + /* shortcut */ + if (!((x1 = (blk[8 * 4] << 8)) | (x2 = blk[8 * 6]) | (x3 = blk[8 * 2]) | + (x4 = blk[8 * 1]) | (x5 = blk[8 * 7]) | (x6 = blk[8 * 5]) | + (x7 = blk[8 * 3]))) + { + blk[8 * 0] = blk[8 * 1] = blk[8 * 2] = blk[8 * 3] + = blk[8 * 4] = blk[8 * 5] = blk[8 * 6] + = blk[8 * 7] = ((blk[8 * 0] + 32) >>6); + return; + } + + x0 = (blk[8 * 0] << 8) + 16384; + + /* first stage */ + x8 = W7 * (x4 + x5) + 4; + x4 = (x8 + (W1 - W7) * x4) >> 3; + x5 = (x8 - (W1 + W7) * x5) >> 3; + x8 = W3 * (x6 + x7) + 4; + x6 = (x8 - (W3 - W5) * x6) >> 3; + x7 = (x8 - (W3 + W5) * x7) >> 3; + + /* second stage */ + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2) + 4; + x2 = (x1 - (W2 + W6) * x2) >> 3; + x3 = (x1 + (W2 - W6) * x3) >> 3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + + /* third stage */ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + + /* fourth stage */ + blk[8 * 0] = (x7 + x1 ) >> 14; + blk[8 * 1] = (x3 + x2 ) >> 14; + blk[8 * 2] = (x0 + x4 ) >> 14; + blk[8 * 3] = (x8 + x6 ) >> 14; + blk[8 * 4] = (x8 - x6 ) >> 14; + blk[8 * 5] = (x0 - x4 ) >> 14; + blk[8 * 6] = (x3 - x2 ) >> 14; + blk[8 * 7] = (x7 - x1 ) >> 14; +} + +#define TX_DIM 8 +void vp8_short_idct8x8_c(short *coefs, short *block, int pitch) +{ + int X[TX_DIM*TX_DIM]; + int i,j; + int shortpitch = pitch >> 1; + + for (i = 0; i < TX_DIM; i++) + { + for (j = 0; j < TX_DIM; j++) + { + X[i * TX_DIM + j] = (int)(coefs[i * TX_DIM + j]+1 + + (coefs[i * TX_DIM + j]<0))>>2; + } + } + for (i = 0; i < 8; i++) + idctrow (X + 8 * i); + + for (i = 0; i < 8; i++) + idctcol (X + i); + + for (i = 0; i < TX_DIM; i++) + { + for (j = 0; j < TX_DIM; j++) + { + block[i*shortpitch+j] = X[i * TX_DIM + j]>>1; + } + } +} + + +void vp8_short_ihaar2x2_c(short *input, short *output, int pitch) +{ + int i, x; + short *ip = input; //0,1, 4, 8 + short *op = output; + for (i = 0; i < 16; i++) + { + op[i] = 0; + } + + op[0] = (ip[0] + ip[1] + ip[4] + ip[8] + 1)>>1; + op[1] = (ip[0] - ip[1] + ip[4] - ip[8])>>1; + op[4] = (ip[0] + ip[1] - ip[4] - ip[8])>>1; + op[8] = (ip[0] - ip[1] - ip[4] + ip[8])>>1; +} + diff --git a/vp8/common/implicit_segmentation.c b/vp8/common/implicit_segmentation.c new file mode 100644 index 000000000..3f72f8455 --- /dev/null +++ b/vp8/common/implicit_segmentation.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vp8/common/onyxc_int.h" + +#define MAX_REGIONS 24000 +#define NULL 0 + +#define min_mbs_in_region 3 + +// this linked list structure holds equivalences for connected +// component labeling +struct list_el { + int label; + int seg_value; + int count; + struct list_el * next; +}; +typedef struct list_el item; + +// connected colorsegments +typedef struct +{ + int min_x; + int min_y; + int max_x; + int max_y; + long long sum_x; + long long sum_y; + int pixels; + int seg_value; + int label; +} segment_info; + + +typedef enum +{ + SEGMENT_MODE, + SEGMENT_MV, + SEGMENT_REFFRAME, + SEGMENT_SKIPPED +} SEGMENT_TYPE; + + +// this merges the two equivalence lists and +// then makes sure that every label points to the same +// equivalence list +void merge ( item *labels, int u, int v ) +{ + item *a = labels[u].next; + item *b = labels[v].next; + item c; + item *it = &c; + int count; + + // check if they are already merged + if(u==v || a==b) + return; + + count = a->count + b->count; + + // merge 2 sorted linked lists. + while ( a != NULL && b != NULL ) + { + if ( a->label < b->label) + { + it->next = a; + a = a->next; + } + else + { + it->next = b; + b = b->next; + } + + it = it->next; + } + + if ( a == NULL ) + it->next = b; + else + it->next = a; + + it = c.next; + + // make sure every equivalence in the linked list points to this new ll + while( it != NULL) + { + labels[it->label].next = c.next; + it=it->next; + } + c.next->count = count; + +} + +void segment_via_mode_info( VP8_COMMON *oci, int how) +{ + MODE_INFO *mi = oci->mi; + int i,j; + int mb_index = 0; + + int label=1; + int pitch = oci->mb_cols; + + // holds linked list equivalences + // the max should probably be allocated at a higher level in oci + item equivalences[MAX_REGIONS]; + int eq_ptr = 0; + item labels[MAX_REGIONS]; + segment_info segments[MAX_REGIONS]; + int label_count = 1; + int labeling[400*300]; + int *lp = labeling; + + label_count = 1; + memset(labels,0,sizeof(labels)); + memset(segments,0,sizeof(segments)); + + /* Go through each macroblock first pass labelling */ + for (i = 0; i < oci->mb_rows; i++,lp+=pitch) + { + for (j = 0; j < oci->mb_cols; j++) + { + // int above seg_value, left seg_value, this seg_value... + int a=-1,l=-1,n=-1; + + // above label, left label + int al=-1,ll=-1; + if(i) + { + al=lp[j-pitch]; + a = labels[al].next->seg_value; + } + if(j) + { + ll=lp[j-1]; + l = labels[ll].next->seg_value; + } + + // what setting are we going to do the implicit segmentation on + switch (how) + { + case SEGMENT_MODE: + n= mi[mb_index].mbmi.mode; + break; + case SEGMENT_MV: + n = mi[mb_index].mbmi.mv.as_int; + if(mi[mb_index].mbmi.ref_frame == INTRA_FRAME) + n=-9999999; + break; + case SEGMENT_REFFRAME: + n = mi[mb_index].mbmi.ref_frame; + break; + case SEGMENT_SKIPPED: + n = mi[mb_index].mbmi.mb_skip_coeff; + break; + } + + // above and left both have the same seg_value + if(n==a&&n==l) + { + // pick the lowest label + lp[j] = (alcount++; + + // merge the above and left equivalencies + merge( labels, al, ll ); + } + // this matches above seg_value + else if(n==a) + { + // give it the same label as above + lp[j]=al; + labels[al].next->count++; + } + // this matches left seg_value + else if(n==l) + { + // give it the same label as above + lp[j]=ll; + labels[ll].next->count++; + } + else + { + // new label doesn't match either + item *e = &labels[label]; + item *nl = &equivalences[eq_ptr++]; + lp[j]=label; + nl->label = label; + nl->next = 0; + nl->seg_value = n; + nl->count = 1; + e->next = nl; + label++; + } + mb_index++; + } + mb_index++; + } + lp = labeling; + + // give new labels to regions + for(i=1;icount >min_mbs_in_region && labels[labels[i].next->label].label == 0 ) + { + segment_info *cs= &segments[label_count]; + cs->label = label_count; + labels[labels[i].next->label].label = label_count++; + labels[labels[i].next->label].seg_value = labels[i].next->seg_value; + cs->seg_value = labels[labels[i].next->label].seg_value; + cs->min_x = oci->mb_cols; + cs->min_y = oci->mb_rows; + cs->max_x = 0; + cs->max_y = 0; + cs->sum_x = 0; + cs->sum_y = 0; + cs->pixels= 0; + + } + lp = labeling; + + // this is just to gather stats... + for(i=0;imb_rows;i++,lp+=pitch) + { + for(j=0;jmb_cols;j++) + { + segment_info *cs; + int oldlab = labels[lp[j]].next->label; + int lab = labels[oldlab].label; + lp[j] = lab; + + cs= &segments[lab]; + + cs->min_x = (jmin_x?j:cs->min_x); + cs->max_x = (j>cs->max_x?j:cs->max_x); + cs->min_y = (imin_y?i:cs->min_y); + cs->max_y = (i>cs->max_y?i:cs->max_y); + cs->sum_x += j; + cs->sum_y += i; + cs->pixels ++; + + lp[j] = lab; + mb_index++; + } + mb_index++; + } + + { + lp = labeling; + printf("labelling \n"); + mb_index = 0; + for(i=0;imb_rows;i++,lp+=pitch) + { + for(j=0;jmb_cols;j++) + { + printf("%4d",lp[j]); + } + printf(" "); + for(j=0;jmb_cols;j++,mb_index++) + { + //printf("%3d",mi[mb_index].mbmi.mode ); + printf("%4d:%4d",mi[mb_index].mbmi.mv.as_mv.row,mi[mb_index].mbmi.mv.as_mv.col ); + } + printf("\n"); + ++mb_index; + } + printf("\n"); + } +} + diff --git a/vp8/common/invtrans.c b/vp8/common/invtrans.c index 81a3f2d89..eed8363a3 100644 --- a/vp8/common/invtrans.c +++ b/vp8/common/invtrans.c @@ -24,13 +24,23 @@ static void recon_dcblock(MACROBLOCKD *x) } } +static void recon_dcblock_8x8(MACROBLOCKD *x) +{ + BLOCKD *b = &x->block[24]; //for coeff 0, 2, 8, 10 + x->block[0].dqcoeff[0] = b->diff[0]; + x->block[4].dqcoeff[0] = b->diff[1]; + x->block[8].dqcoeff[0] = b->diff[4]; + x->block[12].dqcoeff[0] = b->diff[8]; + +} + void vp8_inverse_transform_b(const vp8_idct_rtcd_vtable_t *rtcd, BLOCKD *b, int pitch) { - if (b->eob > 1) - IDCT_INVOKE(rtcd, idct16)(b->dqcoeff, b->diff, pitch); - else + if (b->eob <= 1) IDCT_INVOKE(rtcd, idct1)(b->dqcoeff, b->diff, pitch); + else + IDCT_INVOKE(rtcd, idct16)(b->dqcoeff, b->diff, pitch); } @@ -66,6 +76,7 @@ void vp8_inverse_transform_mb(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x int i; if (x->mode_info_context->mbmi.mode != B_PRED && + x->mode_info_context->mbmi.mode != I8X8_PRED && x->mode_info_context->mbmi.mode != SPLITMV) { /* do 2nd order transform on the dc block */ @@ -86,3 +97,77 @@ void vp8_inverse_transform_mb(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x } } + + +void vp8_inverse_transform_b_8x8(const vp8_idct_rtcd_vtable_t *rtcd, short *input_dqcoeff, short *output_coeff, int pitch)//pay attention to use when 8x8 +{ + // int b,i; + //if (b->eob > 1) + IDCT_INVOKE(rtcd, idct8)(input_dqcoeff, output_coeff, pitch); + //else + //IDCT_INVOKE(rtcd, idct8_1)(b->dqcoeff, b->diff, pitch);//pitch + +} + + +void vp8_inverse_transform_mby_8x8(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + // do 2nd order transform on the dc block + IDCT_INVOKE(rtcd, ihaar2)(x->block[24].dqcoeff, x->block[24].diff, 8); + + recon_dcblock_8x8(x); //need to change for 8x8 + for (i = 0; i < 9; i += 8) + { + vp8_inverse_transform_b_8x8(rtcd, &x->block[i].dqcoeff[0], &x->block[i].diff[0], 32); + } + for (i = 2; i < 11; i += 8) + { + vp8_inverse_transform_b_8x8(rtcd, &x->block[i+2].dqcoeff[0], &x->block[i].diff[0], 32); + } + +} +void vp8_inverse_transform_mbuv_8x8(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + for (i = 16; i < 24; i += 4) + { + vp8_inverse_transform_b_8x8(rtcd, &x->block[i].dqcoeff[0], &x->block[i].diff[0], 16); + } + +} + + +void vp8_inverse_transform_mb_8x8(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + if (x->mode_info_context->mbmi.mode != B_PRED && + x->mode_info_context->mbmi.mode != SPLITMV) + { + // do 2nd order transform on the dc block + + IDCT_INVOKE(rtcd, ihaar2)(&x->block[24].dqcoeff[0], x->block[24].diff, 8);//dqcoeff[0] + recon_dcblock_8x8(x); //need to change for 8x8 + + } + + for (i = 0; i < 9; i += 8) + { + vp8_inverse_transform_b_8x8(rtcd, &x->block[i].dqcoeff[0], &x->block[i].diff[0], 32); + } + for (i = 2; i < 11; i += 8) + { + vp8_inverse_transform_b_8x8(rtcd, &x->block[i+2].dqcoeff[0], &x->block[i].diff[0], 32); + } + + + for (i = 16; i < 24; i += 4) + { + vp8_inverse_transform_b_8x8(rtcd, &x->block[i].dqcoeff[0], &x->block[i].diff[0], 16); + } + +} + diff --git a/vp8/common/invtrans.h b/vp8/common/invtrans.h index d14573b91..4c4f0d3d2 100644 --- a/vp8/common/invtrans.h +++ b/vp8/common/invtrans.h @@ -12,7 +12,7 @@ #ifndef __INC_INVTRANS_H #define __INC_INVTRANS_H -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "idct.h" #include "blockd.h" extern void vp8_inverse_transform_b(const vp8_idct_rtcd_vtable_t *rtcd, BLOCKD *b, int pitch); @@ -20,4 +20,9 @@ extern void vp8_inverse_transform_mb(const vp8_idct_rtcd_vtable_t *rtcd, MACROBL extern void vp8_inverse_transform_mby(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x); extern void vp8_inverse_transform_mbuv(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +extern void vp8_inverse_transform_b_8x8(const vp8_idct_rtcd_vtable_t *rtcd, short *input_dqcoeff, short *output_coeff, int pitch); +extern void vp8_inverse_transform_mb_8x8(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +extern void vp8_inverse_transform_mby_8x8(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +extern void vp8_inverse_transform_mbuv_8x8(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x); + #endif diff --git a/vp8/common/loopfilter.c b/vp8/common/loopfilter.c index fe0644bdd..1cac063e0 100644 --- a/vp8/common/loopfilter.c +++ b/vp8/common/loopfilter.c @@ -14,10 +14,14 @@ #include "onyxc_int.h" #include "vpx_mem/vpx_mem.h" +#include "vp8/common/seg_common.h" + typedef unsigned char uc; prototype_loopfilter(vp8_loop_filter_horizontal_edge_c); prototype_loopfilter(vp8_loop_filter_vertical_edge_c); + + prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_c); prototype_loopfilter(vp8_mbloop_filter_vertical_edge_c); @@ -68,6 +72,14 @@ void vp8_loop_filter_bh_c(unsigned char *y_ptr, unsigned char *u_ptr, vp8_loop_filter_horizontal_edge_c(v_ptr + 4 * uv_stride, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); } +void vp8_loop_filter_bh8x8_c(unsigned char *y_ptr, unsigned char *u_ptr, + unsigned char *v_ptr, int y_stride, int uv_stride, + loop_filter_info *lfi) +{ + vp8_mbloop_filter_horizontal_edge_c( + y_ptr + 8 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); +} + void vp8_loop_filter_bhs_c(unsigned char *y_ptr, int y_stride, const unsigned char *blimit) { @@ -92,6 +104,14 @@ void vp8_loop_filter_bv_c(unsigned char *y_ptr, unsigned char *u_ptr, vp8_loop_filter_vertical_edge_c(v_ptr + 4, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); } +void vp8_loop_filter_bv8x8_c(unsigned char *y_ptr, unsigned char *u_ptr, + unsigned char *v_ptr, int y_stride, int uv_stride, + loop_filter_info *lfi) +{ + vp8_mbloop_filter_vertical_edge_c( + y_ptr + 8, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); +} + void vp8_loop_filter_bvs_c(unsigned char *y_ptr, int y_stride, const unsigned char *blimit) { @@ -133,7 +153,7 @@ static void lf_init_lut(loop_filter_info_n *lfi) lfi->mode_lf_lut[H_PRED] = 1; lfi->mode_lf_lut[TM_PRED] = 1; lfi->mode_lf_lut[B_PRED] = 0; - + lfi->mode_lf_lut[I8X8_PRED]=0; lfi->mode_lf_lut[ZEROMV] = 1; lfi->mode_lf_lut[NEARESTMV] = 2; lfi->mode_lf_lut[NEARMV] = 2; @@ -194,7 +214,7 @@ void vp8_loop_filter_init(VP8_COMMON *cm) } void vp8_loop_filter_frame_init(VP8_COMMON *cm, - MACROBLOCKD *mbd, + MACROBLOCKD *xd, int default_filt_lvl) { int seg, /* segment number */ @@ -215,22 +235,23 @@ void vp8_loop_filter_frame_init(VP8_COMMON *cm, int lvl_seg = default_filt_lvl; int lvl_ref, lvl_mode; - /* Note the baseline filter values for each segment */ - if (mbd->segmentation_enabled) + + // Set the baseline filter values for each segment + if ( segfeature_active( xd, seg, SEG_LVL_ALT_LF ) ) { /* Abs value */ - if (mbd->mb_segement_abs_delta == SEGMENT_ABSDATA) + if (xd->mb_segment_abs_delta == SEGMENT_ABSDATA) { - lvl_seg = mbd->segment_feature_data[MB_LVL_ALT_LF][seg]; + lvl_seg = get_segdata( xd, seg, SEG_LVL_ALT_LF ); } else /* Delta Value */ { - lvl_seg += mbd->segment_feature_data[MB_LVL_ALT_LF][seg]; + lvl_seg += get_segdata( xd, seg, SEG_LVL_ALT_LF );; lvl_seg = (lvl_seg > 0) ? ((lvl_seg > 63) ? 63: lvl_seg) : 0; } } - if (!mbd->mode_ref_lf_delta_enabled) + if (!xd->mode_ref_lf_delta_enabled) { /* we could get rid of this if we assume that deltas are set to * zero when not in use; encoder always uses deltas @@ -245,12 +266,12 @@ void vp8_loop_filter_frame_init(VP8_COMMON *cm, ref = INTRA_FRAME; /* Apply delta for reference frame */ - lvl_ref += mbd->ref_lf_deltas[ref]; + lvl_ref += xd->ref_lf_deltas[ref]; /* Apply delta for Intra modes */ mode = 0; /* B_PRED */ /* Only the split mode BPRED has a further special case */ - lvl_mode = lvl_ref + mbd->mode_lf_deltas[mode]; + lvl_mode = lvl_ref + xd->mode_lf_deltas[mode]; lvl_mode = (lvl_mode > 0) ? (lvl_mode > 63 ? 63 : lvl_mode) : 0; /* clamp */ lfi->lvl[seg][ref][mode] = lvl_mode; @@ -265,12 +286,12 @@ void vp8_loop_filter_frame_init(VP8_COMMON *cm, int lvl_ref = lvl_seg; /* Apply delta for reference frame */ - lvl_ref += mbd->ref_lf_deltas[ref]; + lvl_ref += xd->ref_lf_deltas[ref]; /* Apply delta for Inter modes */ for (mode = 1; mode < 4; mode++) { - lvl_mode = lvl_ref + mbd->mode_lf_deltas[mode]; + lvl_mode = lvl_ref + xd->mode_lf_deltas[mode]; lvl_mode = (lvl_mode > 0) ? (lvl_mode > 63 ? 63 : lvl_mode) : 0; /* clamp */ lfi->lvl[seg][ref][mode] = lvl_mode; @@ -282,7 +303,7 @@ void vp8_loop_filter_frame_init(VP8_COMMON *cm, void vp8_loop_filter_frame ( VP8_COMMON *cm, - MACROBLOCKD *mbd + MACROBLOCKD *xd ) { YV12_BUFFER_CONFIG *post = cm->frame_to_show; @@ -302,7 +323,7 @@ void vp8_loop_filter_frame const MODE_INFO *mode_info_context = cm->mi; /* Initialize the loop filter for this frame. */ - vp8_loop_filter_frame_init(cm, mbd, cm->filter_level); + vp8_loop_filter_frame_init(cm, xd, cm->filter_level); /* Set up the buffer pointers */ y_ptr = post->y_buffer; @@ -315,13 +336,14 @@ void vp8_loop_filter_frame for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) { int skip_lf = (mode_info_context->mbmi.mode != B_PRED && + mode_info_context->mbmi.mode != I8X8_PRED && mode_info_context->mbmi.mode != SPLITMV && mode_info_context->mbmi.mb_skip_coeff); const int mode_index = lfi_n->mode_lf_lut[mode_info_context->mbmi.mode]; const int seg = mode_info_context->mbmi.segment_id; const int ref_frame = mode_info_context->mbmi.ref_frame; - + int tx_type = mode_info_context->mbmi.txfm_size; filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; if (filter_level) @@ -335,21 +357,34 @@ void vp8_loop_filter_frame lfi.hev_thr = lfi_n->hev_thr[hev_index]; if (mb_col > 0) - LF_INVOKE(&cm->rtcd.loopfilter, normal_mb_v) + vp8_loop_filter_mbv_c (y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); if (!skip_lf) - LF_INVOKE(&cm->rtcd.loopfilter, normal_b_v) - (y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); + { + if(tx_type == TX_8X8) + vp8_loop_filter_bv8x8_c + (y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); + else + LF_INVOKE(&cm->rtcd.loopfilter, normal_b_v) + (y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); + + } /* don't apply across umv border */ if (mb_row > 0) - LF_INVOKE(&cm->rtcd.loopfilter, normal_mb_h) + vp8_loop_filter_mbh_c (y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); if (!skip_lf) - LF_INVOKE(&cm->rtcd.loopfilter, normal_b_h) - (y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); + { + if(tx_type == TX_8X8) + vp8_loop_filter_bh8x8_c + (y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); + else + LF_INVOKE(&cm->rtcd.loopfilter, normal_b_h) + (y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); + } } else { @@ -390,7 +425,7 @@ void vp8_loop_filter_frame void vp8_loop_filter_frame_yonly ( VP8_COMMON *cm, - MACROBLOCKD *mbd, + MACROBLOCKD *xd, int default_filt_lvl ) { @@ -415,7 +450,7 @@ void vp8_loop_filter_frame_yonly #endif /* Initialize the loop filter for this frame. */ - vp8_loop_filter_frame_init( cm, mbd, default_filt_lvl); + vp8_loop_filter_frame_init( cm, xd, default_filt_lvl); /* Set up the buffer pointers */ y_ptr = post->y_buffer; @@ -426,12 +461,14 @@ void vp8_loop_filter_frame_yonly for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) { int skip_lf = (mode_info_context->mbmi.mode != B_PRED && + mode_info_context->mbmi.mode != I8X8_PRED && mode_info_context->mbmi.mode != SPLITMV && mode_info_context->mbmi.mb_skip_coeff); const int mode_index = lfi_n->mode_lf_lut[mode_info_context->mbmi.mode]; const int seg = mode_info_context->mbmi.segment_id; const int ref_frame = mode_info_context->mbmi.ref_frame; + int tx_type = mode_info_context->mbmi.txfm_size; filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; @@ -446,21 +483,33 @@ void vp8_loop_filter_frame_yonly lfi.hev_thr = lfi_n->hev_thr[hev_index]; if (mb_col > 0) - LF_INVOKE(&cm->rtcd.loopfilter, normal_mb_v) + vp8_loop_filter_mbv_c (y_ptr, 0, 0, post->y_stride, 0, &lfi); if (!skip_lf) - LF_INVOKE(&cm->rtcd.loopfilter, normal_b_v) - (y_ptr, 0, 0, post->y_stride, 0, &lfi); + { + if(tx_type == TX_8X8) + vp8_loop_filter_bv8x8_c + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + else + LF_INVOKE(&cm->rtcd.loopfilter, normal_b_v) + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + } /* don't apply across umv border */ if (mb_row > 0) - LF_INVOKE(&cm->rtcd.loopfilter, normal_mb_h) + vp8_loop_filter_mbh_c (y_ptr, 0, 0, post->y_stride, 0, &lfi); if (!skip_lf) - LF_INVOKE(&cm->rtcd.loopfilter, normal_b_h) - (y_ptr, 0, 0, post->y_stride, 0, &lfi); + { + if(tx_type == TX_8X8) + vp8_loop_filter_bh8x8_c + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + else + LF_INVOKE(&cm->rtcd.loopfilter, normal_b_h) + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + } } else { @@ -493,11 +542,134 @@ void vp8_loop_filter_frame_yonly } } +#if CONFIG_FEATUREUPDATES +// TODO: Multiple copies of loop filtering code should be pruned and +// cut down. This just adds yet another so that I can do an if +// on segment. +void vp8_loop_filter_frame_segment(VP8_COMMON *cm, MACROBLOCKD *xd, + int default_filt_lvl, int segment) +{ + YV12_BUFFER_CONFIG *post = cm->frame_to_show; + + unsigned char *y_ptr; + int mb_row; + int mb_col; + + loop_filter_info_n *lfi_n = &cm->lf_info; + loop_filter_info lfi; + + int filter_level; + FRAME_TYPE frame_type = cm->frame_type; + + /* Point at base of Mb MODE_INFO list */ + const MODE_INFO *mode_info_context = cm->mi; + +#if 0 + if(default_filt_lvl == 0) /* no filter applied */ + return; +#endif + + /* Initialize the loop filter for this frame. */ + vp8_loop_filter_frame_init(cm, xd, default_filt_lvl); + + /* Set up the buffer pointers */ + y_ptr = post->y_buffer; + + /* vp8_filter each macro block */ + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + int skip_lf = (mode_info_context->mbmi.mode != B_PRED + && mode_info_context->mbmi.mode != I8X8_PRED + && mode_info_context->mbmi.mode != SPLITMV + && mode_info_context->mbmi.mb_skip_coeff); + + const int mode_index = lfi_n->mode_lf_lut[mode_info_context->mbmi + .mode]; + const int seg = mode_info_context->mbmi.segment_id; + const int ref_frame = mode_info_context->mbmi.ref_frame; + + filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; + + // check if this mb has filtering applied + // and then whether it is the right segment or + // if not whether the passed in segment is 0 and this + // segment has no alt lf + + // TODO: Make this work for when segment 0 has the alt lv enabled + if (filter_level + && (seg == segment + || (!segfeature_active(xd, seg, SEG_LVL_ALT_LF) + && segment == 0))) + { + if (cm->filter_type == NORMAL_LOOPFILTER) + { + const int hev_index = + lfi_n->hev_thr_lut[frame_type][filter_level]; + lfi.mblim = lfi_n->mblim[filter_level]; + lfi.blim = lfi_n->blim[filter_level]; + lfi.lim = lfi_n->lim[filter_level]; + lfi.hev_thr = lfi_n->hev_thr[hev_index]; + + if (mb_col > 0) + vp8_loop_filter_mbv_c(y_ptr, 0, 0, post->y_stride, 0, + &lfi); + + if (!skip_lf) + LF_INVOKE(&cm->rtcd.loopfilter, normal_b_v)( + y_ptr, 0, 0, post->y_stride, 0, &lfi); + + /* don't apply across umv border */ + if (mb_row > 0) + vp8_loop_filter_mbh_c(y_ptr, 0, 0, post->y_stride, 0, + &lfi); + + if (!skip_lf) + LF_INVOKE(&cm->rtcd.loopfilter, normal_b_h)( + y_ptr, 0, 0, post->y_stride, 0, &lfi); + } + else + { + if (mb_col > 0) + LF_INVOKE(&cm->rtcd.loopfilter, simple_mb_v)( + y_ptr, post->y_stride, + lfi_n->mblim[filter_level]); + + if (!skip_lf) + LF_INVOKE(&cm->rtcd.loopfilter, simple_b_v)( + y_ptr, post->y_stride, + lfi_n->blim[filter_level]); + + /* don't apply across umv border */ + if (mb_row > 0) + LF_INVOKE(&cm->rtcd.loopfilter, simple_mb_h)( + y_ptr, post->y_stride, + lfi_n->mblim[filter_level]); + + if (!skip_lf) + LF_INVOKE(&cm->rtcd.loopfilter, simple_b_h)( + y_ptr, post->y_stride, + lfi_n->blim[filter_level]); + } + } + + y_ptr += 16; + mode_info_context++; /* step to next MB */ + + } + + y_ptr += post->y_stride * 16 - post->y_width; + mode_info_context++; /* Skip border mb */ + } + +} +#endif void vp8_loop_filter_partial_frame ( VP8_COMMON *cm, - MACROBLOCKD *mbd, + MACROBLOCKD *xd, int default_filt_lvl ) { @@ -514,7 +686,7 @@ void vp8_loop_filter_partial_frame loop_filter_info lfi; int filter_level; - int alt_flt_enabled = mbd->segmentation_enabled; + int alt_flt_enabled = xd->segmentation_enabled; FRAME_TYPE frame_type = cm->frame_type; const MODE_INFO *mode_info_context; @@ -539,15 +711,15 @@ void vp8_loop_filter_partial_frame { for (i = 0; i < MAX_MB_SEGMENTS; i++) { /* Abs value */ - if (mbd->mb_segement_abs_delta == SEGMENT_ABSDATA) + if (xd->mb_segment_abs_delta == SEGMENT_ABSDATA) { - lvl_seg[i] = mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + lvl_seg[i] = get_segdata( xd, i, SEG_LVL_ALT_LF ); } /* Delta Value */ else { - lvl_seg[i] = default_filt_lvl - + mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + lvl_seg[i] = default_filt_lvl + + get_segdata( xd, i, SEG_LVL_ALT_LF ); lvl_seg[i] = (lvl_seg[i] > 0) ? ((lvl_seg[i] > 63) ? 63: lvl_seg[i]) : 0; } @@ -563,6 +735,7 @@ void vp8_loop_filter_partial_frame for (mb_col = 0; mb_col < mb_cols; mb_col++) { int skip_lf = (mode_info_context->mbmi.mode != B_PRED && + mode_info_context->mbmi.mode != I8X8_PRED && mode_info_context->mbmi.mode != SPLITMV && mode_info_context->mbmi.mb_skip_coeff); diff --git a/vp8/common/loopfilter.h b/vp8/common/loopfilter.h index 9887cf55b..0ae2b9a1b 100644 --- a/vp8/common/loopfilter.h +++ b/vp8/common/loopfilter.h @@ -14,6 +14,7 @@ #include "vpx_ports/mem.h" #include "vpx_config.h" +#include "blockd.h" #define MAX_LOOP_FILTER 63 @@ -40,7 +41,7 @@ typedef struct DECLARE_ALIGNED(SIMD_WIDTH, unsigned char, hev_thr[4][SIMD_WIDTH]); unsigned char lvl[4][4][4]; unsigned char hev_thr_lut[2][MAX_LOOP_FILTER + 1]; - unsigned char mode_lf_lut[10]; + unsigned char mode_lf_lut[MB_MODE_COUNT]; } loop_filter_info_n; typedef struct diff --git a/vp8/common/loopfilter_filters.c b/vp8/common/loopfilter_filters.c index 10228ae09..dbfd3c96f 100644 --- a/vp8/common/loopfilter_filters.c +++ b/vp8/common/loopfilter_filters.c @@ -10,6 +10,7 @@ #include +#include "vpx_config.h" #include "loopfilter.h" #include "onyxc_int.h" @@ -148,7 +149,8 @@ void vp8_loop_filter_vertical_edge_c do { mask = vp8_filter_mask(limit[0], blimit[0], - s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]); + s[-4], s[-3], s[-2], s[-1], + s[0], s[1], s[2], s[3]); hev = vp8_hevmask(thresh[0], s[-2], s[-1], s[0], s[1]); @@ -158,62 +160,95 @@ void vp8_loop_filter_vertical_edge_c } while (++i < count * 8); } - -static __inline void vp8_mbfilter(signed char mask, uc hev, - uc *op2, uc *op1, uc *op0, uc *oq0, uc *oq1, uc *oq2) +static __inline signed char vp8_flatmask(uc thresh, + uc p4, uc p3, uc p2, uc p1, uc p0, + uc q0, uc q1, uc q2, uc q3, uc q4) { - signed char s, u; - signed char vp8_filter, Filter1, Filter2; - signed char ps2 = (signed char) * op2 ^ 0x80; - signed char ps1 = (signed char) * op1 ^ 0x80; - signed char ps0 = (signed char) * op0 ^ 0x80; - signed char qs0 = (signed char) * oq0 ^ 0x80; - signed char qs1 = (signed char) * oq1 ^ 0x80; - signed char qs2 = (signed char) * oq2 ^ 0x80; - - /* add outer taps if we have high edge variance */ - vp8_filter = vp8_signed_char_clamp(ps1 - qs1); - vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0)); - vp8_filter &= mask; - - Filter2 = vp8_filter; - Filter2 &= hev; - - /* save bottom 3 bits so that we round one side +4 and the other +3 */ - Filter1 = vp8_signed_char_clamp(Filter2 + 4); - Filter2 = vp8_signed_char_clamp(Filter2 + 3); - Filter1 >>= 3; - Filter2 >>= 3; - qs0 = vp8_signed_char_clamp(qs0 - Filter1); - ps0 = vp8_signed_char_clamp(ps0 + Filter2); - - - /* only apply wider filter if not high edge variance */ - vp8_filter &= ~hev; - Filter2 = vp8_filter; - - /* roughly 3/7th difference across boundary */ - u = vp8_signed_char_clamp((63 + Filter2 * 27) >> 7); - s = vp8_signed_char_clamp(qs0 - u); - *oq0 = s ^ 0x80; - s = vp8_signed_char_clamp(ps0 + u); - *op0 = s ^ 0x80; - - /* roughly 2/7th difference across boundary */ - u = vp8_signed_char_clamp((63 + Filter2 * 18) >> 7); - s = vp8_signed_char_clamp(qs1 - u); - *oq1 = s ^ 0x80; - s = vp8_signed_char_clamp(ps1 + u); - *op1 = s ^ 0x80; - - /* roughly 1/7th difference across boundary */ - u = vp8_signed_char_clamp((63 + Filter2 * 9) >> 7); - s = vp8_signed_char_clamp(qs2 - u); - *oq2 = s ^ 0x80; - s = vp8_signed_char_clamp(ps2 + u); - *op2 = s ^ 0x80; + signed char flat = 0; + flat |= (abs(p1 - p0) > 1) * -1; + flat |= (abs(q1 - q0) > 1) * -1; + flat |= (abs(p0 - p2) > 1) * -1; + flat |= (abs(q0 - q2) > 1) * -1; + flat |= (abs(p3 - p0) > 1) * -1; + flat |= (abs(q3 - q0) > 1) * -1; + flat |= (abs(p4 - p0) > 1) * -1; + flat |= (abs(q4 - q0) > 1) * -1; + flat = ~flat; + return flat; } +static __inline void vp8_mbfilter(signed char mask, uc hev, uc flat, + uc *op4, uc *op3, uc *op2, uc *op1, uc *op0, + uc *oq0, uc *oq1, uc *oq2, uc *oq3, uc *oq4) +{ + /* use a 7 tap filter [1, 1, 1, 2, 1, 1, 1] for flat line */ + if(flat && mask) + { + unsigned char p0, q0; + unsigned char p1, q1; + unsigned char p2, q2; + unsigned char p3, q3; + unsigned char p4, q4; + + p4 = *op4; + p3 = *op3; + p2 = *op2; + p1 = *op1; + p0 = *op0; + q0 = *oq0; + q1 = *oq1; + q2 = *oq2; + q3 = *oq3; + q4 = *oq4; + + *op2 = ( p4 + p4 + p3 + p2 + p2 + p1 + p0 + q0 + 4)>>3; + *op1 = ( p4 + p3 + p2 + p1 + p1 + p0 + q0 + q1 + 4)>>3; + *op0 = ( p3 + p2 + p1 + p0 + p0 + q0 + q1 + q2 + 4)>>3; + *oq0 = ( p2 + p1 + p0 + q0 + q0 + q1 + q2 + q3 + 4)>>3; + *oq1 = ( p1 + p0 + q0 + q1 + q1 + q2 + q3 + q4 + 4)>>3; + *oq2 = ( p0 + q0 + q1 + q2 + q2 + q3 + q4 + q4 + 4)>>3; + } + else + { + signed char ps0, qs0; + signed char ps1, qs1; + signed char vp8_filter, Filter1, Filter2; + signed char u; + + ps1 = (signed char) * op1 ^ 0x80; + ps0 = (signed char) * op0 ^ 0x80; + qs0 = (signed char) * oq0 ^ 0x80; + qs1 = (signed char) * oq1 ^ 0x80; + + /* add outer taps if we have high edge variance */ + vp8_filter = vp8_signed_char_clamp(ps1 - qs1); + vp8_filter &= hev; + + /* inner taps */ + vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0)); + vp8_filter &= mask; + + Filter1 = vp8_signed_char_clamp(vp8_filter + 4); + Filter2 = vp8_signed_char_clamp(vp8_filter + 3); + Filter1 >>= 3; + Filter2 >>= 3; + u = vp8_signed_char_clamp(qs0 - Filter1); + *oq0 = u ^ 0x80; + u = vp8_signed_char_clamp(ps0 + Filter2); + *op0 = u ^ 0x80; + vp8_filter = Filter1; + + /* outer tap adjustments */ + vp8_filter += 1; + vp8_filter >>= 1; + vp8_filter &= ~hev; + + u = vp8_signed_char_clamp(qs1 - vp8_filter); + *oq1 = u ^ 0x80; + u = vp8_signed_char_clamp(ps1 + vp8_filter); + *op1 = u ^ 0x80; + } +} void vp8_mbloop_filter_horizontal_edge_c ( unsigned char *s, @@ -226,6 +261,7 @@ void vp8_mbloop_filter_horizontal_edge_c { signed char hev = 0; /* high edge variance */ signed char mask = 0; + signed char flat = 0; int i = 0; /* loop filter designed to work using chars so that we can make maximum use @@ -236,11 +272,16 @@ void vp8_mbloop_filter_horizontal_edge_c mask = vp8_filter_mask(limit[0], blimit[0], s[-4*p], s[-3*p], s[-2*p], s[-1*p], - s[0*p], s[1*p], s[2*p], s[3*p]); + s[ 0*p], s[ 1*p], s[ 2*p], s[ 3*p]); hev = vp8_hevmask(thresh[0], s[-2*p], s[-1*p], s[0*p], s[1*p]); - vp8_mbfilter(mask, hev, s - 3 * p, s - 2 * p, s - 1 * p, s, s + 1 * p, s + 2 * p); + flat = vp8_flatmask(thresh[0], + s[-5*p], s[-4*p], s[-3*p], s[-2*p], s[-1*p], + s[ 0*p], s[ 1*p], s[ 2*p], s[ 3*p], s[ 4*p]); + vp8_mbfilter(mask, hev, flat, + s - 5*p, s - 4*p, s- 3*p, s - 2*p, s - 1*p, + s, s + 1*p, s+ 2*p, s + 3*p, s + 4*p ); ++s; } @@ -261,18 +302,23 @@ void vp8_mbloop_filter_vertical_edge_c { signed char hev = 0; /* high edge variance */ signed char mask = 0; + signed char flat = 0; int i = 0; do { mask = vp8_filter_mask(limit[0], blimit[0], - s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]); + s[-4], s[-3], s[-2], s[-1], + s[0], s[1], s[2], s[3]); hev = vp8_hevmask(thresh[0], s[-2], s[-1], s[0], s[1]); - - vp8_mbfilter(mask, hev, s - 3, s - 2, s - 1, s, s + 1, s + 2); - + flat = vp8_flatmask(thresh[0], + s[-5],s[-4],s[-3],s[-2],s[-1], + s[ 0],s[ 1],s[ 2],s[ 3],s[ 4]); + vp8_mbfilter(mask, hev, flat, + s - 5, s - 4, s - 3, s - 2, s - 1, + s, s + 1, s + 2, s + 3, s + 4); s += p; } while (++i < count * 8); @@ -280,7 +326,9 @@ void vp8_mbloop_filter_vertical_edge_c } /* should we apply any filter at all ( 11111111 yes, 00000000 no) */ -static __inline signed char vp8_simple_filter_mask(uc blimit, uc p1, uc p0, uc q0, uc q1) +static __inline signed char vp8_simple_filter_mask(uc blimit, + uc p1, uc p0, + uc q0, uc q1) { /* Why does this cause problems for win32? * error C2143: syntax error : missing ';' before 'type' @@ -290,7 +338,9 @@ static __inline signed char vp8_simple_filter_mask(uc blimit, uc p1, uc p0, uc q return mask; } -static __inline void vp8_simple_filter(signed char mask, uc *op1, uc *op0, uc *oq0, uc *oq1) +static __inline void vp8_simple_filter(signed char mask, + uc *op1, uc *op0, + uc *oq0, uc *oq1) { signed char vp8_filter, Filter1, Filter2; signed char p1 = (signed char) * op1 ^ 0x80; @@ -327,8 +377,12 @@ void vp8_loop_filter_simple_horizontal_edge_c do { - mask = vp8_simple_filter_mask(blimit[0], s[-2*p], s[-1*p], s[0*p], s[1*p]); - vp8_simple_filter(mask, s - 2 * p, s - 1 * p, s, s + 1 * p); + mask = vp8_simple_filter_mask(blimit[0], + s[-2*p], s[-1*p], + s[0*p], s[1*p]); + vp8_simple_filter(mask, + s - 2 * p, s - 1 * p, + s, s + 1 * p); ++s; } while (++i < 16); diff --git a/vp8/common/maskingmv.c b/vp8/common/maskingmv.c new file mode 100644 index 000000000..d01a18fc8 --- /dev/null +++ b/vp8/common/maskingmv.c @@ -0,0 +1,855 @@ +/* + ============================================================================ + Name : maskingmv.c + Author : jimbankoski + Version : + Copyright : Your copyright notice + Description : Hello World in C, Ansi-style + ============================================================================ + */ + +#include +#include +#include +extern unsigned int vp8_sad16x16_sse3( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int max_err); + +extern void vp8_sad16x16x3_sse3( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int *results); + +extern int vp8_growmaskmb_sse3( + unsigned char *om, + unsigned char *nm); + +extern void vp8_makemask_sse3( + unsigned char *y, + unsigned char *u, + unsigned char *v, + unsigned char *ym, + int yp, + int uvp, + int ys, + int us, + int vs, + int yt, + int ut, + int vt); + +unsigned int vp8_sad16x16_unmasked_wmt( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + unsigned char *mask); + +unsigned int vp8_sad16x16_masked_wmt( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + unsigned char *mask); + +unsigned int vp8_masked_predictor_wmt( + unsigned char *masked, + unsigned char *unmasked, + int src_stride, + unsigned char *dst_ptr, + int dst_stride, + unsigned char *mask); +unsigned int vp8_masked_predictor_uv_wmt( + unsigned char *masked, + unsigned char *unmasked, + int src_stride, + unsigned char *dst_ptr, + int dst_stride, + unsigned char *mask); +unsigned int vp8_uv_from_y_mask( + unsigned char *ymask, + unsigned char *uvmask); +int yp=16; +unsigned char sxy[]= +{ +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,80,120,120,90,90,90,90,90,80,120,120,90,90,90,90,90 +}; + +unsigned char sts[]= +{ +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +}; +unsigned char str[]= +{ +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +}; + +unsigned char y[]= +{ +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40, +40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,40, +40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,40, +40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,40, +60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,40, +60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,40, +60,60,60,60,40,40,40,40,60,60,60,60,40,40,40,40, +40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,40, +40,60,60,60,60,40,40,40,40,60,60,60,60,40,40,40, +40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,40, +40,40,60,60,60,60,40,40,40,40,60,60,60,60,40,40, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40, +40,40,40,60,60,60,60,40,40,40,40,60,60,60,60,40 +}; +int uvp=8; +unsigned char u[]= +{ +90,80,70,70,90,90,90,17, +90,80,70,70,90,90,90,17, +84,70,70,90,90,90,17,17, +84,70,70,90,90,90,17,17, +80,70,70,90,90,90,17,17, +90,80,70,70,90,90,90,17, +90,80,70,70,90,90,90,17, +90,80,70,70,90,90,90,17 +}; + +unsigned char v[]= +{ +80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80 +}; + +unsigned char ym[256]; +unsigned char uvm[64]; +typedef struct +{ + unsigned char y; + unsigned char yt; + unsigned char u; + unsigned char ut; + unsigned char v; + unsigned char vt; + unsigned char use; +} COLOR_SEG_ELEMENT; + +/* +COLOR_SEG_ELEMENT segmentation[]= +{ + { 60,4,80,17,80,10, 1}, + { 40,4,15,10,80,10, 1}, +}; +*/ + +COLOR_SEG_ELEMENT segmentation[]= +{ + { 79,44,92,44, 237,60, 1}, +}; + +unsigned char pixel_mask(unsigned char y,unsigned char u,unsigned char v, + COLOR_SEG_ELEMENT sgm[], + int c) +{ + COLOR_SEG_ELEMENT *s=sgm; + unsigned char m =0; + int i; + for(i=0;iy)< s->yt && + abs(u-s->u)< s->ut && + abs(v-s->v)< s->vt ? 255 : 0 ); + + return m; +} +int neighbors[256][8]; +int makeneighbors(void) +{ + int i,j; + for(i=0;i<256;i++) + { + int r=(i>>4),c=(i&15); + int ni=0; + for(j=0;j<8;j++) + neighbors[i][j]=i; + for(j=0;j<256;j++) + { + int nr=(j>>4),nc=(j&15); + if(abs(nr-r)<2&&abs(nc-c)<2) + neighbors[i][ni++]=j; + } + } + return 0; +} +void grow_ymask(unsigned char *ym) +{ + unsigned char nym[256]; + int i,j; + + for(i=0;i<256;i++) + { + nym[i]=ym[i]; + for(j=0;j<8;j++) + { + nym[i]|=ym[neighbors[i][j]]; + } + } + for(i=0;i<256;i++) + ym[i]=nym[i]; +} +void make_mb_mask(unsigned char *y, unsigned char *u, unsigned char *v, + unsigned char *ym, unsigned char *uvm, + int yp, int uvp, + COLOR_SEG_ELEMENT sgm[], + int count) +{ + int r,c; + unsigned char *oym = ym; + + memset(ym,20,256); + for(r=0;r<8;r++,uvm+=8,u+=uvp,v+=uvp,y+=(yp+yp),ym+=32) + for(c=0;c<8;c++) + { + int y1=y[c<<1]; + int u1=u[c]; + int v1=v[c]; + int m = pixel_mask(y1,u1,v1,sgm,count); + uvm[c] = m; + ym[c<<1] = uvm[c];// = pixel_mask(y[c<<1],u[c],v[c],sgm,count); + ym[(c<<1)+1] = pixel_mask(y[1+(c<<1)],u[c],v[c],sgm,count); + ym[(c<<1)+16] = pixel_mask(y[yp+(c<<1)],u[c],v[c],sgm,count); + ym[(c<<1)+17] = pixel_mask(y[1+yp+(c<<1)],u[c],v[c],sgm,count); + } + grow_ymask(oym); +} + +int masked_sad(unsigned char *src, int p, unsigned char *dst, int dp, + unsigned char *ym ) +{ + int i,j; + unsigned sad = 0; + for(i=0;i<16;i++,src+=p,dst+=dp,ym+=16) + for(j=0;j<16;j++) + if(ym[j]) + sad+= abs(src[j]-dst[j]); + + return sad; +} + +int compare_masks(unsigned char *sym, unsigned char *ym) +{ + int i,j; + unsigned sad = 0; + for(i=0;i<16;i++,sym += 16,ym+=16) + for(j=0;j<16;j++) + sad+= (sym[j]!=ym[j]?1:0); + + return sad; +} +int unmasked_sad(unsigned char *src, int p, unsigned char *dst, int dp, + unsigned char *ym) +{ + int i,j; + unsigned sad = 0; + for(i=0;i<16;i++,src+=p,dst+=dp,ym+=16) + for(j=0;j<16;j++) + if(!ym[j]) + sad+= abs(src[j]-dst[j]); + + return sad; +} +int masked_motion_search( unsigned char *y, unsigned char *u, unsigned char *v, + int yp, int uvp, + unsigned char *dy, unsigned char *du, unsigned char *dv, + int dyp, int duvp, + COLOR_SEG_ELEMENT sgm[], + int count, + int *mi, + int *mj, + int *ui, + int *uj, + int *wm) +{ + int i,j; + + unsigned char ym[256]; + unsigned char uvm[64]; + unsigned char dym[256]; + unsigned char duvm[64]; + unsigned int e = 0 ; + int beste=256; + int bmi=-32,bmj=-32; + int bui=-32,buj=-32; + int beste1=256; + int bmi1=-32,bmj1=-32; + int bui1=-32,buj1=-32; + int obeste; + + // first try finding best mask and then unmasked + beste = 0xffffffff; + + // find best unmasked mv + for(i=-32;i<32;i++) + { + unsigned char *dyz = i*dyp + dy; + unsigned char *duz = i/2*duvp + du; + unsigned char *dvz = i/2*duvp + dv; + for(j=-32;j<32;j++) + { + // 0,0 masked destination + make_mb_mask(dyz+j,duz+j/2, dvz+j/2, dym, duvm, dyp, duvp,sgm,count); + + e = unmasked_sad(y, yp, dyz+j, dyp, dym ); + + if(edisplay_b_modes_flag & (1<mbmi.mode)) || (ppflags->display_mb_modes_flag & B_PRED)) { - Y = B_PREDICTION_MODE_colors[bmi->as_mode][0]; - U = B_PREDICTION_MODE_colors[bmi->as_mode][1]; - V = B_PREDICTION_MODE_colors[bmi->as_mode][2]; + Y = B_PREDICTION_MODE_colors[bmi->as_mode.first][0]; + U = B_PREDICTION_MODE_colors[bmi->as_mode.first][1]; + V = B_PREDICTION_MODE_colors[bmi->as_mode.first][2]; POSTPROC_INVOKE(RTCD_VTABLE(oci), blend_b) (yl+bx, ul+(bx>>1), vl+(bx>>1), Y, U, V, 0xc000, y_stride); diff --git a/vp8/common/pred_common.c b/vp8/common/pred_common.c new file mode 100644 index 000000000..6bbb619e5 --- /dev/null +++ b/vp8/common/pred_common.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vp8/common/pred_common.h" + +// TBD prediction functions for various bitstream signals + +// Returns a context number for the given MB prediction signal +unsigned char get_pred_context( VP8_COMMON *const cm, + MACROBLOCKD *const xd, + PRED_ID pred_id ) +{ + int pred_context; + MODE_INFO *m = xd->mode_info_context; + + // Note: + // The mode info data structure has a one element border above and to the + // left of the entries correpsonding to real macroblocks. + // The prediction flags in these dummy entries are initialised to 0. + switch (pred_id) + { + case PRED_SEG_ID: + pred_context = (m - 1)->mbmi.seg_id_predicted + + (m - cm->mode_info_stride)->mbmi.seg_id_predicted; + break; + + + case PRED_REF: + pred_context = (m - 1)->mbmi.ref_predicted + + (m - cm->mode_info_stride)->mbmi.ref_predicted; + break; + + case PRED_COMP: + // Context based on use of comp pred flag by neighbours + //pred_context = + // ((m - 1)->mbmi.second_ref_frame != INTRA_FRAME) + + // ((m - cm->mode_info_stride)->mbmi.second_ref_frame != INTRA_FRAME); + + // Context based on mode and reference frame + //if ( m->mbmi.ref_frame == LAST_FRAME ) + // pred_context = 0 + (m->mbmi.mode != ZEROMV); + //else if ( m->mbmi.ref_frame == GOLDEN_FRAME ) + // pred_context = 2 + (m->mbmi.mode != ZEROMV); + //else + // pred_context = 4 + (m->mbmi.mode != ZEROMV); + + if ( m->mbmi.ref_frame == LAST_FRAME ) + pred_context = 0; + else + pred_context = 1; + + break; + + default: + // TODO *** add error trap code. + pred_context = 0; + break; + } + + return pred_context; +} + +// This function returns a context probability for coding a given +// prediction signal +vp8_prob get_pred_prob( VP8_COMMON *const cm, + MACROBLOCKD *const xd, + PRED_ID pred_id ) +{ + vp8_prob pred_probability; + int pred_context; + + // Get the appropriate prediction context + pred_context = get_pred_context( cm, xd, pred_id ); + + switch (pred_id) + { + case PRED_SEG_ID: + pred_probability = cm->segment_pred_probs[pred_context]; + break; + + case PRED_REF: + pred_probability = cm->ref_pred_probs[pred_context]; + break; + + case PRED_COMP: + // In keeping with convention elsewhre the probability returned is + // the probability of a "0" outcome which in this case means the + // probability of comp pred off. + pred_probability = cm->prob_comppred[pred_context]; + break; + + default: + // TODO *** add error trap code. + pred_probability = 128; + break; + } + + return pred_probability; +} + +// This function returns the status of the given prediction signal. +// I.e. is the predicted value for the given signal correct. +unsigned char get_pred_flag( MACROBLOCKD *const xd, + PRED_ID pred_id ) +{ + unsigned char pred_flag = 0; + + switch (pred_id) + { + case PRED_SEG_ID: + pred_flag = xd->mode_info_context->mbmi.seg_id_predicted; + break; + + case PRED_REF: + pred_flag = xd->mode_info_context->mbmi.ref_predicted; + break; + + default: + // TODO *** add error trap code. + pred_flag = 0; + break; +} + + return pred_flag; +} + +// This function sets the status of the given prediction signal. +// I.e. is the predicted value for the given signal correct. +void set_pred_flag( MACROBLOCKD *const xd, + PRED_ID pred_id, + unsigned char pred_flag) +{ + switch (pred_id) + { + case PRED_SEG_ID: + xd->mode_info_context->mbmi.seg_id_predicted = pred_flag; + break; + + case PRED_REF: + xd->mode_info_context->mbmi.ref_predicted = pred_flag; + break; + + default: + // TODO *** add error trap code. + break; + } +} + + +// The following contain the guts of the prediction code used to +// peredict various bitstream signals. + +// Macroblock segment id prediction function +unsigned char get_pred_mb_segid( VP8_COMMON *const cm, int MbIndex ) +{ + // Currently the prediction for the macroblock segment ID is + // the value stored for this macroblock in the previous frame. + return cm->last_frame_seg_map[MbIndex]; +} + +MV_REFERENCE_FRAME get_pred_ref( VP8_COMMON *const cm, + MACROBLOCKD *const xd ) +{ + MODE_INFO *m = xd->mode_info_context; + + MV_REFERENCE_FRAME left; + MV_REFERENCE_FRAME above; + MV_REFERENCE_FRAME above_left; + MV_REFERENCE_FRAME pred_ref = LAST_FRAME; + + int segment_id = xd->mode_info_context->mbmi.segment_id; + int seg_ref_active; + int i; + + unsigned char frame_allowed[MAX_REF_FRAMES] = {1,1,1,1}; + unsigned char ref_score[MAX_REF_FRAMES]; + unsigned char best_score = 0; + unsigned char left_in_image; + unsigned char above_in_image; + unsigned char above_left_in_image; + + // Is segment coding ennabled + seg_ref_active = segfeature_active( xd, segment_id, SEG_LVL_REF_FRAME ); + + // Special case treatment if segment coding is enabled. + // Dont allow prediction of a reference frame that the segment + // does not allow + if ( seg_ref_active ) + { + for ( i = 0; i < MAX_REF_FRAMES; i++ ) + { + frame_allowed[i] = + check_segref( xd, segment_id, i ); + + // Score set to 0 if ref frame not allowed + ref_score[i] = cm->ref_scores[i] * frame_allowed[i]; + } + } + else + vpx_memcpy( ref_score, cm->ref_scores, sizeof(ref_score) ); + + // Reference frames used by neighbours + left = (m - 1)->mbmi.ref_frame; + above = (m - cm->mode_info_stride)->mbmi.ref_frame; + above_left = (m - 1 - cm->mode_info_stride)->mbmi.ref_frame; + + // Are neighbours in image + left_in_image = (m - 1)->mbmi.mb_in_image; + above_in_image = (m - cm->mode_info_stride)->mbmi.mb_in_image; + above_left_in_image = (m - 1 - cm->mode_info_stride)->mbmi.mb_in_image; + + // Adjust scores for candidate reference frames based on neigbours + if ( frame_allowed[left] && left_in_image ) + { + ref_score[left] += 16; + if ( above_left_in_image && (left == above_left) ) + ref_score[left] += 4; + } + if ( frame_allowed[above] && above_in_image ) + { + ref_score[above] += 16; + if ( above_left_in_image && (above == above_left) ) + ref_score[above] += 4; + } + + // Now choose the candidate with the highest score + for ( i = 0; i < MAX_REF_FRAMES; i++ ) + { + if ( ref_score[i] > best_score ) + { + pred_ref = i; + best_score = ref_score[i]; + } + } + + return pred_ref; +} + +// Functions to computes a set of modified reference frame probabilities +// to use when the prediction of the reference frame value fails +void calc_ref_probs( int * count, vp8_prob * probs ) +{ + int tot_count; + + tot_count = count[0] + count[1] + count[2] + count[3]; + if ( tot_count ) + { + probs[0] = (vp8_prob)((count[0] * 255) / tot_count); + probs[0] += !probs[0]; + } + else + probs[0] = 128; + + tot_count -= count[0]; + if ( tot_count ) + { + probs[1] = (vp8_prob)((count[1] * 255) / tot_count); + probs[1] += !probs[1]; + } + else + probs[1] = 128; + + tot_count -= count[1]; + if ( tot_count ) + { + probs[2] = (vp8_prob)((count[2] * 255) / tot_count); + probs[2] += !probs[2]; + } + else + probs[2] = 128; + +} + +// Computes a set of modified conditional probabilities for the reference frame +// Values willbe set to 0 for reference frame options that are not possible +// because wither they were predicted and prediction has failed or because +// they are not allowed for a given segment. +void compute_mod_refprobs( VP8_COMMON *const cm ) +{ + int norm_cnt[MAX_REF_FRAMES]; + int intra_count; + int inter_count; + int last_count; + int gfarf_count; + int gf_count; + int arf_count; + + intra_count = cm->prob_intra_coded; + inter_count = (255 - intra_count); + last_count = (inter_count * cm->prob_last_coded)/255; + gfarf_count = inter_count - last_count; + gf_count = (gfarf_count * cm->prob_gf_coded)/255; + arf_count = gfarf_count - gf_count; + + // Work out modified reference frame probabilities to use where prediction + // of the reference frame fails + norm_cnt[0] = 0; + norm_cnt[1] = last_count; + norm_cnt[2] = gf_count; + norm_cnt[3] = arf_count; + calc_ref_probs( norm_cnt, cm->mod_refprobs[INTRA_FRAME] ); + cm->mod_refprobs[INTRA_FRAME][0] = 0; // This branch implicit + + norm_cnt[0] = intra_count; + norm_cnt[1] = 0; + norm_cnt[2] = gf_count; + norm_cnt[3] = arf_count; + calc_ref_probs( norm_cnt, cm->mod_refprobs[LAST_FRAME]); + cm->mod_refprobs[LAST_FRAME][1] = 0; // This branch implicit + + norm_cnt[0] = intra_count; + norm_cnt[1] = last_count; + norm_cnt[2] = 0; + norm_cnt[3] = arf_count; + calc_ref_probs( norm_cnt, cm->mod_refprobs[GOLDEN_FRAME] ); + cm->mod_refprobs[GOLDEN_FRAME][2] = 0; // This branch implicit + + norm_cnt[0] = intra_count; + norm_cnt[1] = last_count; + norm_cnt[2] = gf_count; + norm_cnt[3] = 0; + calc_ref_probs( norm_cnt, cm->mod_refprobs[ALTREF_FRAME] ); + cm->mod_refprobs[ALTREF_FRAME][2] = 0; // This branch implicit + + // Score the reference frames based on overal frequency. + // These scores contribute to the prediction choices. + // Max score 17 min 1 + cm->ref_scores[INTRA_FRAME] = 1 + (intra_count * 16 / 255); + cm->ref_scores[LAST_FRAME] = 1 + (last_count * 16 / 255); + cm->ref_scores[GOLDEN_FRAME] = 1 + (gf_count * 16 / 255); + cm->ref_scores[ALTREF_FRAME] = 1 + (arf_count * 16 / 255); +} diff --git a/vp8/common/pred_common.h b/vp8/common/pred_common.h new file mode 100644 index 000000000..cd68035b8 --- /dev/null +++ b/vp8/common/pred_common.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "type_aliases.h" +#include "onyxc_int.h" +#include "vp8/common/blockd.h" + +#ifndef __INC_PRED_COMMON_H__ +#define __INC_PRED_COMMON_H__ 1 + + +// Predicted items +typedef enum +{ + PRED_SEG_ID = 0, // Segment identifier + PRED_REF = 1, + PRED_COMP = 2 + +} PRED_ID; + + +extern unsigned char get_pred_context( VP8_COMMON *const cm, + MACROBLOCKD *const xd, + PRED_ID pred_id ); + +extern vp8_prob get_pred_prob( VP8_COMMON *const cm, + MACROBLOCKD *const xd, + PRED_ID pred_id ); + +extern unsigned char get_pred_flag( MACROBLOCKD *const xd, + PRED_ID pred_id ); + +extern void set_pred_flag( MACROBLOCKD *const xd, + PRED_ID pred_id, + unsigned char pred_flag); + + +extern unsigned char get_pred_mb_segid( VP8_COMMON *const cm, int MbIndex ); + +extern MV_REFERENCE_FRAME get_pred_ref( VP8_COMMON *const cm, + MACROBLOCKD *const xd ); +extern void compute_mod_refprobs( VP8_COMMON *const cm ); + +#endif /* __INC_PRED_COMMON_H__ */ diff --git a/vp8/common/predict_rotated.c b/vp8/common/predict_rotated.c new file mode 100644 index 000000000..0880bfb4c --- /dev/null +++ b/vp8/common/predict_rotated.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#if CONFIG_ROTATION +typedef struct +{ + int y; + int x; + unsigned long t; +} tap; + +typedef struct +{ + tap pt[4]; +} point_taps; + +typedef struct +{ + point_taps pt[256]; +} mb_taps; + +mb_taps mt_8x8[] = +{ + #include "rotate2.h" +}; + +mb_taps mt[] = +{ + #include "rotate.h" +}; + +void predict_rotated_16x16(int rotation_index, unsigned char *src, int sp, + unsigned char *dst, int dp) +{ + int i, j, k, p = 0; + + for (i = 0; i < 16; i++, dst += dp) + { + for (j = 0; j < 16; j++, p++) + { + unsigned int sum = 32768; + + for (k = 0; k < 4; k++) + { + tap *tp = &mt[rotation_index].pt[p].pt[k]; + sum += src[tp->y * sp + tp->x] * tp->t; + } + sum >>= 16; + dst[j] = sum; + } + } +} +void predict_rotated_8x8(int rotation_index, unsigned char *src, int sp, + unsigned char *dst, int dp) +{ + int i, j, k, p = 0; + + for (i = 0; i < 8; i++, dst += dp) + { + for (j = 0; j < 8; j++, p++) + { + unsigned int sum = 32768; + + for (k = 0; k < 4; k++) + { + tap *tp = &mt_8x8[rotation_index].pt[p].pt[k]; + sum += src[tp->y * sp + tp->x] * tp->t; + } + sum >>= 16; + dst[j] = sum; + } + } +} +#endif + + + + diff --git a/vp8/common/quant_common.c b/vp8/common/quant_common.c index b8e6e2972..0bb44f588 100644 --- a/vp8/common/quant_common.c +++ b/vp8/common/quant_common.c @@ -11,57 +11,34 @@ #include "quant_common.h" +static int dc_qlookup[QINDEX_RANGE]; +static int ac_qlookup[QINDEX_RANGE]; -#if !CONFIG_EXTEND_QRANGE -static const int dc_qlookup[QINDEX_RANGE] = -{ - 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 17, - 18, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 91, 93, 95, 96, 98, 100, 101, 102, 104, 106, 108, 110, 112, 114, 116, 118, - 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 143, 145, 148, 151, 154, 157, -}; +#define ACDC_MIN 4 -static const int ac_qlookup[QINDEX_RANGE] = +void vp8_init_quant_tables() { - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, - 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, - 110, 112, 114, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, - 155, 158, 161, 164, 167, 170, 173, 177, 181, 185, 189, 193, 197, 201, 205, 209, - 213, 217, 221, 225, 229, 234, 239, 245, 249, 254, 259, 264, 269, 274, 279, 284, -}; -#else + int i; + int current_val = 4; + int last_val = 4; + int ac_val; -static const int dc_qlookup[QINDEX_RANGE] = -{ - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 32, 34, 36, 38, 40, 42, - 44, 46, 49, 52, 55, 58, 61, 64, 67, 70, 73, 76, 79, 82, 85, 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, 205, 210, 215, 220, - 225, 230, 235, 240, 245, 250, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300, - 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, - 472, 484, 496, 508, 520, 532, 544, 556, 572, 588, 608, 628, 648, 668, 692, 720, -}; + for ( i = 0; i < QINDEX_RANGE; i++ ) + { + ac_qlookup[i] = current_val; + current_val = (int)((double)current_val * 1.02); + if ( current_val == last_val ) + current_val++; + last_val = current_val; -static const int ac_qlookup[QINDEX_RANGE] = -{ - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 51, - 54, 57, 60, 63, 66, 69, 72, 76, 80, 84, 88, 92, 96, 100, 105, 110, - 115, 120, 125, 130, 135, 140, 146, 152, 158, 164, 170, 176, 182, 188, 194, 200, - 206, 212, 218, 224, 232, 240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, - 330, 340, 350, 360, 370, 380, 392, 404, 416, 428, 440, 454, 468, 482, 496, 510, - 524, 540, 556, 572, 588, 604, 622, 640, 658, 676, 696, 716, 736, 756, 776, 796, - 820, 844, 868, 892, 916, 944, 972, 1000, 1032, 1064, 1096, 1128, 1168, 1208, 1252, 1300 -}; -#endif + ac_val = ac_qlookup[i]; + dc_qlookup[i] = (0.000000305 * ac_val * ac_val * ac_val) + + (-0.00065 * ac_val * ac_val) + + (0.9 * ac_val) + 0.5; + if ( dc_qlookup[i] < ACDC_MIN ) + dc_qlookup[i] = ACDC_MIN; + } +} int vp8_dc_quant(int QIndex, int Delta) { @@ -69,8 +46,8 @@ int vp8_dc_quant(int QIndex, int Delta) QIndex = QIndex + Delta; - if (QIndex > 127) - QIndex = 127; + if (QIndex > MAXQ) + QIndex = MAXQ; else if (QIndex < 0) QIndex = 0; @@ -84,16 +61,13 @@ int vp8_dc2quant(int QIndex, int Delta) QIndex = QIndex + Delta; - if (QIndex > 127) - QIndex = 127; + if (QIndex > MAXQ) + QIndex = MAXQ; else if (QIndex < 0) QIndex = 0; -#if !CONFIG_EXTEND_QRANGE - retval = dc_qlookup[ QIndex ] * 2; -#else retval = dc_qlookup[ QIndex ]; -#endif + return retval; } @@ -103,8 +77,8 @@ int vp8_dc_uv_quant(int QIndex, int Delta) QIndex = QIndex + Delta; - if (QIndex > 117) - QIndex = 117; + if (QIndex > MAXQ) + QIndex = MAXQ; else if (QIndex < 0) QIndex = 0; @@ -117,8 +91,8 @@ int vp8_ac_yquant(int QIndex) { int retval; - if (QIndex > 127) - QIndex = 127; + if (QIndex > MAXQ) + QIndex = MAXQ; else if (QIndex < 0) QIndex = 0; @@ -132,17 +106,15 @@ int vp8_ac2quant(int QIndex, int Delta) QIndex = QIndex + Delta; - if (QIndex > 127) - QIndex = 127; + if (QIndex > MAXQ) + QIndex = MAXQ; else if (QIndex < 0) QIndex = 0; -#if !CONFIG_EXTEND_QRANGE - retval = (ac_qlookup[ QIndex ] * 155) / 100; - if (retval < 8) - retval = 8; -#else - retval = ac_qlookup[ QIndex ]; -#endif + + retval = (ac_qlookup[ QIndex ] * 775) / 1000; + if (retval < 4) + retval = 4; + return retval; } int vp8_ac_uv_quant(int QIndex, int Delta) @@ -151,8 +123,8 @@ int vp8_ac_uv_quant(int QIndex, int Delta) QIndex = QIndex + Delta; - if (QIndex > 127) - QIndex = 127; + if (QIndex > MAXQ) + QIndex = MAXQ; else if (QIndex < 0) QIndex = 0; diff --git a/vp8/common/quant_common.h b/vp8/common/quant_common.h index cb64d8eb8..0d8099e9b 100644 --- a/vp8/common/quant_common.h +++ b/vp8/common/quant_common.h @@ -13,6 +13,7 @@ #include "blockd.h" #include "onyxc_int.h" +extern void vp8_init_quant_tables(); extern int vp8_ac_yquant(int QIndex); extern int vp8_dc_quant(int QIndex, int Delta); extern int vp8_dc2quant(int QIndex, int Delta); diff --git a/vp8/common/recon.c b/vp8/common/recon.c index eebf6dcb9..279fbe82f 100644 --- a/vp8/common/recon.c +++ b/vp8/common/recon.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "recon.h" #include "blockd.h" @@ -44,6 +44,36 @@ void vp8_recon_b_c } } +void vp8_recon_uv_b_c +( + unsigned char *pred_ptr, + short *diff_ptr, + unsigned char *dst_ptr, + int stride +) +{ + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = diff_ptr[c] + pred_ptr[c] ; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dst_ptr[c] = (unsigned char) a ; + } + + dst_ptr += stride; + diff_ptr += 8; + pred_ptr += 8; + } +} void vp8_recon4b_c ( unsigned char *pred_ptr, diff --git a/vp8/common/recon.h b/vp8/common/recon.h index 7cfc779cd..9fb12c85d 100644 --- a/vp8/common/recon.h +++ b/vp8/common/recon.h @@ -29,6 +29,11 @@ #define prototype_intra4x4_predict(sym) \ void sym(BLOCKD *x, int b_mode, unsigned char *predictor) +#if CONFIG_COMP_INTRA_PRED +#define prototype_comp_intra4x4_predict(sym) \ + void sym(BLOCKD *x, int b_mode, int mode2, unsigned char *predictor) +#endif + struct vp8_recon_rtcd_vtable; #if ARCH_X86 || ARCH_X86_64 @@ -49,6 +54,16 @@ extern prototype_copy_block(vp8_recon_copy16x16); #endif extern prototype_copy_block(vp8_recon_copy8x8); +#ifndef vp8_recon_avg16x16 +#define vp8_recon_avg16x16 vp8_avg_mem16x16_c +#endif +extern prototype_copy_block(vp8_recon_avg16x16); + +#ifndef vp8_recon_avg8x8 +#define vp8_recon_avg8x8 vp8_avg_mem8x8_c +#endif +extern prototype_copy_block(vp8_recon_avg8x8); + #ifndef vp8_recon_copy8x4 #define vp8_recon_copy8x4 vp8_copy_mem8x4_c #endif @@ -59,6 +74,12 @@ extern prototype_copy_block(vp8_recon_copy8x4); #endif extern prototype_recon_block(vp8_recon_recon); +#ifndef vp8_recon_recon_uv +#define vp8_recon_recon_uv vp8_recon_uv_b_c +#endif +extern prototype_recon_block(vp8_recon_recon_uv); + +extern prototype_recon_block(vp8_recon_recon); #ifndef vp8_recon_recon2 #define vp8_recon_recon2 vp8_recon2b_c #endif @@ -85,6 +106,20 @@ extern prototype_recon_macroblock(vp8_recon_recon_mby); extern prototype_build_intra_predictors\ (vp8_recon_build_intra_predictors_mby); +#if CONFIG_COMP_INTRA_PRED +#ifndef vp8_recon_build_comp_intra_predictors_mby +#define vp8_recon_build_comp_intra_predictors_mby vp8_build_comp_intra_predictors_mby +#endif +extern prototype_build_intra_predictors\ + (vp8_recon_build_comp_intra_predictors_mby); +#endif + +#ifndef vp8_recon_build_intra8x8_predictors_mby +#define vp8_recon_build_intra8x8_predictors_mby vp8_build_intra8x8_predictors_mby +#endif +extern prototype_build_intra_predictors\ + (vp8_recon_build_intra8x8_predictors_mby); + #ifndef vp8_recon_build_intra_predictors_mby_s #define vp8_recon_build_intra_predictors_mby_s vp8_build_intra_predictors_mby_s #endif @@ -97,39 +132,111 @@ extern prototype_build_intra_predictors\ extern prototype_build_intra_predictors\ (vp8_recon_build_intra_predictors_mbuv); +#ifndef vp8_recon_build_intra8x8_predictors_mbuv +#define vp8_recon_build_intra8x8_predictors_mbuv vp8_build_intra8x8_predictors_mbuv +#endif +extern prototype_build_intra_predictors\ + (vp8_recon_build_intra8x8_predictors_mbuv); + #ifndef vp8_recon_build_intra_predictors_mbuv_s #define vp8_recon_build_intra_predictors_mbuv_s vp8_build_intra_predictors_mbuv_s #endif extern prototype_build_intra_predictors\ (vp8_recon_build_intra_predictors_mbuv_s); +#if CONFIG_COMP_INTRA_PRED +#ifndef vp8_recon_build_comp_intra_predictors_mbuv +#define vp8_recon_build_comp_intra_predictors_mbuv vp8_build_comp_intra_predictors_mbuv +#endif +extern prototype_build_intra_predictors\ + (vp8_recon_build_comp_intra_predictors_mbuv); +#endif + #ifndef vp8_recon_intra4x4_predict #define vp8_recon_intra4x4_predict vp8_intra4x4_predict #endif extern prototype_intra4x4_predict\ (vp8_recon_intra4x4_predict); +#if CONFIG_COMP_INTRA_PRED +#ifndef vp8_recon_comp_intra4x4_predict +#define vp8_recon_comp_intra4x4_predict vp8_comp_intra4x4_predict +#endif +extern prototype_comp_intra4x4_predict\ + (vp8_recon_comp_intra4x4_predict); +#endif + +#ifndef vp8_recon_intra8x8_predict +#define vp8_recon_intra8x8_predict vp8_intra8x8_predict +#endif +extern prototype_intra4x4_predict\ + (vp8_recon_intra8x8_predict); + +#if CONFIG_COMP_INTRA_PRED +#ifndef vp8_recon_comp_intra8x8_predict +#define vp8_recon_comp_intra8x8_predict vp8_comp_intra8x8_predict +#endif +extern prototype_comp_intra4x4_predict\ + (vp8_recon_comp_intra8x8_predict); +#endif + +#ifndef vp8_recon_intra_uv4x4_predict +#define vp8_recon_intra_uv4x4_predict vp8_intra_uv4x4_predict +#endif +extern prototype_intra4x4_predict\ + (vp8_recon_intra_uv4x4_predict); + +#if CONFIG_COMP_INTRA_PRED +#ifndef vp8_recon_comp_intra_uv4x4_predict +#define vp8_recon_comp_intra_uv4x4_predict vp8_comp_intra_uv4x4_predict +#endif +extern prototype_comp_intra4x4_predict\ + (vp8_recon_comp_intra_uv4x4_predict); +#endif typedef prototype_copy_block((*vp8_copy_block_fn_t)); typedef prototype_recon_block((*vp8_recon_fn_t)); typedef prototype_recon_macroblock((*vp8_recon_mb_fn_t)); typedef prototype_build_intra_predictors((*vp8_build_intra_pred_fn_t)); typedef prototype_intra4x4_predict((*vp8_intra4x4_pred_fn_t)); +#if CONFIG_COMP_INTRA_PRED +typedef prototype_comp_intra4x4_predict((*vp8_comp_intra4x4_pred_fn_t)); +#endif typedef struct vp8_recon_rtcd_vtable { vp8_copy_block_fn_t copy16x16; vp8_copy_block_fn_t copy8x8; + vp8_copy_block_fn_t avg16x16; + vp8_copy_block_fn_t avg8x8; vp8_copy_block_fn_t copy8x4; vp8_recon_fn_t recon; + vp8_recon_fn_t recon_uv; vp8_recon_fn_t recon2; vp8_recon_fn_t recon4; vp8_recon_mb_fn_t recon_mb; vp8_recon_mb_fn_t recon_mby; vp8_build_intra_pred_fn_t build_intra_predictors_mby_s; vp8_build_intra_pred_fn_t build_intra_predictors_mby; +#if CONFIG_COMP_INTRA_PRED + vp8_build_intra_pred_fn_t build_comp_intra_predictors_mby; +#endif vp8_build_intra_pred_fn_t build_intra_predictors_mbuv_s; vp8_build_intra_pred_fn_t build_intra_predictors_mbuv; +#if CONFIG_COMP_INTRA_PRED + vp8_build_intra_pred_fn_t build_comp_intra_predictors_mbuv; +#endif vp8_intra4x4_pred_fn_t intra4x4_predict; +#if CONFIG_COMP_INTRA_PRED + vp8_comp_intra4x4_pred_fn_t comp_intra4x4_predict; +#endif + vp8_intra4x4_pred_fn_t intra8x8_predict; +#if CONFIG_COMP_INTRA_PRED + vp8_comp_intra4x4_pred_fn_t comp_intra8x8_predict; +#endif + vp8_intra4x4_pred_fn_t intra_uv4x4_predict; +#if CONFIG_COMP_INTRA_PRED + vp8_comp_intra4x4_pred_fn_t comp_intra_uv4x4_predict; +#endif } vp8_recon_rtcd_vtable_t; #if CONFIG_RUNTIME_CPU_DETECT diff --git a/vp8/common/reconinter.c b/vp8/common/reconinter.c index e4e8a80a4..bd08e7f2c 100644 --- a/vp8/common/reconinter.c +++ b/vp8/common/reconinter.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx/vpx_integer.h" #include "recon.h" #include "subpixel.h" @@ -62,6 +62,28 @@ void vp8_copy_mem16x16_c( } +void vp8_avg_mem16x16_c( + unsigned char *src, + int src_stride, + unsigned char *dst, + int dst_stride) +{ + int r; + + for (r = 0; r < 16; r++) + { + int n; + + for (n = 0; n < 16; n++) + { + dst[n] = (dst[n] + src[n] + 1) >> 1; + } + + src += src_stride; + dst += dst_stride; + } +} + void vp8_copy_mem8x8_c( unsigned char *src, int src_stride, @@ -92,6 +114,28 @@ void vp8_copy_mem8x8_c( } +void vp8_avg_mem8x8_c( + unsigned char *src, + int src_stride, + unsigned char *dst, + int dst_stride) +{ + int r; + + for (r = 0; r < 8; r++) + { + int n; + + for (n = 0; n < 8; n++) + { + dst[n] = (dst[n] + src[n] + 1) >> 1; + } + + src += src_stride; + dst += dst_stride; + } +} + void vp8_copy_mem8x4_c( unsigned char *src, int src_stride, @@ -136,7 +180,11 @@ void vp8_build_inter_predictors_b(BLOCKD *d, int pitch, vp8_subpix_fn_t sppf) if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) { ptr = ptr_base + d->pre + (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); +#if CONFIG_SIXTEENTH_SUBPEL_UV + sppf(ptr, d->pre_stride, (d->bmi.mv.as_mv.col & 7)<<1, (d->bmi.mv.as_mv.row & 7)<<1, pred_ptr, pitch); +#else sppf(ptr, d->pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, pred_ptr, pitch); +#endif } else { @@ -170,7 +218,11 @@ static void build_inter_predictors4b(MACROBLOCKD *x, BLOCKD *d, int pitch) if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + x->subpixel_predict8x8(ptr, d->pre_stride, (d->bmi.mv.as_mv.col & 7)<<1, (d->bmi.mv.as_mv.row & 7)<<1, pred_ptr, pitch); +#else x->subpixel_predict8x8(ptr, d->pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, pred_ptr, pitch); +#endif } else { @@ -189,7 +241,11 @@ static void build_inter_predictors2b(MACROBLOCKD *x, BLOCKD *d, int pitch) if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + x->subpixel_predict8x4(ptr, d->pre_stride, (d->bmi.mv.as_mv.col & 7)<<1, (d->bmi.mv.as_mv.row & 7)<<1, pred_ptr, pitch); +#else x->subpixel_predict8x4(ptr, d->pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, pred_ptr, pitch); +#endif } else { @@ -205,8 +261,10 @@ void vp8_build_inter16x16_predictors_mbuv(MACROBLOCKD *x) unsigned char *upred_ptr = &x->predictor[256]; unsigned char *vpred_ptr = &x->predictor[320]; - int mv_row = x->mode_info_context->mbmi.mv.as_mv.row; - int mv_col = x->mode_info_context->mbmi.mv.as_mv.col; + int omv_row = x->mode_info_context->mbmi.mv.as_mv.row; + int omv_col = x->mode_info_context->mbmi.mv.as_mv.col; + int mv_row = omv_row; + int mv_col = omv_col; int offset; int pre_stride = x->block[16].pre_stride; @@ -231,11 +289,19 @@ void vp8_build_inter16x16_predictors_mbuv(MACROBLOCKD *x) uptr = x->pre.u_buffer + offset; vptr = x->pre.v_buffer + offset; +#if CONFIG_SIXTEENTH_SUBPEL_UV + if ((omv_row | omv_col) & 15) + { + x->subpixel_predict8x8(uptr, pre_stride, omv_col & 15, omv_row & 15, upred_ptr, 8); + x->subpixel_predict8x8(vptr, pre_stride, omv_col & 15, omv_row & 15, vpred_ptr, 8); + } +#else /* CONFIG_SIXTEENTH_SUBPEL_UV */ if ((mv_row | mv_col) & 7) { x->subpixel_predict8x8(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, 8); x->subpixel_predict8x8(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, 8); } +#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */ else { RECON_INVOKE(&x->rtcd->recon, copy8x8)(uptr, pre_stride, upred_ptr, 8); @@ -317,7 +383,11 @@ void vp8_build_inter16x16_predictors_mby(MACROBLOCKD *x) if ((mv_row | mv_col) & 7) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + x->subpixel_predict16x16(ptr, pre_stride, (mv_col & 7)<<1, (mv_row & 7)<<1, pred_ptr, 16); +#else x->subpixel_predict16x16(ptr, pre_stride, mv_col & 7, mv_row & 7, pred_ptr, 16); +#endif } else { @@ -336,31 +406,33 @@ static void clamp_mv_to_umv_border(MV *mv, const MACROBLOCKD *xd) * filtering. The bottom and right edges use 16 pixels plus 2 pixels * left of the central pixel when filtering. */ - if (mv->col < (xd->mb_to_left_edge - (19 << 3))) + if (mv->col < (xd->mb_to_left_edge - ((16+INTERP_EXTEND) << 3))) mv->col = xd->mb_to_left_edge - (16 << 3); - else if (mv->col > xd->mb_to_right_edge + (18 << 3)) + else if (mv->col > xd->mb_to_right_edge + ((15+INTERP_EXTEND) << 3)) mv->col = xd->mb_to_right_edge + (16 << 3); - if (mv->row < (xd->mb_to_top_edge - (19 << 3))) + if (mv->row < (xd->mb_to_top_edge - ((16+INTERP_EXTEND) << 3))) mv->row = xd->mb_to_top_edge - (16 << 3); - else if (mv->row > xd->mb_to_bottom_edge + (18 << 3)) + else if (mv->row > xd->mb_to_bottom_edge + ((15+INTERP_EXTEND) << 3)) mv->row = xd->mb_to_bottom_edge + (16 << 3); } /* A version of the above function for chroma block MVs.*/ static void clamp_uvmv_to_umv_border(MV *mv, const MACROBLOCKD *xd) { - mv->col = (2*mv->col < (xd->mb_to_left_edge - (19 << 3))) ? + mv->col = (2*mv->col < (xd->mb_to_left_edge - ((16+INTERP_EXTEND) << 3))) ? (xd->mb_to_left_edge - (16 << 3)) >> 1 : mv->col; - mv->col = (2*mv->col > xd->mb_to_right_edge + (18 << 3)) ? + mv->col = (2*mv->col > xd->mb_to_right_edge + ((15+INTERP_EXTEND) << 3)) ? (xd->mb_to_right_edge + (16 << 3)) >> 1 : mv->col; - mv->row = (2*mv->row < (xd->mb_to_top_edge - (19 << 3))) ? + mv->row = (2*mv->row < (xd->mb_to_top_edge - ((16+INTERP_EXTEND) << 3))) ? (xd->mb_to_top_edge - (16 << 3)) >> 1 : mv->row; - mv->row = (2*mv->row > xd->mb_to_bottom_edge + (18 << 3)) ? + mv->row = (2*mv->row > xd->mb_to_bottom_edge + ((15+INTERP_EXTEND) << 3)) ? (xd->mb_to_bottom_edge + (16 << 3)) >> 1 : mv->row; } + + void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x, unsigned char *dst_y, unsigned char *dst_u, @@ -372,6 +444,7 @@ void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x, unsigned char *ptr; unsigned char *uptr, *vptr; + int_mv _o16x16mv; int_mv _16x16mv; unsigned char *ptr_base = x->pre.y_buffer; @@ -388,13 +461,18 @@ void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x, if ( _16x16mv.as_int & 0x00070007) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + x->subpixel_predict16x16(ptr, pre_stride, (_16x16mv.as_mv.col & 7)<<1, (_16x16mv.as_mv.row & 7)<<1, dst_y, dst_ystride); +#else x->subpixel_predict16x16(ptr, pre_stride, _16x16mv.as_mv.col & 7, _16x16mv.as_mv.row & 7, dst_y, dst_ystride); +#endif } else { RECON_INVOKE(&x->rtcd->recon, copy16x16)(ptr, pre_stride, dst_y, dst_ystride); } + _o16x16mv = _16x16mv; /* calc uv motion vectors */ if ( _16x16mv.as_mv.row < 0) _16x16mv.as_mv.row -= 1; @@ -417,16 +495,106 @@ void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x, uptr = x->pre.u_buffer + offset; vptr = x->pre.v_buffer + offset; +#if CONFIG_SIXTEENTH_SUBPEL_UV + if ( _o16x16mv.as_int & 0x000f000f) + { + x->subpixel_predict8x8(uptr, pre_stride, _o16x16mv.as_mv.col & 15, _o16x16mv.as_mv.row & 15, dst_u, dst_uvstride); + x->subpixel_predict8x8(vptr, pre_stride, _o16x16mv.as_mv.col & 15, _o16x16mv.as_mv.row & 15, dst_v, dst_uvstride); + } +#else /* CONFIG_SIXTEENTH_SUBPEL_UV */ if ( _16x16mv.as_int & 0x00070007) { x->subpixel_predict8x8(uptr, pre_stride, _16x16mv.as_mv.col & 7, _16x16mv.as_mv.row & 7, dst_u, dst_uvstride); x->subpixel_predict8x8(vptr, pre_stride, _16x16mv.as_mv.col & 7, _16x16mv.as_mv.row & 7, dst_v, dst_uvstride); } +#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */ else { RECON_INVOKE(&x->rtcd->recon, copy8x8)(uptr, pre_stride, dst_u, dst_uvstride); RECON_INVOKE(&x->rtcd->recon, copy8x8)(vptr, pre_stride, dst_v, dst_uvstride); } + +} + +/* + * This function should be called after an initial call to + * vp8_build_inter16x16_predictors_mb() or _mby()/_mbuv(). + * It will run a second sixtap filter on a (different) ref + * frame and average the result with the output of the + * first sixtap filter. The second reference frame is stored + * in x->second_pre (the reference frame index is in + * x->mode_info_context->mbmi.second_ref_frame). The second + * motion vector is x->mode_info_context->mbmi.second_mv. + * + * This allows blending prediction from two reference frames + * which sometimes leads to better prediction than from a + * single reference framer. + */ +void vp8_build_2nd_inter16x16_predictors_mb(MACROBLOCKD *x, + unsigned char *dst_y, + unsigned char *dst_u, + unsigned char *dst_v, + int dst_ystride, + int dst_uvstride) +{ + int offset; + unsigned char *ptr; + unsigned char *uptr, *vptr; + + int mv_row = x->mode_info_context->mbmi.second_mv.as_mv.row; + int mv_col = x->mode_info_context->mbmi.second_mv.as_mv.col; + int omv_row, omv_col; + + unsigned char *ptr_base = x->second_pre.y_buffer; + int pre_stride = x->block[0].pre_stride; + + ptr = ptr_base + (mv_row >> 3) * pre_stride + (mv_col >> 3); + + if ((mv_row | mv_col) & 7) + { +#if CONFIG_SIXTEENTH_SUBPEL_UV + x->subpixel_predict_avg16x16(ptr, pre_stride, (mv_col & 7)<<1, (mv_row & 7)<<1, dst_y, dst_ystride); +#else + x->subpixel_predict_avg16x16(ptr, pre_stride, mv_col & 7, mv_row & 7, dst_y, dst_ystride); +#endif + } + else + { + RECON_INVOKE(&x->rtcd->recon, avg16x16)(ptr, pre_stride, dst_y, dst_ystride); + } + + /* calc uv motion vectors */ + omv_row = mv_row; + omv_col = mv_col; + mv_row = (mv_row + (mv_row > 0)) >> 1; + mv_col = (mv_col + (mv_col > 0)) >> 1; + + mv_row &= x->fullpixel_mask; + mv_col &= x->fullpixel_mask; + + pre_stride >>= 1; + offset = (mv_row >> 3) * pre_stride + (mv_col >> 3); + uptr = x->second_pre.u_buffer + offset; + vptr = x->second_pre.v_buffer + offset; + +#if CONFIG_SIXTEENTH_SUBPEL_UV + if ((omv_row | omv_col) & 15) + { + x->subpixel_predict_avg8x8(uptr, pre_stride, omv_col & 15, omv_row & 15, dst_u, dst_uvstride); + x->subpixel_predict_avg8x8(vptr, pre_stride, omv_col & 15, omv_row & 15, dst_v, dst_uvstride); + } +#else /* CONFIG_SIXTEENTH_SUBPEL_UV */ + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict_avg8x8(uptr, pre_stride, mv_col & 7, mv_row & 7, dst_u, dst_uvstride); + x->subpixel_predict_avg8x8(vptr, pre_stride, mv_col & 7, mv_row & 7, dst_v, dst_uvstride); + } +#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */ + else + { + RECON_INVOKE(&x->rtcd->recon, avg8x8)(uptr, pre_stride, dst_u, dst_uvstride); + RECON_INVOKE(&x->rtcd->recon, avg8x8)(vptr, pre_stride, dst_v, dst_uvstride); + } } static void build_inter4x4_predictors_mb(MACROBLOCKD *x) @@ -439,6 +607,7 @@ static void build_inter4x4_predictors_mb(MACROBLOCKD *x) x->block[ 2].bmi = x->mode_info_context->bmi[ 2]; x->block[ 8].bmi = x->mode_info_context->bmi[ 8]; x->block[10].bmi = x->mode_info_context->bmi[10]; + if (x->mode_info_context->mbmi.need_to_clamp_mvs) { clamp_mv_to_umv_border(&x->block[ 0].bmi.mv.as_mv, x); @@ -447,6 +616,7 @@ static void build_inter4x4_predictors_mb(MACROBLOCKD *x) clamp_mv_to_umv_border(&x->block[10].bmi.mv.as_mv, x); } + build_inter_predictors4b(x, &x->block[ 0], 16); build_inter_predictors4b(x, &x->block[ 2], 16); build_inter_predictors4b(x, &x->block[ 8], 16); @@ -461,6 +631,7 @@ static void build_inter4x4_predictors_mb(MACROBLOCKD *x) x->block[i+0].bmi = x->mode_info_context->bmi[i+0]; x->block[i+1].bmi = x->mode_info_context->bmi[i+1]; + if (x->mode_info_context->mbmi.need_to_clamp_mvs) { clamp_mv_to_umv_border(&x->block[i+0].bmi.mv.as_mv, x); @@ -484,8 +655,6 @@ static void build_inter4x4_predictors_mb(MACROBLOCKD *x) BLOCKD *d0 = &x->block[i]; BLOCKD *d1 = &x->block[i+1]; - /* Note: uv mvs already clamped in build_4x4uvmvs() */ - if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) build_inter_predictors2b(x, d0, 8); else @@ -531,6 +700,9 @@ void build_4x4uvmvs(MACROBLOCKD *x) x->block[uoffset].bmi.mv.as_mv.col = (temp / 8) & x->fullpixel_mask; + if (x->mode_info_context->mbmi.need_to_clamp_mvs) + clamp_uvmv_to_umv_border(&x->block[uoffset].bmi.mv.as_mv, x); + if (x->mode_info_context->mbmi.need_to_clamp_mvs) clamp_uvmv_to_umv_border(&x->block[uoffset].bmi.mv.as_mv, x); @@ -548,6 +720,16 @@ void vp8_build_inter_predictors_mb(MACROBLOCKD *x) { vp8_build_inter16x16_predictors_mb(x, x->predictor, &x->predictor[256], &x->predictor[320], 16, 8); + + if (x->mode_info_context->mbmi.second_ref_frame) + { + /* 256 = offset of U plane in Y+U+V buffer; + * 320 = offset of V plane in Y+U+V buffer. + * (256=16x16, 320=16x16+8x8). */ + vp8_build_2nd_inter16x16_predictors_mb(x, x->predictor, + &x->predictor[256], + &x->predictor[320], 16, 8); + } } else { @@ -555,4 +737,3 @@ void vp8_build_inter_predictors_mb(MACROBLOCKD *x) build_inter4x4_predictors_mb(x); } } - diff --git a/vp8/common/reconinter.h b/vp8/common/reconinter.h index 456812ecd..c8e2f803b 100644 --- a/vp8/common/reconinter.h +++ b/vp8/common/reconinter.h @@ -19,6 +19,12 @@ extern void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x, unsigned char *dst_v, int dst_ystride, int dst_uvstride); +extern void vp8_build_2nd_inter16x16_predictors_mb(MACROBLOCKD *x, + unsigned char *dst_y, + unsigned char *dst_u, + unsigned char *dst_v, + int dst_ystride, + int dst_uvstride); extern void vp8_build_inter16x16_predictors_mby(MACROBLOCKD *x); diff --git a/vp8/common/reconintra.c b/vp8/common/reconintra.c index 16dadc47d..501eacab2 100644 --- a/vp8/common/reconintra.c +++ b/vp8/common/reconintra.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "recon.h" #include "reconintra.h" #include "vpx_mem/vpx_mem.h" @@ -28,13 +28,12 @@ void vp8_recon_intra_mbuv(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) } } -void vp8_build_intra_predictors_mby(MACROBLOCKD *x) +void vp8_build_intra_predictors_mby_internal(MACROBLOCKD *x, unsigned char *ypred_ptr, int y_stride, int mode) { unsigned char *yabove_row = x->dst.y_buffer - x->dst.y_stride; unsigned char yleft_col[16]; unsigned char ytop_left = yabove_row[-1]; - unsigned char *ypred_ptr = x->predictor; int r, c, i; for (i = 0; i < 16; i++) @@ -43,7 +42,7 @@ void vp8_build_intra_predictors_mby(MACROBLOCKD *x) } /* for Y */ - switch (x->mode_info_context->mbmi.mode) + switch (mode) { case DC_PRED: { @@ -70,11 +69,7 @@ void vp8_build_intra_predictors_mby(MACROBLOCKD *x) { average += yleft_col[i]; } - } - - - shift = 3 + x->up_available + x->left_available; expected_dc = (average + (1 << (shift - 1))) >> shift; } @@ -83,128 +78,6 @@ void vp8_build_intra_predictors_mby(MACROBLOCKD *x) expected_dc = 128; } - vpx_memset(ypred_ptr, expected_dc, 256); - } - break; - case V_PRED: - { - - for (r = 0; r < 16; r++) - { - - ((int *)ypred_ptr)[0] = ((int *)yabove_row)[0]; - ((int *)ypred_ptr)[1] = ((int *)yabove_row)[1]; - ((int *)ypred_ptr)[2] = ((int *)yabove_row)[2]; - ((int *)ypred_ptr)[3] = ((int *)yabove_row)[3]; - ypred_ptr += 16; - } - } - break; - case H_PRED: - { - - for (r = 0; r < 16; r++) - { - - vpx_memset(ypred_ptr, yleft_col[r], 16); - ypred_ptr += 16; - } - - } - break; - case TM_PRED: - { - - for (r = 0; r < 16; r++) - { - for (c = 0; c < 16; c++) - { - int pred = yleft_col[r] + yabove_row[ c] - ytop_left; - - if (pred < 0) - pred = 0; - - if (pred > 255) - pred = 255; - - ypred_ptr[c] = pred; - } - - ypred_ptr += 16; - } - - } - break; - case B_PRED: - case NEARESTMV: - case NEARMV: - case ZEROMV: - case NEWMV: - case SPLITMV: - case MB_MODE_COUNT: - break; - } -} - -void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x) -{ - - unsigned char *yabove_row = x->dst.y_buffer - x->dst.y_stride; - unsigned char yleft_col[16]; - unsigned char ytop_left = yabove_row[-1]; - unsigned char *ypred_ptr = x->predictor; - int r, c, i; - - int y_stride = x->dst.y_stride; - ypred_ptr = x->dst.y_buffer; /*x->predictor;*/ - - for (i = 0; i < 16; i++) - { - yleft_col[i] = x->dst.y_buffer [i* x->dst.y_stride -1]; - } - - /* for Y */ - switch (x->mode_info_context->mbmi.mode) - { - case DC_PRED: - { - int expected_dc; - int i; - int shift; - int average = 0; - - - if (x->up_available || x->left_available) - { - if (x->up_available) - { - for (i = 0; i < 16; i++) - { - average += yabove_row[i]; - } - } - - if (x->left_available) - { - - for (i = 0; i < 16; i++) - { - average += yleft_col[i]; - } - - } - - - - shift = 3 + x->up_available + x->left_available; - expected_dc = (average + (1 << (shift - 1))) >> shift; - } - else - { - expected_dc = 128; - } - - /*vpx_memset(ypred_ptr, expected_dc, 256);*/ for (r = 0; r < 16; r++) { vpx_memset(ypred_ptr, expected_dc, 16); @@ -222,7 +95,7 @@ void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x) ((int *)ypred_ptr)[1] = ((int *)yabove_row)[1]; ((int *)ypred_ptr)[2] = ((int *)yabove_row)[2]; ((int *)ypred_ptr)[3] = ((int *)yabove_row)[3]; - ypred_ptr += y_stride; /*16;*/ + ypred_ptr += y_stride; } } break; @@ -233,7 +106,7 @@ void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x) { vpx_memset(ypred_ptr, yleft_col[r], 16); - ypred_ptr += y_stride; /*16;*/ + ypred_ptr += y_stride; } } @@ -256,11 +129,14 @@ void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x) ypred_ptr[c] = pred; } - ypred_ptr += y_stride; /*16;*/ + ypred_ptr += y_stride; } } break; +#if CONIFG_I8X8 + case I8X8_PRED: +#endif case B_PRED: case NEARESTMV: case NEARMV: @@ -272,145 +148,41 @@ void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x) } } -void vp8_build_intra_predictors_mbuv(MACROBLOCKD *x) +void vp8_build_intra_predictors_mby(MACROBLOCKD *x) { - unsigned char *uabove_row = x->dst.u_buffer - x->dst.uv_stride; - unsigned char uleft_col[16]; - unsigned char utop_left = uabove_row[-1]; - unsigned char *vabove_row = x->dst.v_buffer - x->dst.uv_stride; - unsigned char vleft_col[20]; - unsigned char vtop_left = vabove_row[-1]; - unsigned char *upred_ptr = &x->predictor[256]; - unsigned char *vpred_ptr = &x->predictor[320]; - int i, j; - - for (i = 0; i < 8; i++) - { - uleft_col[i] = x->dst.u_buffer [i* x->dst.uv_stride -1]; - vleft_col[i] = x->dst.v_buffer [i* x->dst.uv_stride -1]; - } - - switch (x->mode_info_context->mbmi.uv_mode) - { - case DC_PRED: - { - int expected_udc; - int expected_vdc; - int i; - int shift; - int Uaverage = 0; - int Vaverage = 0; - - if (x->up_available) - { - for (i = 0; i < 8; i++) - { - Uaverage += uabove_row[i]; - Vaverage += vabove_row[i]; - } - } - - if (x->left_available) - { - for (i = 0; i < 8; i++) - { - Uaverage += uleft_col[i]; - Vaverage += vleft_col[i]; - } - } - - if (!x->up_available && !x->left_available) - { - expected_udc = 128; - expected_vdc = 128; - } - else - { - shift = 2 + x->up_available + x->left_available; - expected_udc = (Uaverage + (1 << (shift - 1))) >> shift; - expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift; - } - - - vpx_memset(upred_ptr, expected_udc, 64); - vpx_memset(vpred_ptr, expected_vdc, 64); - - - } - break; - case V_PRED: - { - int i; - - for (i = 0; i < 8; i++) - { - vpx_memcpy(upred_ptr, uabove_row, 8); - vpx_memcpy(vpred_ptr, vabove_row, 8); - upred_ptr += 8; - vpred_ptr += 8; - } - - } - break; - case H_PRED: - { - int i; - - for (i = 0; i < 8; i++) - { - vpx_memset(upred_ptr, uleft_col[i], 8); - vpx_memset(vpred_ptr, vleft_col[i], 8); - upred_ptr += 8; - vpred_ptr += 8; - } - } - - break; - case TM_PRED: - { - int i; - - for (i = 0; i < 8; i++) - { - for (j = 0; j < 8; j++) - { - int predu = uleft_col[i] + uabove_row[j] - utop_left; - int predv = vleft_col[i] + vabove_row[j] - vtop_left; - - if (predu < 0) - predu = 0; - - if (predu > 255) - predu = 255; - - if (predv < 0) - predv = 0; - - if (predv > 255) - predv = 255; - - upred_ptr[j] = predu; - vpred_ptr[j] = predv; - } - - upred_ptr += 8; - vpred_ptr += 8; - } - - } - break; - case B_PRED: - case NEARESTMV: - case NEARMV: - case ZEROMV: - case NEWMV: - case SPLITMV: - case MB_MODE_COUNT: - break; - } + vp8_build_intra_predictors_mby_internal(x, x->predictor, 16, + x->mode_info_context->mbmi.mode); } -void vp8_build_intra_predictors_mbuv_s(MACROBLOCKD *x) +void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x) +{ + vp8_build_intra_predictors_mby_internal(x, x->dst.y_buffer, x->dst.y_stride, + x->mode_info_context->mbmi.mode); +} + +#if CONFIG_COMP_INTRA_PRED +void vp8_build_comp_intra_predictors_mby(MACROBLOCKD *x) +{ + unsigned char predictor[2][256]; + int i; + + vp8_build_intra_predictors_mby_internal(x, predictor[0], 16, + x->mode_info_context->mbmi.mode); + vp8_build_intra_predictors_mby_internal(x, predictor[1], 16, + x->mode_info_context->mbmi.second_mode); + + for (i = 0; i < 256; i++) + { + x->predictor[i] = (predictor[0][i] + predictor[1][i] + 1) >> 1; + } +} +#endif + +void vp8_build_intra_predictors_mbuv_internal(MACROBLOCKD *x, + unsigned char *upred_ptr, + unsigned char *vpred_ptr, + int uv_stride, + int mode) { unsigned char *uabove_row = x->dst.u_buffer - x->dst.uv_stride; unsigned char uleft_col[16]; @@ -418,9 +190,6 @@ void vp8_build_intra_predictors_mbuv_s(MACROBLOCKD *x) unsigned char *vabove_row = x->dst.v_buffer - x->dst.uv_stride; unsigned char vleft_col[20]; unsigned char vtop_left = vabove_row[-1]; - unsigned char *upred_ptr = x->dst.u_buffer; /*&x->predictor[256];*/ - unsigned char *vpred_ptr = x->dst.v_buffer; /*&x->predictor[320];*/ - int uv_stride = x->dst.uv_stride; int i, j; @@ -430,7 +199,7 @@ void vp8_build_intra_predictors_mbuv_s(MACROBLOCKD *x) vleft_col[i] = x->dst.v_buffer [i* x->dst.uv_stride -1]; } - switch (x->mode_info_context->mbmi.uv_mode) + switch (mode) { case DC_PRED: { @@ -554,3 +323,261 @@ void vp8_build_intra_predictors_mbuv_s(MACROBLOCKD *x) break; } } + +void vp8_build_intra_predictors_mbuv(MACROBLOCKD *x) +{ + vp8_build_intra_predictors_mbuv_internal(x, + &x->predictor[256], + &x->predictor[320], + 8, + x->mode_info_context->mbmi.uv_mode); +} + +void vp8_build_intra_predictors_mbuv_s(MACROBLOCKD *x) +{ + vp8_build_intra_predictors_mbuv_internal(x, + x->dst.u_buffer, + x->dst.v_buffer, + x->dst.uv_stride, + x->mode_info_context->mbmi.uv_mode); +} + +#if CONFIG_COMP_INTRA_PRED +void vp8_build_comp_intra_predictors_mbuv(MACROBLOCKD *x) +{ + unsigned char predictor[2][2][64]; + int i; + + vp8_build_intra_predictors_mbuv_internal(x, predictor[0][0], predictor[1][0], 8, + x->mode_info_context->mbmi.uv_mode); + vp8_build_intra_predictors_mbuv_internal(x, predictor[0][1], predictor[1][1], 8, + x->mode_info_context->mbmi.second_uv_mode); + for (i = 0; i < 64; i++) + { + x->predictor[256 + i] = (predictor[0][0][i] + predictor[0][1][i] + 1) >> 1; + x->predictor[256 + 64 + i] = (predictor[1][0][i] + predictor[1][1][i] + 1) >> 1; + } +} +#endif + +void vp8_intra8x8_predict(BLOCKD *x, + int mode, + unsigned char *predictor) +{ + + unsigned char *yabove_row = *(x->base_dst) + x->dst - x->dst_stride; + unsigned char yleft_col[8]; + unsigned char ytop_left = yabove_row[-1]; + int r, c, i; + + for (i = 0; i < 8; i++) + { + yleft_col[i] = (*(x->base_dst))[x->dst - 1 + i * x->dst_stride]; + } + switch (mode) + { + case DC_PRED: + { + int expected_dc = 0; + + for (i = 0; i < 8; i++) + { + expected_dc += yabove_row[i]; + expected_dc += yleft_col[i]; + } + expected_dc = (expected_dc + 8) >> 4; + + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + predictor[c] = expected_dc; + } + predictor += 16; + } + } + break; + case V_PRED: + { + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + + predictor[c] = yabove_row[c]; + } + predictor += 16; + } + + } + break; + case H_PRED: + { + + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + predictor[c] = yleft_col[r]; + } + predictor += 16; + } + } + break; + case TM_PRED: + { + /* prediction similar to true_motion prediction */ + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + int pred = yabove_row[c] - ytop_left + yleft_col[r]; + if (pred < 0) + pred = 0; + + if (pred > 255) + pred = 255; + predictor[c] = pred; + } + + predictor += 16; + } + } + break; + } +} + +#if CONFIG_COMP_INTRA_PRED +void vp8_comp_intra8x8_predict(BLOCKD *x, + int mode, int second_mode, + unsigned char *out_predictor) +{ + + unsigned char predictor[2][8*16]; + int i, j; + + vp8_intra8x8_predict(x, mode, predictor[0]); + vp8_intra8x8_predict(x, second_mode, predictor[1]); + + for (i = 0; i < 8*16; i += 16) + { + for (j = i; j < i + 8; j++) + { + out_predictor[j] = (predictor[0][j] + predictor[1][j] + 1) >> 1; + } + } +} +#endif + +void vp8_intra_uv4x4_predict(BLOCKD *x, + int mode, + unsigned char *predictor) +{ + + unsigned char *above_row = *(x->base_dst) + x->dst - x->dst_stride; + unsigned char left_col[4]; + unsigned char top_left = above_row[-1]; + int r, c, i; + + for (i = 0; i < 4; i++) + { + left_col[i] = (*(x->base_dst))[x->dst - 1 + i * x->dst_stride]; + } + switch (mode) + { + case DC_PRED: + { + int expected_dc = 0; + + for (i = 0; i < 4; i++) + { + expected_dc += above_row[i]; + expected_dc += left_col[i]; + } + expected_dc = (expected_dc + 4) >> 3; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + predictor[c] = expected_dc; + } + predictor += 8; + } + } + break; + case V_PRED: + { + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + + predictor[c] = above_row[c]; + } + predictor += 8; + } + + } + break; + case H_PRED: + { + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + predictor[c] = left_col[r]; + } + predictor += 8; + } + } + break; + case TM_PRED: + { + /* prediction similar to true_motion prediction */ + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int pred = above_row[c] - top_left + left_col[r]; + if (pred < 0) + pred = 0; + + if (pred > 255) + pred = 255; + predictor[c] = pred; + } + + predictor += 8; + } + } + break; + } +} + +#if CONFIG_COMP_INTRA_PRED +void vp8_comp_intra_uv4x4_predict(BLOCKD *x, + int mode, int mode2, + unsigned char *out_predictor) +{ + unsigned char predictor[2][8*4]; + int i, j; + + vp8_intra_uv4x4_predict(x, mode, predictor[0]); + vp8_intra_uv4x4_predict(x, mode2, predictor[1]); + + for (i = 0; i < 4*8; i += 8) + { + for (j = i; j < i + 4; j++) + { + out_predictor[j] = (predictor[0][j] + predictor[1][j] + 1) >> 1; + } + } +} +#endif + +/* TODO: try different ways of use Y-UV mode correlation + Current code assumes that a uv 4x4 block use same mode + as corresponding Y 8x8 area + */ diff --git a/vp8/common/reconintra4x4.c b/vp8/common/reconintra4x4.c index 3841227e3..ab8be4815 100644 --- a/vp8/common/reconintra4x4.c +++ b/vp8/common/reconintra4x4.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "recon.h" #include "vpx_mem/vpx_mem.h" #include "reconintra.h" @@ -295,6 +295,28 @@ void vp8_intra4x4_predict(BLOCKD *x, } } + +#if CONFIG_COMP_INTRA_PRED +void vp8_comp_intra4x4_predict(BLOCKD *x, + int b_mode, int b_mode2, + unsigned char *out_predictor) +{ + unsigned char predictor[2][4*16]; + int i, j; + + vp8_intra4x4_predict(x, b_mode, predictor[0]); + vp8_intra4x4_predict(x, b_mode2, predictor[1]); + + for (i = 0; i < 16*4; i += 16) + { + for (j = i; j < i + 4; j++) + { + out_predictor[j] = (predictor[0][j] + predictor[1][j] + 1) >> 1; + } + } +} +#endif + /* copy 4 bytes from the above right down so that the 4x4 prediction modes using pixels above and * to the right prediction have filled in pixels to use. */ diff --git a/vp8/common/rotate.h b/vp8/common/rotate.h new file mode 100644 index 000000000..580f55279 --- /dev/null +++ b/vp8/common/rotate.h @@ -0,0 +1,2827 @@ + // angle of -2.5 degrees + -1, 0, 14696, -1, 1, 11702, 0, 0, 24063, 0, 1, 15075, // 0, 0 + -1, 1, 13787, -1, 2, 11164, 0, 1, 25366, 0, 2, 15219, // 0, 1 + -1, 2, 12938, -1, 3, 10637, 0, 2, 26660, 0, 3, 15301, // 0, 2 + -1, 3, 12159, -1, 4, 10135, 0, 3, 27912, 0, 4, 15330, // 0, 3 + -1, 4, 11461, -1, 5, 9673, 0, 4, 29078, 0, 5, 15324, // 0, 4 + -1, 5, 10855, -1, 6, 9265, 0, 5, 30105, 0, 6, 15311, // 0, 5 + -1, 6, 10351, -1, 7, 8927, 0, 6, 30939, 0, 7, 15319, // 0, 6 + -1, 7, 9959, -1, 8, 8669, 0, 7, 31532, 0, 8, 15376, // 0, 7 + 0, 8, 31444, 0, 9, 15301, 1, 8, 10065, 1, 9, 8726, // 0, 8 + 0, 9, 30876, 0, 10, 15193, 1, 9, 10482, 1, 10, 8985, // 0, 9 + 0, 10, 30064, 0, 11, 15135, 1, 10, 11013, 1, 11, 9324, // 0,10 + 0, 11, 29055, 0, 12, 15100, 1, 11, 11652, 1, 12, 9729, // 0,11 + 0, 12, 27903, 0, 13, 15060, 1, 12, 12388, 1, 13, 10185, // 0,12 + 0, 13, 26660, 0, 14, 14990, 1, 13, 13211, 1, 14, 10675, // 0,13 + 0, 14, 25368, 0, 15, 14872, 1, 14, 14109, 1, 15, 11187, // 0,14 + 0, 15, 24063, 0, 16, 14696, 1, 15, 15076, 1, 16, 11701, // 0,15 + 0, 0, 14872, 0, 1, 11187, 1, 0, 25368, 1, 1, 14109, // 1, 0 + 0, 1, 13853, 0, 2, 10644, 1, 1, 26893, 1, 2, 14146, // 1, 1 + 0, 2, 12897, 0, 3, 10102, 1, 2, 28430, 1, 3, 14107, // 1, 2 + 0, 3, 12014, 0, 4, 9575, 1, 3, 29938, 1, 4, 14009, // 1, 3 + 0, 4, 11218, 0, 5, 9082, 1, 4, 31361, 1, 5, 13875, // 1, 4 + 0, 5, 10528, 0, 6, 8645, 1, 5, 32624, 1, 6, 13739, // 1, 5 + 0, 6, 9961, 0, 7, 8286, 1, 6, 33642, 1, 7, 13647, // 1, 6 + 0, 7, 9534, 0, 8, 8024, 1, 7, 34340, 1, 8, 13638, // 1, 7 + 1, 8, 34261, 1, 9, 13582, 2, 8, 9626, 2, 9, 8067, // 1, 8 + 1, 9, 33585, 1, 10, 13548, 2, 9, 10074, 2, 10, 8329, // 1, 9 + 1, 10, 32586, 1, 11, 13600, 2, 10, 10665, 2, 11, 8685, // 1,10 + 1, 11, 31339, 1, 12, 13694, 2, 11, 11385, 2, 12, 9118, // 1,11 + 1, 12, 29928, 1, 13, 13789, 2, 12, 12216, 2, 13, 9603, // 1,12 + 1, 13, 28427, 1, 14, 13850, 2, 13, 13141, 2, 14, 10118, // 1,13 + 1, 14, 26893, 1, 15, 13853, 2, 14, 14145, 2, 15, 10645, // 1,14 + 1, 15, 25366, 1, 16, 13787, 2, 15, 15220, 2, 16, 11163, // 1,15 + 1, 0, 14990, 1, 1, 10676, 2, 0, 26660, 2, 1, 13210, // 2, 0 + 1, 1, 13850, 1, 2, 10119, 2, 1, 28427, 2, 2, 13140, // 2, 1 + 1, 2, 12769, 1, 3, 9546, 2, 2, 30239, 2, 3, 12982, // 2, 2 + 1, 3, 11760, 1, 4, 8976, 2, 3, 32052, 2, 4, 12748, // 2, 3 + 1, 4, 10842, 1, 5, 8432, 2, 4, 33795, 2, 5, 12467, // 2, 4 + 1, 5, 10041, 1, 6, 7943, 2, 5, 35364, 2, 6, 12188, // 2, 5 + 1, 6, 9390, 1, 7, 7543, 2, 6, 36631, 2, 7, 11972, // 2, 6 + 1, 7, 8918, 1, 8, 7266, 2, 7, 37470, 2, 8, 11882, // 2, 7 + 2, 8, 37402, 2, 9, 11842, 3, 8, 8994, 3, 9, 7298, // 2, 8 + 2, 9, 36582, 2, 10, 11897, 3, 9, 9484, 3, 10, 7573, // 2, 9 + 2, 10, 35332, 2, 11, 12079, 3, 10, 10156, 3, 11, 7969, // 2,10 + 2, 11, 33777, 2, 12, 12323, 3, 11, 10983, 3, 12, 8453, // 2,11 + 2, 12, 32045, 2, 13, 12569, 3, 12, 11934, 3, 13, 8988, // 2,12 + 2, 13, 30239, 2, 14, 12769, 3, 13, 12982, 3, 14, 9546, // 2,13 + 2, 14, 28430, 2, 15, 12897, 3, 14, 14107, 3, 15, 10102, // 2,14 + 2, 15, 26660, 2, 16, 12938, 3, 15, 15301, 3, 16, 10637, // 2,15 + 2, 0, 15060, 2, 1, 10185, 3, 0, 27903, 3, 1, 12388, // 3, 0 + 2, 1, 13789, 2, 2, 9603, 3, 1, 29928, 3, 2, 12216, // 3, 1 + 2, 2, 12569, 2, 3, 8988, 3, 2, 32045, 3, 3, 11934, // 3, 2 + 2, 3, 11411, 2, 4, 8358, 3, 3, 34213, 3, 4, 11554, // 3, 3 + 2, 4, 10337, 2, 5, 7737, 3, 4, 36354, 3, 5, 11108, // 3, 4 + 2, 5, 9388, 2, 6, 7165, 3, 5, 38330, 3, 6, 10653, // 3, 5 + 2, 6, 8617, 2, 7, 6695, 3, 6, 39949, 3, 7, 10275, // 3, 6 + 2, 7, 8082, 2, 8, 6381, 3, 7, 40994, 3, 8, 10079, // 3, 7 + 3, 8, 40940, 3, 9, 10051, 4, 8, 8141, 4, 9, 6404, // 3, 8 + 3, 9, 39912, 3, 10, 10221, 4, 9, 8690, 4, 10, 6713, // 3, 9 + 3, 10, 38307, 3, 11, 10569, 4, 10, 9479, 4, 11, 7181, // 3,10 + 3, 11, 36343, 3, 12, 10995, 4, 11, 10452, 4, 12, 7746, // 3,11 + 3, 12, 34213, 3, 13, 11411, 4, 12, 11554, 4, 13, 8358, // 3,12 + 3, 13, 32052, 3, 14, 11760, 4, 13, 12747, 4, 14, 8977, // 3,13 + 3, 14, 29938, 3, 15, 12014, 4, 14, 14009, 4, 15, 9575, // 3,14 + 3, 15, 27912, 3, 16, 12159, 4, 15, 15330, 4, 16, 10135, // 3,15 + 3, 0, 15100, 3, 1, 9728, 4, 0, 29055, 4, 1, 11653, // 4, 0 + 3, 1, 13694, 3, 2, 9118, 4, 1, 31339, 4, 2, 11385, // 4, 1 + 3, 2, 12323, 3, 3, 8452, 4, 2, 33777, 4, 3, 10984, // 4, 2 + 3, 3, 10995, 3, 4, 7746, 4, 3, 36343, 4, 4, 10452, // 4, 3 + 3, 4, 9730, 3, 5, 7022, 4, 4, 38966, 4, 5, 9818, // 4, 4 + 3, 5, 8578, 3, 6, 6328, 4, 5, 41487, 4, 6, 9143, // 4, 5 + 3, 6, 7626, 3, 7, 5739, 4, 6, 43626, 4, 7, 8545, // 4, 6 + 3, 7, 6987, 3, 8, 5354, 4, 7, 44999, 4, 8, 8196, // 4, 7 + 4, 8, 44962, 4, 9, 8177, 5, 8, 7029, 5, 9, 5368, // 4, 8 + 4, 9, 43602, 4, 10, 8507, 5, 9, 7678, 5, 10, 5749, // 4, 9 + 4, 10, 41475, 4, 11, 9081, 5, 10, 8646, 5, 11, 6334, // 4,10 + 4, 11, 38966, 4, 12, 9730, 5, 11, 9818, 5, 12, 7022, // 4,11 + 4, 12, 36354, 4, 13, 10337, 5, 12, 11108, 5, 13, 7737, // 4,12 + 4, 13, 33795, 4, 14, 10842, 5, 13, 12467, 5, 14, 8432, // 4,13 + 4, 14, 31361, 4, 15, 11218, 5, 14, 13875, 5, 15, 9082, // 4,14 + 4, 15, 29078, 4, 16, 11461, 5, 15, 15325, 5, 16, 9672, // 4,15 + 4, 0, 15135, 4, 1, 9323, 5, 0, 30064, 5, 1, 11014, // 5, 0 + 4, 1, 13600, 4, 2, 8685, 5, 1, 32586, 5, 2, 10665, // 5, 1 + 4, 2, 12079, 4, 3, 7969, 5, 2, 35332, 5, 3, 10156, // 5, 2 + 4, 3, 10569, 4, 4, 7180, 5, 3, 38307, 5, 4, 9480, // 5, 3 + 4, 4, 9081, 4, 5, 6334, 5, 4, 41475, 5, 5, 8646, // 5, 4 + 4, 5, 7659, 4, 6, 5472, 5, 5, 44700, 5, 6, 7705, // 5, 5 + 4, 6, 6422, 4, 7, 4690, 5, 6, 47630, 5, 7, 6794, // 5, 6 + 4, 7, 5590, 4, 8, 4164, 5, 7, 49588, 5, 8, 6194, // 5, 7 + 5, 8, 49566, 5, 9, 6183, 6, 8, 5615, 6, 9, 4172, // 5, 8 + 5, 9, 47619, 5, 10, 6768, 6, 9, 6455, 6, 10, 4694, // 5, 9 + 5, 10, 44700, 5, 11, 7659, 6, 10, 7705, 6, 11, 5472, // 5,10 + 5, 11, 41487, 5, 12, 8578, 6, 11, 9143, 6, 12, 6328, // 5,11 + 5, 12, 38330, 5, 13, 9388, 6, 12, 10653, 6, 13, 7165, // 5,12 + 5, 13, 35364, 5, 14, 10041, 6, 13, 12188, 6, 14, 7943, // 5,13 + 5, 14, 32624, 5, 15, 10528, 6, 14, 13740, 6, 15, 8644, // 5,14 + 5, 15, 30105, 5, 16, 10855, 6, 15, 15311, 6, 16, 9265, // 5,15 + 5, 0, 15193, 5, 1, 8986, 6, 0, 30876, 6, 1, 10481, // 6, 0 + 5, 1, 13548, 5, 2, 8329, 6, 1, 33585, 6, 2, 10074, // 6, 1 + 5, 2, 11897, 5, 3, 7573, 6, 2, 36582, 6, 3, 9484, // 6, 2 + 5, 3, 10221, 5, 4, 6714, 6, 3, 39912, 6, 4, 8689, // 6, 3 + 5, 4, 8507, 5, 5, 5749, 6, 4, 43602, 6, 5, 7678, // 6, 4 + 5, 5, 6768, 5, 6, 4694, 6, 5, 47619, 6, 6, 6455, // 6, 5 + 5, 6, 5099, 5, 7, 3620, 6, 6, 51701, 6, 7, 5116, // 6, 6 + 5, 7, 3853, 5, 8, 2795, 6, 7, 54839, 6, 8, 4049, // 6, 7 + 6, 8, 54831, 6, 9, 4044, 7, 8, 3864, 7, 9, 2797, // 6, 8 + 6, 9, 51701, 6, 10, 5099, 7, 9, 5116, 7, 10, 3620, // 6, 9 + 6, 10, 47630, 6, 11, 6422, 7, 10, 6794, 7, 11, 4690, // 6,10 + 6, 11, 43626, 6, 12, 7626, 7, 11, 8545, 7, 12, 5739, // 6,11 + 6, 12, 39949, 6, 13, 8617, 7, 12, 10275, 7, 13, 6695, // 6,12 + 6, 13, 36631, 6, 14, 9390, 7, 13, 11972, 7, 14, 7543, // 6,13 + 6, 14, 33642, 6, 15, 9961, 7, 14, 13647, 7, 15, 8286, // 6,14 + 6, 15, 30939, 6, 16, 10351, 7, 15, 15319, 7, 16, 8927, // 6,15 + 6, 0, 15301, 6, 1, 8727, 7, 0, 31444, 7, 1, 10064, // 7, 0 + 6, 1, 13582, 6, 2, 8068, 7, 1, 34261, 7, 2, 9625, // 7, 1 + 6, 2, 11842, 6, 3, 7298, 7, 2, 37402, 7, 3, 8994, // 7, 2 + 6, 3, 10051, 6, 4, 6403, 7, 3, 40940, 7, 4, 8142, // 7, 3 + 6, 4, 8177, 6, 5, 5368, 7, 4, 44962, 7, 5, 7029, // 7, 4 + 6, 5, 6183, 6, 6, 4172, 7, 5, 49566, 7, 6, 5615, // 7, 5 + 6, 6, 4044, 6, 7, 2797, 7, 6, 54831, 7, 7, 3864, // 7, 6 + 6, 7, 1903, 6, 8, 1347, 7, 7, 60382, 7, 8, 1904, // 7, 7 + 7, 8, 60382, 7, 9, 1903, 8, 8, 1905, 8, 9, 1346, // 7, 8 + 7, 9, 54839, 7, 10, 3853, 8, 9, 4049, 8, 10, 2795, // 7, 9 + 7, 10, 49588, 7, 11, 5590, 8, 10, 6193, 8, 11, 4165, // 7,10 + 7, 11, 44999, 7, 12, 6987, 8, 11, 8195, 8, 12, 5355, // 7,11 + 7, 12, 40994, 7, 13, 8082, 8, 12, 10079, 8, 13, 6381, // 7,12 + 7, 13, 37470, 7, 14, 8918, 8, 13, 11883, 8, 14, 7265, // 7,13 + 7, 14, 34340, 7, 15, 9534, 8, 14, 13638, 8, 15, 8024, // 7,14 + 7, 15, 31532, 7, 16, 9959, 8, 15, 15376, 8, 16, 8669, // 7,15 + 7, -1, 8669, 7, 0, 15376, 8, -1, 9959, 8, 0, 31532, // 8, 0 + 7, 0, 8024, 7, 1, 13638, 8, 0, 9534, 8, 1, 34340, // 8, 1 + 7, 1, 7266, 7, 2, 11883, 8, 1, 8918, 8, 2, 37469, // 8, 2 + 7, 2, 6381, 7, 3, 10079, 8, 2, 8082, 8, 3, 40994, // 8, 3 + 7, 3, 5354, 7, 4, 8195, 8, 3, 6987, 8, 4, 45000, // 8, 4 + 7, 4, 4164, 7, 5, 6193, 8, 4, 5590, 8, 5, 49589, // 8, 5 + 7, 5, 2795, 7, 6, 4049, 8, 5, 3853, 8, 6, 54839, // 8, 6 + 7, 6, 1347, 7, 7, 1905, 8, 6, 1903, 8, 7, 60381, // 8, 7 + 8, 7, 1905, 8, 8, 60382, 9, 7, 1347, 9, 8, 1902, // 8, 8 + 8, 8, 3864, 8, 9, 54831, 9, 8, 2797, 9, 9, 4044, // 8, 9 + 8, 9, 5615, 8, 10, 49566, 9, 9, 4172, 9, 10, 6183, // 8,10 + 8, 10, 7029, 8, 11, 44962, 9, 10, 5368, 9, 11, 8177, // 8,11 + 8, 11, 8141, 8, 12, 40940, 9, 11, 6403, 9, 12, 10052, // 8,12 + 8, 12, 8994, 8, 13, 37402, 9, 12, 7298, 9, 13, 11842, // 8,13 + 8, 13, 9626, 8, 14, 34261, 9, 13, 8068, 9, 14, 13581, // 8,14 + 8, 14, 10065, 8, 15, 31444, 9, 14, 8727, 9, 15, 15300, // 8,15 + 8, -1, 8927, 8, 0, 15319, 9, -1, 10351, 9, 0, 30939, // 9, 0 + 8, 0, 8286, 8, 1, 13647, 9, 0, 9961, 9, 1, 33642, // 9, 1 + 8, 1, 7543, 8, 2, 11972, 9, 1, 9390, 9, 2, 36631, // 9, 2 + 8, 2, 6695, 8, 3, 10275, 9, 2, 8617, 9, 3, 39949, // 9, 3 + 8, 3, 5739, 8, 4, 8545, 9, 3, 7626, 9, 4, 43626, // 9, 4 + 8, 4, 4690, 8, 5, 6794, 9, 4, 6422, 9, 5, 47630, // 9, 5 + 8, 5, 3620, 8, 6, 5116, 9, 5, 5099, 9, 6, 51701, // 9, 6 + 8, 6, 2797, 8, 7, 3864, 9, 6, 4044, 9, 7, 54831, // 9, 7 + 9, 7, 4049, 9, 8, 54839, 10, 7, 2795, 10, 8, 3853, // 9, 8 + 9, 8, 5116, 9, 9, 51701, 10, 8, 3620, 10, 9, 5099, // 9, 9 + 9, 9, 6455, 9, 10, 47619, 10, 9, 4694, 10, 10, 6768, // 9,10 + 9, 10, 7678, 9, 11, 43602, 10, 10, 5749, 10, 11, 8507, // 9,11 + 9, 11, 8690, 9, 12, 39912, 10, 11, 6714, 10, 12, 10220, // 9,12 + 9, 12, 9484, 9, 13, 36582, 10, 12, 7573, 10, 13, 11897, // 9,13 + 9, 13, 10074, 9, 14, 33585, 10, 13, 8329, 10, 14, 13548, // 9,14 + 9, 14, 10482, 9, 15, 30876, 10, 14, 8986, 10, 15, 15192, // 9,15 + 9, -1, 9265, 9, 0, 15311, 10, -1, 10855, 10, 0, 30105, // 10, 0 + 9, 0, 8645, 9, 1, 13740, 10, 0, 10528, 10, 1, 32623, // 10, 1 + 9, 1, 7943, 9, 2, 12188, 10, 1, 10041, 10, 2, 35364, // 10, 2 + 9, 2, 7165, 9, 3, 10653, 10, 2, 9388, 10, 3, 38330, // 10, 3 + 9, 3, 6328, 9, 4, 9143, 10, 3, 8578, 10, 4, 41487, // 10, 4 + 9, 4, 5472, 9, 5, 7705, 10, 4, 7659, 10, 5, 44700, // 10, 5 + 9, 5, 4694, 9, 6, 6455, 10, 5, 6768, 10, 6, 47619, // 10, 6 + 9, 6, 4172, 9, 7, 5615, 10, 6, 6183, 10, 7, 49566, // 10, 7 + 10, 7, 6193, 10, 8, 49588, 11, 7, 4164, 11, 8, 5591, // 10, 8 + 10, 8, 6794, 10, 9, 47630, 11, 8, 4690, 11, 9, 6422, // 10, 9 + 10, 9, 7705, 10, 10, 44700, 11, 9, 5472, 11, 10, 7659, // 10,10 + 10, 10, 8646, 10, 11, 41475, 11, 10, 6334, 11, 11, 9081, // 10,11 + 10, 11, 9479, 10, 12, 38307, 11, 11, 7180, 11, 12, 10570, // 10,12 + 10, 12, 10156, 10, 13, 35332, 11, 12, 7969, 11, 13, 12079, // 10,13 + 10, 13, 10665, 10, 14, 32586, 11, 13, 8685, 11, 14, 13600, // 10,14 + 10, 14, 11013, 10, 15, 30064, 11, 14, 9323, 11, 15, 15136, // 10,15 + 10, -1, 9673, 10, 0, 15325, 11, -1, 11461, 11, 0, 29077, // 11, 0 + 10, 0, 9082, 10, 1, 13875, 11, 0, 11218, 11, 1, 31361, // 11, 1 + 10, 1, 8432, 10, 2, 12467, 11, 1, 10842, 11, 2, 33795, // 11, 2 + 10, 2, 7737, 10, 3, 11108, 11, 2, 10337, 11, 3, 36354, // 11, 3 + 10, 3, 7022, 10, 4, 9818, 11, 3, 9730, 11, 4, 38966, // 11, 4 + 10, 4, 6334, 10, 5, 8646, 11, 4, 9081, 11, 5, 41475, // 11, 5 + 10, 5, 5749, 10, 6, 7678, 11, 5, 8507, 11, 6, 43602, // 11, 6 + 10, 6, 5368, 10, 7, 7029, 11, 6, 8177, 11, 7, 44962, // 11, 7 + 11, 7, 8195, 11, 8, 44999, 12, 7, 5354, 12, 8, 6988, // 11, 8 + 11, 8, 8545, 11, 9, 43626, 12, 8, 5739, 12, 9, 7626, // 11, 9 + 11, 9, 9143, 11, 10, 41487, 12, 9, 6328, 12, 10, 8578, // 11,10 + 11, 10, 9818, 11, 11, 38966, 12, 10, 7022, 12, 11, 9730, // 11,11 + 11, 11, 10452, 11, 12, 36343, 12, 11, 7746, 12, 12, 10995, // 11,12 + 11, 12, 10983, 11, 13, 33777, 12, 12, 8452, 12, 13, 12324, // 11,13 + 11, 13, 11385, 11, 14, 31339, 12, 13, 9118, 12, 14, 13694, // 11,14 + 11, 14, 11652, 11, 15, 29055, 12, 14, 9728, 12, 15, 15101, // 11,15 + 11, -1, 10135, 11, 0, 15330, 12, -1, 12159, 12, 0, 27912, // 12, 0 + 11, 0, 9575, 11, 1, 14009, 12, 0, 12014, 12, 1, 29938, // 12, 1 + 11, 1, 8976, 11, 2, 12747, 12, 1, 11760, 12, 2, 32053, // 12, 2 + 11, 2, 8358, 11, 3, 11554, 12, 2, 11411, 12, 3, 34213, // 12, 3 + 11, 3, 7746, 11, 4, 10452, 12, 3, 10995, 12, 4, 36343, // 12, 4 + 11, 4, 7180, 11, 5, 9479, 12, 4, 10569, 12, 5, 38308, // 12, 5 + 11, 5, 6714, 11, 6, 8690, 12, 5, 10221, 12, 6, 39911, // 12, 6 + 11, 6, 6403, 11, 7, 8141, 12, 6, 10051, 12, 7, 40941, // 12, 7 + 12, 7, 10079, 12, 8, 40994, 13, 7, 6381, 13, 8, 8082, // 12, 8 + 12, 8, 10275, 12, 9, 39949, 13, 8, 6695, 13, 9, 8617, // 12, 9 + 12, 9, 10653, 12, 10, 38330, 13, 9, 7165, 13, 10, 9388, // 12,10 + 12, 10, 11108, 12, 11, 36354, 13, 10, 7737, 13, 11, 10337, // 12,11 + 12, 11, 11554, 12, 12, 34213, 13, 11, 8358, 13, 12, 11411, // 12,12 + 12, 12, 11934, 12, 13, 32045, 13, 12, 8988, 13, 13, 12569, // 12,13 + 12, 13, 12216, 12, 14, 29928, 13, 13, 9603, 13, 14, 13789, // 12,14 + 12, 14, 12388, 12, 15, 27903, 13, 14, 10185, 13, 15, 15060, // 12,15 + 12, -1, 10637, 12, 0, 15301, 13, -1, 12938, 13, 0, 26660, // 13, 0 + 12, 0, 10102, 12, 1, 14107, 13, 0, 12897, 13, 1, 28430, // 13, 1 + 12, 1, 9546, 12, 2, 12982, 13, 1, 12769, 13, 2, 30239, // 13, 2 + 12, 2, 8988, 12, 3, 11934, 13, 2, 12569, 13, 3, 32045, // 13, 3 + 12, 3, 8452, 12, 4, 10983, 13, 3, 12323, 13, 4, 33778, // 13, 4 + 12, 4, 7969, 12, 5, 10156, 13, 4, 12079, 13, 5, 35332, // 13, 5 + 12, 5, 7573, 12, 6, 9484, 13, 5, 11897, 13, 6, 36582, // 13, 6 + 12, 6, 7298, 12, 7, 8994, 13, 6, 11842, 13, 7, 37402, // 13, 7 + 13, 7, 11883, 13, 8, 37470, 14, 7, 7266, 14, 8, 8917, // 13, 8 + 13, 8, 11972, 13, 9, 36631, 14, 8, 7543, 14, 9, 9390, // 13, 9 + 13, 9, 12188, 13, 10, 35364, 14, 9, 7943, 14, 10, 10041, // 13,10 + 13, 10, 12467, 13, 11, 33795, 14, 10, 8432, 14, 11, 10842, // 13,11 + 13, 11, 12747, 13, 12, 32052, 14, 11, 8976, 14, 12, 11761, // 13,12 + 13, 12, 12982, 13, 13, 30239, 14, 12, 9546, 14, 13, 12769, // 13,13 + 13, 13, 13141, 13, 14, 28427, 14, 13, 10119, 14, 14, 13849, // 13,14 + 13, 14, 13211, 13, 15, 26660, 14, 14, 10676, 14, 15, 14989, // 13,15 + 13, -1, 11164, 13, 0, 15220, 14, -1, 13787, 14, 0, 25365, // 14, 0 + 13, 0, 10644, 13, 1, 14145, 14, 0, 13853, 14, 1, 26894, // 14, 1 + 13, 1, 10119, 13, 2, 13141, 14, 1, 13850, 14, 2, 28426, // 14, 2 + 13, 2, 9603, 13, 3, 12216, 14, 2, 13789, 14, 3, 29928, // 14, 3 + 13, 3, 9118, 13, 4, 11385, 14, 3, 13694, 14, 4, 31339, // 14, 4 + 13, 4, 8685, 13, 5, 10665, 14, 4, 13600, 14, 5, 32586, // 14, 5 + 13, 5, 8329, 13, 6, 10074, 14, 5, 13548, 14, 6, 33585, // 14, 6 + 13, 6, 8068, 13, 7, 9626, 14, 6, 13582, 14, 7, 34260, // 14, 7 + 14, 7, 13638, 14, 8, 34340, 15, 7, 8024, 15, 8, 9534, // 14, 8 + 14, 8, 13647, 14, 9, 33642, 15, 8, 8286, 15, 9, 9961, // 14, 9 + 14, 9, 13740, 14, 10, 32624, 15, 9, 8645, 15, 10, 10527, // 14,10 + 14, 10, 13875, 14, 11, 31361, 15, 10, 9082, 15, 11, 11218, // 14,11 + 14, 11, 14009, 14, 12, 29938, 15, 11, 9575, 15, 12, 12014, // 14,12 + 14, 12, 14107, 14, 13, 28430, 15, 12, 10102, 15, 13, 12897, // 14,13 + 14, 13, 14145, 14, 14, 26893, 15, 13, 10644, 15, 14, 13854, // 14,14 + 14, 14, 14109, 14, 15, 25368, 15, 14, 11187, 15, 15, 14872, // 14,15 + 14, -1, 11702, 14, 0, 15076, 15, -1, 14696, 15, 0, 24062, // 15, 0 + 14, 0, 11187, 14, 1, 14109, 15, 0, 14872, 15, 1, 25368, // 15, 1 + 14, 1, 10676, 14, 2, 13211, 15, 1, 14990, 15, 2, 26659, // 15, 2 + 14, 2, 10185, 14, 3, 12388, 15, 2, 15060, 15, 3, 27903, // 15, 3 + 14, 3, 9728, 14, 4, 11652, 15, 3, 15100, 15, 4, 29056, // 15, 4 + 14, 4, 9323, 14, 5, 11013, 15, 4, 15135, 15, 5, 30065, // 15, 5 + 14, 5, 8986, 14, 6, 10482, 15, 5, 15193, 15, 6, 30875, // 15, 6 + 14, 6, 8727, 14, 7, 10065, 15, 6, 15301, 15, 7, 31443, // 15, 7 + 15, 7, 15376, 15, 8, 31532, 16, 7, 8669, 16, 8, 9959, // 15, 8 + 15, 8, 15319, 15, 9, 30939, 16, 8, 8927, 16, 9, 10351, // 15, 9 + 15, 9, 15311, 15, 10, 30105, 16, 9, 9265, 16, 10, 10855, // 15,10 + 15, 10, 15325, 15, 11, 29078, 16, 10, 9673, 16, 11, 11460, // 15,11 + 15, 11, 15330, 15, 12, 27912, 16, 11, 10135, 16, 12, 12159, // 15,12 + 15, 12, 15301, 15, 13, 26660, 16, 12, 10637, 16, 13, 12938, // 15,13 + 15, 13, 15220, 15, 14, 25366, 16, 13, 11164, 16, 14, 13786, // 15,14 + 15, 14, 15076, 15, 15, 24063, 16, 14, 11702, 16, 15, 14695, // 15,15 + // angle of -2.0 degrees + -1, 0, 13368, -1, 1, 10104, 0, 0, 28495, 0, 1, 13569, // 0, 0 + -1, 1, 12574, -1, 2, 9662, 0, 1, 29831, 0, 2, 13469, // 0, 1 + -1, 2, 11829, -1, 3, 9229, 0, 2, 31146, 0, 3, 13332, // 0, 2 + -1, 3, 11143, -1, 4, 8816, 0, 3, 32406, 0, 4, 13171, // 0, 3 + -1, 4, 10528, -1, 5, 8438, 0, 4, 33564, 0, 5, 13006, // 0, 4 + -1, 5, 9995, -1, 6, 8107, 0, 5, 34567, 0, 6, 12867, // 0, 5 + -1, 6, 9558, -1, 7, 7839, 0, 6, 35362, 0, 7, 12777, // 0, 6 + -1, 7, 9224, -1, 8, 7643, 0, 7, 35905, 0, 8, 12764, // 0, 7 + 0, 8, 35844, 0, 9, 12728, 1, 8, 9290, 1, 9, 7674, // 0, 8 + 0, 9, 35315, 0, 10, 12717, 1, 9, 9635, 1, 10, 7869, // 0, 9 + 0, 10, 34532, 0, 11, 12783, 1, 10, 10086, 1, 11, 8135, // 0,10 + 0, 11, 33539, 0, 12, 12899, 1, 11, 10635, 1, 12, 8463, // 0,11 + 0, 12, 32391, 0, 13, 13038, 1, 12, 11269, 1, 13, 8838, // 0,12 + 0, 13, 31138, 0, 14, 13176, 1, 13, 11977, 1, 14, 9245, // 0,13 + 0, 14, 29828, 0, 15, 13291, 1, 14, 12746, 1, 15, 9671, // 0,14 + 0, 15, 28495, 0, 16, 13368, 1, 15, 13569, 1, 16, 10104, // 0,15 + 0, 0, 13291, 0, 1, 9671, 1, 0, 29828, 1, 1, 12746, // 1, 0 + 0, 1, 12412, 0, 2, 9202, 1, 1, 31358, 1, 2, 12564, // 1, 1 + 0, 2, 11580, 0, 3, 8735, 1, 2, 32886, 1, 3, 12335, // 1, 2 + 0, 3, 10808, 0, 4, 8284, 1, 3, 34369, 1, 4, 12075, // 1, 3 + 0, 4, 10111, 0, 5, 7865, 1, 4, 35750, 1, 5, 11810, // 1, 4 + 0, 5, 9509, 0, 6, 7497, 1, 5, 36955, 1, 6, 11575, // 1, 5 + 0, 6, 9020, 0, 7, 7202, 1, 6, 37906, 1, 7, 11408, // 1, 6 + 0, 7, 8662, 0, 8, 6997, 1, 7, 38534, 1, 8, 11343, // 1, 7 + 1, 8, 38481, 1, 9, 11317, 2, 8, 8718, 2, 9, 7020, // 1, 8 + 1, 9, 37866, 1, 10, 11360, 2, 9, 9086, 2, 10, 7224, // 1, 9 + 1, 10, 36926, 1, 11, 11507, 2, 10, 9587, 2, 11, 7516, // 1,10 + 1, 11, 35730, 1, 12, 11721, 2, 11, 10204, 2, 12, 7881, // 1,11 + 1, 12, 34358, 1, 13, 11964, 2, 12, 10918, 2, 13, 8296, // 1,12 + 1, 13, 32881, 1, 14, 12203, 2, 13, 11709, 2, 14, 8743, // 1,13 + 1, 14, 31358, 1, 15, 12412, 2, 14, 12564, 2, 15, 9202, // 1,14 + 1, 15, 29831, 1, 16, 12574, 2, 15, 13470, 2, 16, 9661, // 1,15 + 1, 0, 13176, 1, 1, 9245, 2, 0, 31138, 2, 1, 11977, // 2, 0 + 1, 1, 12203, 1, 2, 8742, 2, 1, 32881, 2, 2, 11710, // 2, 1 + 1, 2, 11272, 1, 3, 8232, 2, 2, 34650, 2, 3, 11382, // 2, 2 + 1, 3, 10397, 1, 4, 7728, 2, 3, 36399, 2, 4, 11012, // 2, 3 + 1, 4, 9597, 1, 5, 7252, 2, 4, 38057, 2, 5, 10630, // 2, 4 + 1, 5, 8902, 1, 6, 6829, 2, 5, 39526, 2, 6, 10279, // 2, 5 + 1, 6, 8344, 1, 7, 6491, 2, 6, 40688, 2, 7, 10013, // 2, 6 + 1, 7, 7951, 1, 8, 6266, 2, 7, 41432, 2, 8, 9887, // 2, 7 + 2, 8, 41389, 2, 9, 9867, 3, 8, 7996, 3, 9, 6284, // 2, 8 + 2, 9, 40656, 2, 10, 9977, 3, 9, 8397, 3, 10, 6506, // 2, 9 + 2, 10, 39503, 2, 11, 10226, 3, 10, 8966, 3, 11, 6841, // 2,10 + 2, 11, 38042, 2, 12, 10559, 3, 11, 9674, 3, 12, 7261, // 2,11 + 2, 12, 36392, 2, 13, 10922, 3, 12, 10488, 3, 13, 7734, // 2,12 + 2, 13, 34650, 2, 14, 11272, 3, 13, 11382, 3, 14, 8232, // 2,13 + 2, 14, 32886, 2, 15, 11580, 3, 14, 12334, 3, 15, 8736, // 2,14 + 2, 15, 31146, 2, 16, 11829, 3, 15, 13332, 3, 16, 9229, // 2,15 + 2, 0, 13038, 2, 1, 8838, 3, 0, 32391, 3, 1, 11269, // 3, 0 + 2, 1, 11964, 2, 2, 8296, 3, 1, 34358, 3, 2, 10918, // 3, 1 + 2, 2, 10922, 2, 3, 7734, 3, 2, 36392, 3, 3, 10488, // 3, 2 + 2, 3, 9924, 2, 4, 7164, 3, 3, 38450, 3, 4, 9998, // 3, 3 + 2, 4, 8995, 2, 5, 6611, 3, 4, 40452, 3, 5, 9478, // 3, 4 + 2, 5, 8175, 2, 6, 6108, 3, 5, 42271, 3, 6, 8982, // 3, 5 + 2, 6, 7516, 2, 7, 5703, 3, 6, 43733, 3, 7, 8584, // 3, 6 + 2, 7, 7072, 2, 8, 5443, 3, 7, 44649, 3, 8, 8372, // 3, 7 + 3, 8, 44616, 3, 9, 8359, 4, 8, 7106, 4, 9, 5455, // 3, 8 + 3, 9, 43710, 3, 10, 8558, 4, 9, 7556, 4, 10, 5712, // 3, 9 + 3, 10, 42256, 3, 11, 8940, 4, 10, 8224, 4, 11, 6116, // 3,10 + 3, 11, 40444, 3, 12, 9421, 4, 11, 9056, 4, 12, 6615, // 3,11 + 3, 12, 38450, 3, 13, 9924, 4, 12, 9998, 4, 13, 7164, // 3,12 + 3, 13, 36399, 3, 14, 10397, 4, 13, 11012, 4, 14, 7728, // 3,13 + 3, 14, 34369, 3, 15, 10808, 4, 14, 12074, 4, 15, 8285, // 3,14 + 3, 15, 32406, 3, 16, 11143, 4, 15, 13171, 4, 16, 8816, // 3,15 + 3, 0, 12899, 3, 1, 8463, 4, 0, 33539, 4, 1, 10635, // 4, 0 + 3, 1, 11721, 3, 2, 7881, 4, 1, 35730, 4, 2, 10204, // 4, 1 + 3, 2, 10559, 3, 3, 7261, 4, 2, 38042, 4, 3, 9674, // 4, 2 + 3, 3, 9421, 3, 4, 6615, 4, 3, 40444, 4, 4, 9056, // 4, 3 + 3, 4, 8332, 3, 5, 5965, 4, 4, 42861, 4, 5, 8378, // 4, 4 + 3, 5, 7342, 3, 6, 5350, 4, 5, 45146, 4, 6, 7698, // 4, 5 + 3, 6, 6530, 3, 7, 4838, 4, 6, 47049, 4, 7, 7119, // 4, 6 + 3, 7, 6000, 3, 8, 4513, 4, 7, 48240, 4, 8, 6783, // 4, 7 + 4, 8, 48218, 4, 9, 6774, 5, 8, 6023, 5, 9, 4521, // 4, 8 + 4, 9, 47035, 4, 10, 7100, 5, 9, 6558, 5, 10, 4843, // 4, 9 + 4, 10, 45139, 4, 11, 7667, 5, 10, 7377, 5, 11, 5353, // 4,10 + 4, 11, 42861, 4, 12, 8332, 5, 11, 8378, 5, 12, 5965, // 4,11 + 4, 12, 40452, 4, 13, 8995, 5, 12, 9478, 5, 13, 6611, // 4,12 + 4, 13, 38057, 4, 14, 9597, 5, 13, 10630, 5, 14, 7252, // 4,13 + 4, 14, 35750, 4, 15, 10111, 5, 14, 11810, 5, 15, 7865, // 4,14 + 4, 15, 33564, 4, 16, 10528, 5, 15, 13007, 5, 16, 8437, // 4,15 + 4, 0, 12783, 4, 1, 8135, 5, 0, 34532, 5, 1, 10086, // 5, 0 + 4, 1, 11507, 4, 2, 7517, 5, 1, 36926, 5, 2, 9586, // 5, 1 + 4, 2, 10226, 4, 3, 6842, 5, 2, 39503, 5, 3, 8965, // 5, 2 + 4, 3, 8940, 4, 4, 6116, 5, 3, 42256, 5, 4, 8224, // 5, 3 + 4, 4, 7667, 4, 5, 5353, 5, 4, 45139, 5, 5, 7377, // 5, 4 + 4, 5, 6451, 4, 6, 4591, 5, 5, 48019, 5, 6, 6475, // 5, 5 + 4, 6, 5400, 4, 7, 3911, 5, 6, 50587, 5, 7, 5638, // 5, 6 + 4, 7, 4708, 4, 8, 3466, 5, 7, 52266, 5, 8, 5096, // 5, 7 + 5, 8, 52253, 5, 9, 5092, 6, 8, 4721, 6, 9, 3470, // 5, 8 + 5, 9, 50581, 5, 10, 5624, 6, 9, 5418, 6, 10, 3913, // 5, 9 + 5, 10, 48019, 5, 11, 6451, 6, 10, 6475, 6, 11, 4591, // 5,10 + 5, 11, 45146, 5, 12, 7342, 6, 11, 7698, 6, 12, 5350, // 5,11 + 5, 12, 42271, 5, 13, 8175, 6, 12, 8982, 6, 13, 6108, // 5,12 + 5, 13, 39526, 5, 14, 8902, 6, 13, 10279, 6, 14, 6829, // 5,13 + 5, 14, 36955, 5, 15, 9509, 6, 14, 11575, 6, 15, 7497, // 5,14 + 5, 15, 34567, 5, 16, 9995, 6, 15, 12867, 6, 16, 8107, // 5,15 + 5, 0, 12717, 5, 1, 7868, 6, 0, 35315, 6, 1, 9636, // 6, 0 + 5, 1, 11360, 5, 2, 7224, 6, 1, 37866, 6, 2, 9086, // 6, 1 + 5, 2, 9977, 5, 3, 6506, 6, 2, 40656, 6, 3, 8397, // 6, 2 + 5, 3, 8558, 5, 4, 5712, 6, 3, 43710, 6, 4, 7556, // 6, 3 + 5, 4, 7100, 5, 5, 4843, 6, 4, 47035, 6, 5, 6558, // 6, 4 + 5, 5, 5624, 5, 6, 3913, 6, 5, 50581, 6, 6, 5418, // 6, 5 + 5, 6, 4217, 5, 7, 2989, 6, 6, 54105, 6, 7, 4225, // 6, 6 + 5, 7, 3180, 5, 8, 2294, 6, 7, 56756, 6, 8, 3306, // 6, 7 + 6, 8, 56751, 6, 9, 3303, 7, 8, 3186, 7, 9, 2296, // 6, 8 + 6, 9, 54105, 6, 10, 4217, 7, 9, 4225, 7, 10, 2989, // 6, 9 + 6, 10, 50587, 6, 11, 5400, 7, 10, 5637, 7, 11, 3912, // 6,10 + 6, 11, 47049, 6, 12, 6530, 7, 11, 7119, 7, 12, 4838, // 6,11 + 6, 12, 43733, 6, 13, 7516, 7, 12, 8584, 7, 13, 5703, // 6,12 + 6, 13, 40688, 6, 14, 8344, 7, 13, 10013, 7, 14, 6491, // 6,13 + 6, 14, 37906, 6, 15, 9020, 7, 14, 11407, 7, 15, 7203, // 6,14 + 6, 15, 35362, 6, 16, 9558, 7, 15, 12777, 7, 16, 7839, // 6,15 + 6, 0, 12728, 6, 1, 7674, 7, 0, 35844, 7, 1, 9290, // 7, 0 + 6, 1, 11317, 6, 2, 7020, 7, 1, 38481, 7, 2, 8718, // 7, 1 + 6, 2, 9867, 6, 3, 6284, 7, 2, 41389, 7, 3, 7996, // 7, 2 + 6, 3, 8359, 6, 4, 5454, 7, 3, 44616, 7, 4, 7107, // 7, 3 + 6, 4, 6774, 6, 5, 4521, 7, 4, 48218, 7, 5, 6023, // 7, 4 + 6, 5, 5092, 6, 6, 3470, 7, 5, 52253, 7, 6, 4721, // 7, 5 + 6, 6, 3303, 6, 7, 2295, 7, 6, 56751, 7, 7, 3187, // 7, 6 + 6, 7, 1541, 6, 8, 1090, 7, 7, 61364, 7, 8, 1541, // 7, 7 + 7, 8, 61364, 7, 9, 1541, 8, 8, 1542, 8, 9, 1089, // 7, 8 + 7, 9, 56756, 7, 10, 3180, 8, 9, 3306, 8, 10, 2294, // 7, 9 + 7, 10, 52266, 7, 11, 4708, 8, 10, 5097, 8, 11, 3465, // 7,10 + 7, 11, 48240, 7, 12, 6000, 8, 11, 6783, 8, 12, 4513, // 7,11 + 7, 12, 44649, 7, 13, 7072, 8, 12, 8373, 8, 13, 5442, // 7,12 + 7, 13, 41432, 7, 14, 7951, 8, 13, 9886, 8, 14, 6267, // 7,13 + 7, 14, 38534, 7, 15, 8662, 8, 14, 11344, 8, 15, 6996, // 7,14 + 7, 15, 35905, 7, 16, 9224, 8, 15, 12764, 8, 16, 7643, // 7,15 + 7, -1, 7643, 7, 0, 12764, 8, -1, 9224, 8, 0, 35905, // 8, 0 + 7, 0, 6997, 7, 1, 11344, 8, 0, 8662, 8, 1, 38533, // 8, 1 + 7, 1, 6266, 7, 2, 9886, 8, 1, 7951, 8, 2, 41433, // 8, 2 + 7, 2, 5443, 7, 3, 8373, 8, 2, 7072, 8, 3, 44648, // 8, 3 + 7, 3, 4513, 7, 4, 6783, 8, 3, 6000, 8, 4, 48240, // 8, 4 + 7, 4, 3466, 7, 5, 5097, 8, 4, 4708, 8, 5, 52265, // 8, 5 + 7, 5, 2294, 7, 6, 3306, 8, 5, 3180, 8, 6, 56756, // 8, 6 + 7, 6, 1090, 7, 7, 1542, 8, 6, 1541, 8, 7, 61363, // 8, 7 + 8, 7, 1542, 8, 8, 61364, 9, 7, 1090, 9, 8, 1540, // 8, 8 + 8, 8, 3186, 8, 9, 56751, 9, 8, 2295, 9, 9, 3304, // 8, 9 + 8, 9, 4721, 8, 10, 52253, 9, 9, 3470, 9, 10, 5092, // 8,10 + 8, 10, 6023, 8, 11, 48218, 9, 10, 4521, 9, 11, 6774, // 8,11 + 8, 11, 7106, 8, 12, 44616, 9, 11, 5454, 9, 12, 8360, // 8,12 + 8, 12, 7996, 8, 13, 41389, 9, 12, 6284, 9, 13, 9867, // 8,13 + 8, 13, 8718, 8, 14, 38481, 9, 13, 7020, 9, 14, 11317, // 8,14 + 8, 14, 9290, 8, 15, 35844, 9, 14, 7674, 9, 15, 12728, // 8,15 + 8, -1, 7839, 8, 0, 12777, 9, -1, 9558, 9, 0, 35362, // 9, 0 + 8, 0, 7202, 8, 1, 11407, 9, 0, 9020, 9, 1, 37907, // 9, 1 + 8, 1, 6491, 8, 2, 10013, 9, 1, 8344, 9, 2, 40688, // 9, 2 + 8, 2, 5703, 8, 3, 8584, 9, 2, 7516, 9, 3, 43733, // 9, 3 + 8, 3, 4838, 8, 4, 7119, 9, 3, 6530, 9, 4, 47049, // 9, 4 + 8, 4, 3911, 8, 5, 5637, 9, 4, 5400, 9, 5, 50588, // 9, 5 + 8, 5, 2989, 8, 6, 4225, 9, 5, 4217, 9, 6, 54105, // 9, 6 + 8, 6, 2295, 8, 7, 3186, 9, 6, 3303, 9, 7, 56752, // 9, 7 + 9, 7, 3306, 9, 8, 56756, 10, 7, 2294, 10, 8, 3180, // 9, 8 + 9, 8, 4225, 9, 9, 54105, 10, 8, 2989, 10, 9, 4217, // 9, 9 + 9, 9, 5418, 9, 10, 50581, 10, 9, 3913, 10, 10, 5624, // 9,10 + 9, 10, 6558, 9, 11, 47035, 10, 10, 4843, 10, 11, 7100, // 9,11 + 9, 11, 7556, 9, 12, 43710, 10, 11, 5712, 10, 12, 8558, // 9,12 + 9, 12, 8397, 9, 13, 40656, 10, 12, 6506, 10, 13, 9977, // 9,13 + 9, 13, 9086, 9, 14, 37866, 10, 13, 7224, 10, 14, 11360, // 9,14 + 9, 14, 9635, 9, 15, 35315, 10, 14, 7868, 10, 15, 12718, // 9,15 + 9, -1, 8107, 9, 0, 12867, 10, -1, 9995, 10, 0, 34567, // 10, 0 + 9, 0, 7497, 9, 1, 11575, 10, 0, 9509, 10, 1, 36955, // 10, 1 + 9, 1, 6829, 9, 2, 10279, 10, 1, 8902, 10, 2, 39526, // 10, 2 + 9, 2, 6108, 9, 3, 8982, 10, 2, 8175, 10, 3, 42271, // 10, 3 + 9, 3, 5350, 9, 4, 7698, 10, 3, 7342, 10, 4, 45146, // 10, 4 + 9, 4, 4591, 9, 5, 6475, 10, 4, 6451, 10, 5, 48019, // 10, 5 + 9, 5, 3913, 9, 6, 5418, 10, 5, 5624, 10, 6, 50581, // 10, 6 + 9, 6, 3470, 9, 7, 4721, 10, 6, 5092, 10, 7, 52253, // 10, 7 + 10, 7, 5097, 10, 8, 52266, 11, 7, 3466, 11, 8, 4707, // 10, 8 + 10, 8, 5637, 10, 9, 50587, 11, 8, 3911, 11, 9, 5401, // 10, 9 + 10, 9, 6475, 10, 10, 48019, 11, 9, 4591, 11, 10, 6451, // 10,10 + 10, 10, 7377, 10, 11, 45139, 11, 10, 5353, 11, 11, 7667, // 10,11 + 10, 11, 8224, 10, 12, 42256, 11, 11, 6116, 11, 12, 8940, // 10,12 + 10, 12, 8966, 10, 13, 39503, 11, 12, 6842, 11, 13, 10225, // 10,13 + 10, 13, 9587, 10, 14, 36926, 11, 13, 7517, 11, 14, 11506, // 10,14 + 10, 14, 10086, 10, 15, 34532, 11, 14, 8135, 11, 15, 12783, // 10,15 + 10, -1, 8438, 10, 0, 13007, 11, -1, 10528, 11, 0, 33563, // 11, 0 + 10, 0, 7865, 10, 1, 11810, 11, 0, 10111, 11, 1, 35750, // 11, 1 + 10, 1, 7252, 10, 2, 10630, 11, 1, 9597, 11, 2, 38057, // 11, 2 + 10, 2, 6611, 10, 3, 9478, 11, 2, 8995, 11, 3, 40452, // 11, 3 + 10, 3, 5965, 10, 4, 8378, 11, 3, 8332, 11, 4, 42861, // 11, 4 + 10, 4, 5353, 10, 5, 7377, 11, 4, 7667, 11, 5, 45139, // 11, 5 + 10, 5, 4843, 10, 6, 6558, 11, 5, 7100, 11, 6, 47035, // 11, 6 + 10, 6, 4521, 10, 7, 6023, 11, 6, 6774, 11, 7, 48218, // 11, 7 + 11, 7, 6783, 11, 8, 48240, 12, 7, 4513, 12, 8, 6000, // 11, 8 + 11, 8, 7119, 11, 9, 47049, 12, 8, 4838, 12, 9, 6530, // 11, 9 + 11, 9, 7698, 11, 10, 45146, 12, 9, 5350, 12, 10, 7342, // 11,10 + 11, 10, 8378, 11, 11, 42861, 12, 10, 5965, 12, 11, 8332, // 11,11 + 11, 11, 9056, 11, 12, 40444, 12, 11, 6615, 12, 12, 9421, // 11,12 + 11, 12, 9674, 11, 13, 38042, 12, 12, 7261, 12, 13, 10559, // 11,13 + 11, 13, 10204, 11, 14, 35730, 12, 13, 7881, 12, 14, 11721, // 11,14 + 11, 14, 10635, 11, 15, 33539, 12, 14, 8463, 12, 15, 12899, // 11,15 + 11, -1, 8816, 11, 0, 13171, 12, -1, 11143, 12, 0, 32406, // 12, 0 + 11, 0, 8284, 11, 1, 12074, 12, 0, 10808, 12, 1, 34370, // 12, 1 + 11, 1, 7728, 11, 2, 11012, 12, 1, 10397, 12, 2, 36399, // 12, 2 + 11, 2, 7164, 11, 3, 9998, 12, 2, 9924, 12, 3, 38450, // 12, 3 + 11, 3, 6615, 11, 4, 9056, 12, 3, 9421, 12, 4, 40444, // 12, 4 + 11, 4, 6116, 11, 5, 8224, 12, 4, 8940, 12, 5, 42256, // 12, 5 + 11, 5, 5712, 11, 6, 7556, 12, 5, 8558, 12, 6, 43710, // 12, 6 + 11, 6, 5454, 11, 7, 7106, 12, 6, 8359, 12, 7, 44617, // 12, 7 + 12, 7, 8373, 12, 8, 44649, 13, 7, 5443, 13, 8, 7071, // 12, 8 + 12, 8, 8584, 12, 9, 43733, 13, 8, 5703, 13, 9, 7516, // 12, 9 + 12, 9, 8982, 12, 10, 42271, 13, 9, 6108, 13, 10, 8175, // 12,10 + 12, 10, 9478, 12, 11, 40452, 13, 10, 6611, 13, 11, 8995, // 12,11 + 12, 11, 9998, 12, 12, 38450, 13, 11, 7164, 13, 12, 9924, // 12,12 + 12, 12, 10488, 12, 13, 36392, 13, 12, 7734, 13, 13, 10922, // 12,13 + 12, 13, 10918, 12, 14, 34358, 13, 13, 8296, 13, 14, 11964, // 12,14 + 12, 14, 11269, 12, 15, 32391, 13, 14, 8838, 13, 15, 13038, // 12,15 + 12, -1, 9229, 12, 0, 13332, 13, -1, 11829, 13, 0, 31146, // 13, 0 + 12, 0, 8735, 12, 1, 12334, 13, 0, 11580, 13, 1, 32887, // 13, 1 + 12, 1, 8232, 12, 2, 11382, 13, 1, 11272, 13, 2, 34650, // 13, 2 + 12, 2, 7734, 12, 3, 10488, 13, 2, 10922, 13, 3, 36392, // 13, 3 + 12, 3, 7261, 12, 4, 9674, 13, 3, 10559, 13, 4, 38042, // 13, 4 + 12, 4, 6842, 12, 5, 8966, 13, 4, 10226, 13, 5, 39502, // 13, 5 + 12, 5, 6506, 12, 6, 8397, 13, 5, 9977, 13, 6, 40656, // 13, 6 + 12, 6, 6284, 12, 7, 7996, 13, 6, 9867, 13, 7, 41389, // 13, 7 + 13, 7, 9886, 13, 8, 41432, 14, 7, 6266, 14, 8, 7952, // 13, 8 + 13, 8, 10013, 13, 9, 40688, 14, 8, 6491, 14, 9, 8344, // 13, 9 + 13, 9, 10279, 13, 10, 39526, 14, 9, 6829, 14, 10, 8902, // 13,10 + 13, 10, 10630, 13, 11, 38057, 14, 10, 7252, 14, 11, 9597, // 13,11 + 13, 11, 11012, 13, 12, 36399, 14, 11, 7728, 14, 12, 10397, // 13,12 + 13, 12, 11382, 13, 13, 34650, 14, 12, 8232, 14, 13, 11272, // 13,13 + 13, 13, 11709, 13, 14, 32881, 14, 13, 8742, 14, 14, 12204, // 13,14 + 13, 14, 11977, 13, 15, 31138, 14, 14, 9245, 14, 15, 13176, // 13,15 + 13, -1, 9662, 13, 0, 13470, 14, -1, 12574, 14, 0, 29830, // 14, 0 + 13, 0, 9202, 13, 1, 12564, 14, 0, 12412, 14, 1, 31358, // 14, 1 + 13, 1, 8742, 13, 2, 11709, 14, 1, 12203, 14, 2, 32882, // 14, 2 + 13, 2, 8296, 13, 3, 10918, 14, 2, 11964, 14, 3, 34358, // 14, 3 + 13, 3, 7881, 13, 4, 10204, 14, 3, 11721, 14, 4, 35730, // 14, 4 + 13, 4, 7517, 13, 5, 9587, 14, 4, 11507, 14, 5, 36925, // 14, 5 + 13, 5, 7224, 13, 6, 9086, 14, 5, 11360, 14, 6, 37866, // 14, 6 + 13, 6, 7020, 13, 7, 8718, 14, 6, 11317, 14, 7, 38481, // 14, 7 + 14, 7, 11344, 14, 8, 38534, 15, 7, 6997, 15, 8, 8661, // 14, 8 + 14, 8, 11407, 14, 9, 37906, 15, 8, 7202, 15, 9, 9021, // 14, 9 + 14, 9, 11575, 14, 10, 36955, 15, 9, 7497, 15, 10, 9509, // 14,10 + 14, 10, 11810, 14, 11, 35750, 15, 10, 7865, 15, 11, 10111, // 14,11 + 14, 11, 12074, 14, 12, 34369, 15, 11, 8284, 15, 12, 10809, // 14,12 + 14, 12, 12334, 14, 13, 32886, 15, 12, 8735, 15, 13, 11581, // 14,13 + 14, 13, 12564, 14, 14, 31358, 15, 13, 9202, 15, 14, 12412, // 14,14 + 14, 14, 12746, 14, 15, 29828, 15, 14, 9671, 15, 15, 13291, // 14,15 + 14, -1, 10104, 14, 0, 13569, 15, -1, 13368, 15, 0, 28495, // 15, 0 + 14, 0, 9671, 14, 1, 12746, 15, 0, 13291, 15, 1, 29828, // 15, 1 + 14, 1, 9245, 14, 2, 11977, 15, 1, 13176, 15, 2, 31138, // 15, 2 + 14, 2, 8838, 14, 3, 11269, 15, 2, 13038, 15, 3, 32391, // 15, 3 + 14, 3, 8463, 14, 4, 10635, 15, 3, 12899, 15, 4, 33539, // 15, 4 + 14, 4, 8135, 14, 5, 10086, 15, 4, 12783, 15, 5, 34532, // 15, 5 + 14, 5, 7868, 14, 6, 9635, 15, 5, 12717, 15, 6, 35316, // 15, 6 + 14, 6, 7674, 14, 7, 9290, 15, 6, 12728, 15, 7, 35844, // 15, 7 + 15, 7, 12764, 15, 8, 35905, 16, 7, 7643, 16, 8, 9224, // 15, 8 + 15, 8, 12777, 15, 9, 35362, 16, 8, 7839, 16, 9, 9558, // 15, 9 + 15, 9, 12867, 15, 10, 34567, 16, 9, 8107, 16, 10, 9995, // 15,10 + 15, 10, 13007, 15, 11, 33564, 16, 10, 8438, 16, 11, 10527, // 15,11 + 15, 11, 13171, 15, 12, 32406, 16, 11, 8816, 16, 12, 11143, // 15,12 + 15, 12, 13332, 15, 13, 31146, 16, 12, 9229, 16, 13, 11829, // 15,13 + 15, 13, 13470, 15, 14, 29831, 16, 13, 9662, 16, 14, 12573, // 15,14 + 15, 14, 13569, 15, 15, 28495, 16, 14, 10104, 16, 15, 13368, // 15,15 + // angle of -1.5 degrees + -1, 0, 11440, -1, 1, 8358, 0, 0, 34212, 0, 1, 11526, // 0, 0 + -1, 1, 10780, -1, 2, 7983, 0, 1, 35506, 0, 2, 11267, // 0, 1 + -1, 2, 10158, -1, 3, 7620, 0, 2, 36764, 0, 3, 10994, // 0, 2 + -1, 3, 9585, -1, 4, 7276, 0, 3, 37951, 0, 4, 10724, // 0, 3 + -1, 4, 9072, -1, 5, 6965, 0, 4, 39026, 0, 5, 10473, // 0, 4 + -1, 5, 8632, -1, 6, 6699, 0, 5, 39940, 0, 6, 10265, // 0, 5 + -1, 6, 8278, -1, 7, 6489, 0, 6, 40646, 0, 7, 10123, // 0, 6 + -1, 7, 8018, -1, 8, 6346, 0, 7, 41106, 0, 8, 10066, // 0, 7 + 0, 8, 41072, 0, 9, 10052, 1, 8, 8052, 1, 9, 6360, // 0, 8 + 0, 9, 40618, 0, 10, 10100, 1, 9, 8316, 1, 10, 6502, // 0, 9 + 0, 10, 39918, 0, 11, 10232, 1, 10, 8676, 1, 11, 6710, // 0,10 + 0, 11, 39009, 0, 12, 10430, 1, 11, 9122, 1, 12, 6975, // 0,11 + 0, 12, 37939, 0, 13, 10670, 1, 12, 9642, 1, 13, 7285, // 0,12 + 0, 13, 36756, 0, 14, 10930, 1, 13, 10224, 1, 14, 7626, // 0,13 + 0, 14, 35502, 0, 15, 11192, 1, 14, 10855, 1, 15, 7987, // 0,14 + 0, 15, 34212, 0, 16, 11440, 1, 15, 11526, 1, 16, 8358, // 0,15 + 0, 0, 11192, 0, 1, 7987, 1, 0, 35502, 1, 1, 10855, // 1, 0 + 0, 1, 10467, 0, 2, 7579, 1, 1, 36959, 1, 2, 10531, // 1, 1 + 0, 2, 9777, 0, 3, 7177, 1, 2, 38394, 1, 3, 10188, // 1, 2 + 0, 3, 9135, 0, 4, 6792, 1, 3, 39767, 1, 4, 9842, // 1, 3 + 0, 4, 8557, 0, 5, 6440, 1, 4, 41026, 1, 5, 9513, // 1, 4 + 0, 5, 8061, 0, 6, 6137, 1, 5, 42105, 1, 6, 9233, // 1, 5 + 0, 6, 7667, 0, 7, 5900, 1, 6, 42936, 1, 7, 9033, // 1, 6 + 0, 7, 7390, 0, 8, 5745, 1, 7, 43461, 1, 8, 8940, // 1, 7 + 1, 8, 43433, 1, 9, 8929, 2, 8, 7418, 2, 9, 5756, // 1, 8 + 1, 9, 42913, 1, 10, 9014, 2, 9, 7699, 2, 10, 5910, // 1, 9 + 1, 10, 42087, 1, 11, 9206, 2, 10, 8098, 2, 11, 6145, // 1,10 + 1, 11, 41013, 1, 12, 9478, 2, 11, 8599, 2, 12, 6446, // 1,11 + 1, 12, 39759, 1, 13, 9796, 2, 12, 9184, 2, 13, 6797, // 1,12 + 1, 13, 38390, 1, 14, 10133, 2, 13, 9834, 2, 14, 7179, // 1,13 + 1, 14, 36959, 1, 15, 10467, 2, 14, 10532, 2, 15, 7578, // 1,14 + 1, 15, 35506, 1, 16, 10780, 2, 15, 11267, 2, 16, 7983, // 1,15 + 1, 0, 10930, 1, 1, 7626, 2, 0, 36756, 2, 1, 10224, // 2, 0 + 1, 1, 10133, 1, 2, 7179, 2, 1, 38390, 2, 2, 9834, // 2, 1 + 1, 2, 9366, 1, 3, 6732, 2, 2, 40025, 2, 3, 9413, // 2, 2 + 1, 3, 8641, 1, 4, 6297, 2, 3, 41618, 2, 4, 8980, // 2, 3 + 1, 4, 7981, 1, 5, 5891, 2, 4, 43105, 2, 5, 8559, // 2, 4 + 1, 5, 7411, 1, 6, 5537, 2, 5, 44399, 2, 6, 8189, // 2, 5 + 1, 6, 6961, 1, 7, 5261, 2, 6, 45401, 2, 7, 7913, // 2, 6 + 1, 7, 6658, 1, 8, 5087, 2, 7, 46017, 2, 8, 7774, // 2, 7 + 2, 8, 45995, 2, 9, 7766, 3, 8, 6680, 3, 9, 5095, // 2, 8 + 2, 9, 45383, 2, 10, 7899, 3, 9, 6986, 3, 10, 5268, // 2, 9 + 2, 10, 44386, 2, 11, 8167, 3, 10, 7440, 3, 11, 5543, // 2,10 + 2, 11, 43096, 2, 12, 8530, 3, 11, 8015, 3, 12, 5895, // 2,11 + 2, 12, 41614, 2, 13, 8941, 3, 12, 8681, 3, 13, 6300, // 2,12 + 2, 13, 40025, 2, 14, 9366, 3, 13, 9413, 3, 14, 6732, // 2,13 + 2, 14, 38394, 2, 15, 9777, 3, 14, 10188, 3, 15, 7177, // 2,14 + 2, 15, 36764, 2, 16, 10158, 3, 15, 10994, 3, 16, 7620, // 2,15 + 2, 0, 10670, 2, 1, 7285, 3, 0, 37939, 3, 1, 9642, // 3, 0 + 2, 1, 9796, 2, 2, 6797, 3, 1, 39759, 3, 2, 9184, // 3, 1 + 2, 2, 8941, 2, 3, 6299, 3, 2, 41614, 3, 3, 8682, // 3, 2 + 2, 3, 8120, 2, 4, 5804, 3, 3, 43461, 3, 4, 8151, // 3, 3 + 2, 4, 7356, 2, 5, 5330, 3, 4, 45229, 3, 5, 7621, // 3, 4 + 2, 5, 6685, 2, 6, 4906, 3, 5, 46806, 3, 6, 7139, // 3, 5 + 2, 6, 6154, 2, 7, 4572, 3, 6, 48049, 3, 7, 6761, // 3, 6 + 2, 7, 5811, 2, 8, 4366, 3, 7, 48801, 3, 8, 6558, // 3, 7 + 3, 8, 48785, 3, 9, 6552, 4, 8, 5827, 4, 9, 4372, // 3, 8 + 3, 9, 48037, 3, 10, 6750, 4, 9, 6173, 4, 10, 4576, // 3, 9 + 3, 10, 46798, 3, 11, 7121, 4, 10, 6707, 4, 11, 4910, // 3,10 + 3, 11, 45224, 3, 12, 7598, 4, 11, 7382, 4, 12, 5332, // 3,11 + 3, 12, 43461, 3, 13, 8120, 4, 12, 8151, 4, 13, 5804, // 3,12 + 3, 13, 41618, 3, 14, 8641, 4, 13, 8979, 4, 14, 6298, // 3,13 + 3, 14, 39767, 3, 15, 9135, 4, 14, 9841, 4, 15, 6793, // 3,14 + 3, 15, 37951, 3, 16, 9585, 4, 15, 10723, 4, 16, 7277, // 3,15 + 3, 0, 10430, 3, 1, 6975, 4, 0, 39009, 4, 1, 9122, // 4, 0 + 3, 1, 9478, 3, 2, 6447, 4, 1, 41013, 4, 2, 8598, // 4, 1 + 3, 2, 8530, 3, 3, 5895, 4, 2, 43096, 4, 3, 8015, // 4, 2 + 3, 3, 7598, 3, 4, 5331, 4, 3, 45224, 4, 4, 7383, // 4, 3 + 3, 4, 6708, 3, 5, 4774, 4, 4, 47328, 4, 5, 6726, // 4, 4 + 3, 5, 5901, 3, 6, 4257, 4, 5, 49279, 4, 6, 6099, // 4, 5 + 3, 6, 5248, 3, 7, 3834, 4, 6, 50873, 4, 7, 5581, // 4, 6 + 3, 7, 4835, 3, 8, 3575, 4, 7, 51842, 4, 8, 5284, // 4, 7 + 4, 8, 51832, 4, 9, 5280, 5, 8, 4846, 5, 9, 3578, // 4, 8 + 4, 9, 50865, 4, 10, 5573, 5, 9, 5261, 5, 10, 3837, // 4, 9 + 4, 10, 49275, 4, 11, 6086, 5, 10, 5917, 5, 11, 4258, // 4,10 + 4, 11, 47328, 4, 12, 6708, 5, 11, 6727, 5, 12, 4773, // 4,11 + 4, 12, 45229, 4, 13, 7356, 5, 12, 7622, 5, 13, 5329, // 4,12 + 4, 13, 43105, 4, 14, 7981, 5, 13, 8559, 5, 14, 5891, // 4,13 + 4, 14, 41026, 4, 15, 8557, 5, 14, 9513, 5, 15, 6440, // 4,14 + 4, 15, 39026, 4, 16, 9072, 5, 15, 10473, 5, 16, 6965, // 4,15 + 4, 0, 10232, 4, 1, 6710, 5, 0, 39918, 5, 1, 8676, // 5, 0 + 4, 1, 9206, 4, 2, 6145, 5, 1, 42087, 5, 2, 8098, // 5, 1 + 4, 2, 8167, 4, 3, 5543, 5, 2, 44386, 5, 3, 7440, // 5, 2 + 4, 3, 7121, 4, 4, 4909, 5, 3, 46798, 5, 4, 6708, // 5, 3 + 4, 4, 6086, 4, 5, 4258, 5, 4, 49275, 5, 5, 5917, // 5, 4 + 4, 5, 5103, 4, 6, 3621, 5, 5, 51700, 5, 6, 5112, // 5, 5 + 4, 6, 4262, 4, 7, 3064, 5, 6, 53816, 5, 7, 4394, // 5, 6 + 4, 7, 3720, 4, 8, 2708, 5, 7, 55168, 5, 8, 3940, // 5, 7 + 5, 8, 55162, 5, 9, 3938, 6, 8, 3726, 6, 9, 2710, // 5, 8 + 5, 9, 53813, 5, 10, 4388, 6, 9, 4269, 6, 10, 3066, // 5, 9 + 5, 10, 51700, 5, 11, 5103, 6, 10, 5113, 6, 11, 3620, // 5,10 + 5, 11, 49279, 5, 12, 5901, 6, 11, 6099, 6, 12, 4257, // 5,11 + 5, 12, 46806, 5, 13, 6685, 6, 12, 7138, 6, 13, 4907, // 5,12 + 5, 13, 44399, 5, 14, 7411, 6, 13, 8189, 6, 14, 5537, // 5,13 + 5, 14, 42105, 5, 15, 8061, 6, 14, 9233, 6, 15, 6137, // 5,14 + 5, 15, 39940, 5, 16, 8632, 6, 15, 10265, 6, 16, 6699, // 5,15 + 5, 0, 10100, 5, 1, 6502, 6, 0, 40618, 6, 1, 8316, // 6, 0 + 5, 1, 9014, 5, 2, 5910, 6, 1, 42913, 6, 2, 7699, // 6, 1 + 5, 2, 7899, 5, 3, 5268, 6, 2, 45383, 6, 3, 6986, // 6, 2 + 5, 3, 6750, 5, 4, 4576, 6, 3, 48037, 6, 4, 6173, // 6, 3 + 5, 4, 5573, 5, 5, 3837, 6, 4, 50865, 6, 5, 5261, // 6, 4 + 5, 5, 4388, 5, 6, 3065, 6, 5, 53813, 6, 6, 4270, // 6, 5 + 5, 6, 3271, 5, 7, 2316, 6, 6, 56673, 6, 7, 3276, // 6, 6 + 5, 7, 2462, 5, 8, 1766, 6, 7, 58775, 6, 8, 2533, // 6, 7 + 6, 8, 58773, 6, 9, 2532, 7, 8, 2464, 7, 9, 1767, // 6, 8 + 6, 9, 56673, 6, 10, 3271, 7, 9, 3275, 7, 10, 2317, // 6, 9 + 6, 10, 53816, 6, 11, 4262, 7, 10, 4394, 7, 11, 3064, // 6,10 + 6, 11, 50873, 6, 12, 5248, 7, 11, 5581, 7, 12, 3834, // 6,11 + 6, 12, 48049, 6, 13, 6154, 7, 12, 6761, 7, 13, 4572, // 6,12 + 6, 13, 45401, 6, 14, 6961, 7, 13, 7913, 7, 14, 5261, // 6,13 + 6, 14, 42936, 6, 15, 7667, 7, 14, 9032, 7, 15, 5901, // 6,14 + 6, 15, 40646, 6, 16, 8278, 7, 15, 10123, 7, 16, 6489, // 6,15 + 6, 0, 10052, 6, 1, 6360, 7, 0, 41072, 7, 1, 8052, // 7, 0 + 6, 1, 8929, 6, 2, 5756, 7, 1, 43433, 7, 2, 7418, // 7, 1 + 6, 2, 7766, 6, 3, 5095, 7, 2, 45995, 7, 3, 6680, // 7, 2 + 6, 3, 6552, 6, 4, 4372, 7, 3, 48785, 7, 4, 5827, // 7, 3 + 6, 4, 5280, 6, 5, 3579, 7, 4, 51832, 7, 5, 4845, // 7, 4 + 6, 5, 3938, 6, 6, 2710, 7, 5, 55162, 7, 6, 3726, // 7, 5 + 6, 6, 2532, 6, 7, 1767, 7, 6, 58773, 7, 7, 2464, // 7, 6 + 6, 7, 1170, 6, 8, 827, 7, 7, 62369, 7, 8, 1170, // 7, 7 + 7, 8, 62369, 7, 9, 1170, 8, 8, 1170, 8, 9, 827, // 7, 8 + 7, 9, 58775, 7, 10, 2462, 8, 9, 2533, 8, 10, 1766, // 7, 9 + 7, 10, 55168, 7, 11, 3720, 8, 10, 3940, 8, 11, 2708, // 7,10 + 7, 11, 51842, 7, 12, 4835, 8, 11, 5283, 8, 12, 3576, // 7,11 + 7, 12, 48801, 7, 13, 5811, 8, 12, 6558, 8, 13, 4366, // 7,12 + 7, 13, 46017, 7, 14, 6658, 8, 13, 7773, 8, 14, 5088, // 7,13 + 7, 14, 43461, 7, 15, 7390, 8, 14, 8939, 8, 15, 5746, // 7,14 + 7, 15, 41106, 7, 16, 8018, 8, 15, 10066, 8, 16, 6346, // 7,15 + 7, -1, 6346, 7, 0, 10066, 8, -1, 8018, 8, 0, 41106, // 8, 0 + 7, 0, 5745, 7, 1, 8939, 8, 0, 7390, 8, 1, 43462, // 8, 1 + 7, 1, 5087, 7, 2, 7773, 8, 1, 6658, 8, 2, 46018, // 8, 2 + 7, 2, 4366, 7, 3, 6558, 8, 2, 5811, 8, 3, 48801, // 8, 3 + 7, 3, 3575, 7, 4, 5283, 8, 3, 4835, 8, 4, 51843, // 8, 4 + 7, 4, 2708, 7, 5, 3940, 8, 4, 3720, 8, 5, 55168, // 8, 5 + 7, 5, 1766, 7, 6, 2533, 8, 5, 2462, 8, 6, 58775, // 8, 6 + 7, 6, 827, 7, 7, 1170, 8, 6, 1170, 8, 7, 62369, // 8, 7 + 8, 7, 1170, 8, 8, 62369, 9, 7, 827, 9, 8, 1170, // 8, 8 + 8, 8, 2464, 8, 9, 58773, 9, 8, 1767, 9, 9, 2532, // 8, 9 + 8, 9, 3726, 8, 10, 55162, 9, 9, 2710, 9, 10, 3938, // 8,10 + 8, 10, 4846, 8, 11, 51832, 9, 10, 3579, 9, 11, 5279, // 8,11 + 8, 11, 5827, 8, 12, 48785, 9, 11, 4372, 9, 12, 6552, // 8,12 + 8, 12, 6680, 8, 13, 45995, 9, 12, 5095, 9, 13, 7766, // 8,13 + 8, 13, 7418, 8, 14, 43433, 9, 13, 5756, 9, 14, 8929, // 8,14 + 8, 14, 8052, 8, 15, 41072, 9, 14, 6360, 9, 15, 10052, // 8,15 + 8, -1, 6489, 8, 0, 10123, 9, -1, 8278, 9, 0, 40646, // 9, 0 + 8, 0, 5900, 8, 1, 9032, 9, 0, 7667, 9, 1, 42937, // 9, 1 + 8, 1, 5261, 8, 2, 7913, 9, 1, 6961, 9, 2, 45401, // 9, 2 + 8, 2, 4572, 8, 3, 6761, 9, 2, 6154, 9, 3, 48049, // 9, 3 + 8, 3, 3834, 8, 4, 5581, 9, 3, 5248, 9, 4, 50873, // 9, 4 + 8, 4, 3064, 8, 5, 4394, 9, 4, 4262, 9, 5, 53816, // 9, 5 + 8, 5, 2316, 8, 6, 3275, 9, 5, 3271, 9, 6, 56674, // 9, 6 + 8, 6, 1767, 8, 7, 2464, 9, 6, 2532, 9, 7, 58773, // 9, 7 + 9, 7, 2533, 9, 8, 58775, 10, 7, 1766, 10, 8, 2462, // 9, 8 + 9, 8, 3275, 9, 9, 56673, 10, 8, 2316, 10, 9, 3272, // 9, 9 + 9, 9, 4269, 9, 10, 53813, 10, 9, 3065, 10, 10, 4389, // 9,10 + 9, 10, 5261, 9, 11, 50865, 10, 10, 3837, 10, 11, 5573, // 9,11 + 9, 11, 6173, 9, 12, 48037, 10, 11, 4576, 10, 12, 6750, // 9,12 + 9, 12, 6986, 9, 13, 45383, 10, 12, 5268, 10, 13, 7899, // 9,13 + 9, 13, 7699, 9, 14, 42913, 10, 13, 5910, 10, 14, 9014, // 9,14 + 9, 14, 8316, 9, 15, 40618, 10, 14, 6502, 10, 15, 10100, // 9,15 + 9, -1, 6699, 9, 0, 10265, 10, -1, 8632, 10, 0, 39940, // 10, 0 + 9, 0, 6137, 9, 1, 9233, 10, 0, 8061, 10, 1, 42105, // 10, 1 + 9, 1, 5537, 9, 2, 8189, 10, 1, 7411, 10, 2, 44399, // 10, 2 + 9, 2, 4906, 9, 3, 7138, 10, 2, 6685, 10, 3, 46807, // 10, 3 + 9, 3, 4257, 9, 4, 6099, 10, 3, 5901, 10, 4, 49279, // 10, 4 + 9, 4, 3621, 9, 5, 5113, 10, 4, 5103, 10, 5, 51699, // 10, 5 + 9, 5, 3065, 9, 6, 4269, 10, 5, 4388, 10, 6, 53814, // 10, 6 + 9, 6, 2710, 9, 7, 3726, 10, 6, 3938, 10, 7, 55162, // 10, 7 + 10, 7, 3940, 10, 8, 55168, 11, 7, 2708, 11, 8, 3720, // 10, 8 + 10, 8, 4394, 10, 9, 53816, 11, 8, 3064, 11, 9, 4262, // 10, 9 + 10, 9, 5113, 10, 10, 51700, 11, 9, 3621, 11, 10, 5102, // 10,10 + 10, 10, 5917, 10, 11, 49275, 11, 10, 4258, 11, 11, 6086, // 10,11 + 10, 11, 6707, 10, 12, 46798, 11, 11, 4909, 11, 12, 7122, // 10,12 + 10, 12, 7440, 10, 13, 44386, 11, 12, 5543, 11, 13, 8167, // 10,13 + 10, 13, 8098, 10, 14, 42087, 11, 13, 6145, 11, 14, 9206, // 10,14 + 10, 14, 8676, 10, 15, 39918, 11, 14, 6710, 11, 15, 10232, // 10,15 + 10, -1, 6965, 10, 0, 10473, 11, -1, 9072, 11, 0, 39026, // 11, 0 + 10, 0, 6440, 10, 1, 9513, 11, 0, 8557, 11, 1, 41026, // 11, 1 + 10, 1, 5891, 10, 2, 8559, 11, 1, 7981, 11, 2, 43105, // 11, 2 + 10, 2, 5330, 10, 3, 7622, 11, 2, 7356, 11, 3, 45228, // 11, 3 + 10, 3, 4774, 10, 4, 6727, 11, 3, 6708, 11, 4, 47327, // 11, 4 + 10, 4, 4258, 10, 5, 5917, 11, 4, 6086, 11, 5, 49275, // 11, 5 + 10, 5, 3837, 10, 6, 5261, 11, 5, 5573, 11, 6, 50865, // 11, 6 + 10, 6, 3579, 10, 7, 4846, 11, 6, 5280, 11, 7, 51831, // 11, 7 + 11, 7, 5283, 11, 8, 51842, 12, 7, 3575, 12, 8, 4836, // 11, 8 + 11, 8, 5581, 11, 9, 50873, 12, 8, 3834, 12, 9, 5248, // 11, 9 + 11, 9, 6099, 11, 10, 49279, 12, 9, 4257, 12, 10, 5901, // 11,10 + 11, 10, 6727, 11, 11, 47328, 12, 10, 4774, 12, 11, 6707, // 11,11 + 11, 11, 7382, 11, 12, 45224, 12, 11, 5331, 12, 12, 7599, // 11,12 + 11, 12, 8015, 11, 13, 43096, 12, 12, 5895, 12, 13, 8530, // 11,13 + 11, 13, 8599, 11, 14, 41013, 12, 13, 6447, 12, 14, 9477, // 11,14 + 11, 14, 9122, 11, 15, 39009, 12, 14, 6975, 12, 15, 10430, // 11,15 + 11, -1, 7276, 11, 0, 10723, 12, -1, 9585, 12, 0, 37952, // 12, 0 + 11, 0, 6792, 11, 1, 9841, 12, 0, 9135, 12, 1, 39768, // 12, 1 + 11, 1, 6297, 11, 2, 8979, 12, 1, 8641, 12, 2, 41619, // 12, 2 + 11, 2, 5804, 11, 3, 8151, 12, 2, 8120, 12, 3, 43461, // 12, 3 + 11, 3, 5331, 11, 4, 7382, 12, 3, 7598, 12, 4, 45225, // 12, 4 + 11, 4, 4909, 11, 5, 6707, 12, 4, 7121, 12, 5, 46799, // 12, 5 + 11, 5, 4576, 11, 6, 6173, 12, 5, 6750, 12, 6, 48037, // 12, 6 + 11, 6, 4372, 11, 7, 5827, 12, 6, 6552, 12, 7, 48785, // 12, 7 + 12, 7, 6558, 12, 8, 48801, 13, 7, 4366, 13, 8, 5811, // 12, 8 + 12, 8, 6761, 12, 9, 48049, 13, 8, 4572, 13, 9, 6154, // 12, 9 + 12, 9, 7138, 12, 10, 46806, 13, 9, 4906, 13, 10, 6686, // 12,10 + 12, 10, 7622, 12, 11, 45229, 13, 10, 5330, 13, 11, 7355, // 12,11 + 12, 11, 8151, 12, 12, 43461, 13, 11, 5804, 13, 12, 8120, // 12,12 + 12, 12, 8681, 12, 13, 41614, 13, 12, 6299, 13, 13, 8942, // 12,13 + 12, 13, 9184, 12, 14, 39759, 13, 13, 6797, 13, 14, 9796, // 12,14 + 12, 14, 9642, 12, 15, 37939, 13, 14, 7285, 13, 15, 10670, // 12,15 + 12, -1, 7620, 12, 0, 10994, 13, -1, 10158, 13, 0, 36764, // 13, 0 + 12, 0, 7177, 12, 1, 10188, 13, 0, 9777, 13, 1, 38394, // 13, 1 + 12, 1, 6732, 12, 2, 9413, 13, 1, 9366, 13, 2, 40025, // 13, 2 + 12, 2, 6299, 12, 3, 8681, 13, 2, 8941, 13, 3, 41615, // 13, 3 + 12, 3, 5895, 12, 4, 8015, 13, 3, 8530, 13, 4, 43096, // 13, 4 + 12, 4, 5543, 12, 5, 7440, 13, 4, 8167, 13, 5, 44386, // 13, 5 + 12, 5, 5268, 12, 6, 6986, 13, 5, 7899, 13, 6, 45383, // 13, 6 + 12, 6, 5095, 12, 7, 6680, 13, 6, 7766, 13, 7, 45995, // 13, 7 + 13, 7, 7773, 13, 8, 46017, 14, 7, 5087, 14, 8, 6659, // 13, 8 + 13, 8, 7913, 13, 9, 45401, 14, 8, 5261, 14, 9, 6961, // 13, 9 + 13, 9, 8189, 13, 10, 44399, 14, 9, 5537, 14, 10, 7411, // 13,10 + 13, 10, 8559, 13, 11, 43105, 14, 10, 5891, 14, 11, 7981, // 13,11 + 13, 11, 8979, 13, 12, 41618, 14, 11, 6297, 14, 12, 8642, // 13,12 + 13, 12, 9413, 13, 13, 40025, 14, 12, 6732, 14, 13, 9366, // 13,13 + 13, 13, 9834, 13, 14, 38390, 14, 13, 7179, 14, 14, 10133, // 13,14 + 13, 14, 10224, 13, 15, 36756, 14, 14, 7626, 14, 15, 10930, // 13,15 + 13, -1, 7983, 13, 0, 11267, 14, -1, 10780, 14, 0, 35506, // 14, 0 + 13, 0, 7579, 13, 1, 10532, 14, 0, 10467, 14, 1, 36958, // 14, 1 + 13, 1, 7179, 13, 2, 9834, 14, 1, 10133, 14, 2, 38390, // 14, 2 + 13, 2, 6797, 13, 3, 9184, 14, 2, 9796, 14, 3, 39759, // 14, 3 + 13, 3, 6447, 13, 4, 8599, 14, 3, 9478, 14, 4, 41012, // 14, 4 + 13, 4, 6145, 13, 5, 8098, 14, 4, 9206, 14, 5, 42087, // 14, 5 + 13, 5, 5910, 13, 6, 7699, 14, 5, 9014, 14, 6, 42913, // 14, 6 + 13, 6, 5756, 13, 7, 7418, 14, 6, 8929, 14, 7, 43433, // 14, 7 + 14, 7, 8939, 14, 8, 43461, 15, 7, 5745, 15, 8, 7391, // 14, 8 + 14, 8, 9032, 14, 9, 42936, 15, 8, 5900, 15, 9, 7668, // 14, 9 + 14, 9, 9233, 14, 10, 42105, 15, 9, 6137, 15, 10, 8061, // 14,10 + 14, 10, 9513, 14, 11, 41026, 15, 10, 6440, 15, 11, 8557, // 14,11 + 14, 11, 9841, 14, 12, 39767, 15, 11, 6792, 15, 12, 9136, // 14,12 + 14, 12, 10188, 14, 13, 38394, 15, 12, 7177, 15, 13, 9777, // 14,13 + 14, 13, 10532, 14, 14, 36959, 15, 13, 7579, 15, 14, 10466, // 14,14 + 14, 14, 10855, 14, 15, 35502, 15, 14, 7987, 15, 15, 11192, // 14,15 + 14, -1, 8358, 14, 0, 11526, 15, -1, 11440, 15, 0, 34212, // 15, 0 + 14, 0, 7987, 14, 1, 10855, 15, 0, 11192, 15, 1, 35502, // 15, 1 + 14, 1, 7626, 14, 2, 10224, 15, 1, 10930, 15, 2, 36756, // 15, 2 + 14, 2, 7285, 14, 3, 9642, 15, 2, 10670, 15, 3, 37939, // 15, 3 + 14, 3, 6975, 14, 4, 9122, 15, 3, 10430, 15, 4, 39009, // 15, 4 + 14, 4, 6710, 14, 5, 8676, 15, 4, 10232, 15, 5, 39918, // 15, 5 + 14, 5, 6502, 14, 6, 8316, 15, 5, 10100, 15, 6, 40618, // 15, 6 + 14, 6, 6360, 14, 7, 8052, 15, 6, 10052, 15, 7, 41072, // 15, 7 + 15, 7, 10066, 15, 8, 41106, 16, 7, 6346, 16, 8, 8018, // 15, 8 + 15, 8, 10123, 15, 9, 40646, 16, 8, 6489, 16, 9, 8278, // 15, 9 + 15, 9, 10265, 15, 10, 39940, 16, 9, 6699, 16, 10, 8632, // 15,10 + 15, 10, 10473, 15, 11, 39026, 16, 10, 6965, 16, 11, 9072, // 15,11 + 15, 11, 10723, 15, 12, 37951, 16, 11, 7276, 16, 12, 9586, // 15,12 + 15, 12, 10994, 15, 13, 36764, 16, 12, 7620, 16, 13, 10158, // 15,13 + 15, 13, 11267, 15, 14, 35506, 16, 13, 7983, 16, 14, 10780, // 15,14 + 15, 14, 11526, 15, 15, 34212, 16, 14, 8358, 16, 15, 11440, // 15,15 + // angle of -1.0 degrees + -1, 0, 8769, -1, 1, 6280, 0, 0, 41693, 0, 1, 8794, // 0, 0 + -1, 1, 8265, -1, 2, 5974, 0, 1, 42823, 0, 2, 8474, // 0, 1 + -1, 2, 7791, -1, 3, 5682, 0, 2, 43904, 0, 3, 8159, // 0, 2 + -1, 3, 7356, -1, 4, 5410, 0, 3, 44907, 0, 4, 7863, // 0, 3 + -1, 4, 6970, -1, 5, 5169, 0, 4, 45799, 0, 5, 7598, // 0, 4 + -1, 5, 6644, -1, 6, 4967, 0, 5, 46541, 0, 6, 7384, // 0, 5 + -1, 6, 6391, -1, 7, 4814, 0, 6, 47098, 0, 7, 7233, // 0, 6 + -1, 7, 6217, -1, 8, 4718, 0, 7, 47440, 0, 8, 7161, // 0, 7 + 0, 8, 47426, 0, 9, 7158, 1, 8, 6230, 1, 9, 4722, // 0, 8 + 0, 9, 47086, 0, 10, 7227, 1, 9, 6405, 1, 10, 4818, // 0, 9 + 0, 10, 46532, 0, 11, 7374, 1, 10, 6659, 1, 11, 4971, // 0,10 + 0, 11, 45791, 0, 12, 7587, 1, 11, 6986, 1, 12, 5172, // 0,11 + 0, 12, 44901, 0, 13, 7848, 1, 12, 7374, 1, 13, 5413, // 0,12 + 0, 13, 43900, 0, 14, 8141, 1, 13, 7812, 1, 14, 5683, // 0,13 + 0, 14, 42821, 0, 15, 8452, 1, 14, 8288, 1, 15, 5975, // 0,14 + 0, 15, 41693, 0, 16, 8769, 1, 15, 8795, 1, 16, 6279, // 0,15 + 0, 0, 8452, 0, 1, 5975, 1, 0, 42821, 1, 1, 8288, // 1, 0 + 0, 1, 7901, 0, 2, 5640, 1, 1, 44074, 1, 2, 7921, // 1, 1 + 0, 2, 7378, 0, 3, 5315, 1, 2, 45288, 1, 3, 7555, // 1, 2 + 0, 3, 6892, 0, 4, 5009, 1, 3, 46430, 1, 4, 7205, // 1, 3 + 0, 4, 6458, 0, 5, 4734, 1, 4, 47458, 1, 5, 6886, // 1, 4 + 0, 5, 6092, 0, 6, 4502, 1, 5, 48322, 1, 6, 6620, // 1, 5 + 0, 6, 5809, 0, 7, 4327, 1, 6, 48969, 1, 7, 6431, // 1, 6 + 0, 7, 5623, 0, 8, 4221, 1, 7, 49358, 1, 8, 6334, // 1, 7 + 1, 8, 49347, 1, 9, 6332, 2, 8, 5633, 2, 9, 4224, // 1, 8 + 1, 9, 48960, 1, 10, 6425, 2, 9, 5820, 2, 10, 4331, // 1, 9 + 1, 10, 48314, 1, 11, 6613, 2, 10, 6104, 2, 11, 4505, // 1,10 + 1, 11, 47453, 1, 12, 6875, 2, 11, 6472, 2, 12, 4736, // 1,11 + 1, 12, 46427, 1, 13, 7191, 2, 12, 6908, 2, 13, 5010, // 1,12 + 1, 13, 45286, 1, 14, 7539, 2, 13, 7395, 2, 14, 5316, // 1,13 + 1, 14, 44074, 1, 15, 7901, 2, 14, 7921, 2, 15, 5640, // 1,14 + 1, 15, 42823, 1, 16, 8265, 2, 15, 8474, 2, 16, 5974, // 1,15 + 1, 0, 8141, 1, 1, 5684, 2, 0, 43900, 2, 1, 7811, // 2, 0 + 1, 1, 7539, 1, 2, 5316, 2, 1, 45286, 2, 2, 7395, // 2, 1 + 1, 2, 6959, 1, 3, 4954, 2, 2, 46650, 2, 3, 6973, // 2, 2 + 1, 3, 6414, 1, 4, 4607, 2, 3, 47955, 2, 4, 6560, // 2, 3 + 1, 4, 5920, 1, 5, 4290, 2, 4, 49150, 2, 5, 6176, // 2, 4 + 1, 5, 5499, 1, 6, 4019, 2, 5, 50171, 2, 6, 5847, // 2, 5 + 1, 6, 5175, 1, 7, 3813, 2, 6, 50942, 2, 7, 5606, // 2, 6 + 1, 7, 4970, 1, 8, 3691, 2, 7, 51395, 2, 8, 5480, // 2, 7 + 2, 8, 51387, 2, 9, 5478, 3, 8, 4978, 3, 9, 3693, // 2, 8 + 2, 9, 50935, 2, 10, 5602, 3, 9, 5184, 3, 10, 3815, // 2, 9 + 2, 10, 50165, 2, 11, 5842, 3, 10, 5508, 3, 11, 4021, // 2,10 + 2, 11, 49147, 2, 12, 6168, 3, 11, 5930, 3, 12, 4291, // 2,11 + 2, 12, 47953, 2, 13, 6549, 3, 12, 6426, 3, 13, 4608, // 2,12 + 2, 13, 46650, 2, 14, 6959, 3, 13, 6973, 3, 14, 4954, // 2,13 + 2, 14, 45288, 2, 15, 7378, 3, 14, 7555, 3, 15, 5315, // 2,14 + 2, 15, 43904, 2, 16, 7791, 3, 15, 8159, 3, 16, 5682, // 2,15 + 2, 0, 7848, 2, 1, 5413, 3, 0, 44901, 3, 1, 7374, // 3, 0 + 2, 1, 7191, 2, 2, 5011, 3, 1, 46427, 3, 2, 6907, // 3, 1 + 2, 2, 6549, 2, 3, 4608, 3, 2, 47953, 3, 3, 6426, // 3, 2 + 2, 3, 5934, 2, 4, 4214, 3, 3, 49445, 3, 4, 5943, // 3, 3 + 2, 4, 5365, 2, 5, 3845, 3, 4, 50844, 3, 5, 5482, // 3, 4 + 2, 5, 4872, 2, 6, 3522, 3, 5, 52069, 3, 6, 5073, // 3, 5 + 2, 6, 4489, 2, 7, 3273, 3, 6, 53012, 3, 7, 4762, // 3, 6 + 2, 7, 4254, 2, 8, 3126, 3, 7, 53562, 3, 8, 4594, // 3, 7 + 3, 8, 53557, 3, 9, 4592, 4, 8, 4259, 4, 9, 3128, // 3, 8 + 3, 9, 53008, 3, 10, 4759, 4, 9, 4495, 4, 10, 3274, // 3, 9 + 3, 10, 52066, 3, 11, 5069, 4, 10, 4879, 4, 11, 3522, // 3,10 + 3, 11, 50843, 3, 12, 5474, 4, 11, 5373, 4, 12, 3846, // 3,11 + 3, 12, 49445, 3, 13, 5934, 4, 12, 5943, 4, 13, 4214, // 3,12 + 3, 13, 47955, 3, 14, 6414, 4, 13, 6560, 4, 14, 4607, // 3,13 + 3, 14, 46430, 3, 15, 6892, 4, 14, 7204, 4, 15, 5010, // 3,14 + 3, 15, 44907, 3, 16, 7356, 4, 15, 7863, 4, 16, 5410, // 3,15 + 3, 0, 7587, 3, 1, 5172, 4, 0, 45791, 4, 1, 6986, // 4, 0 + 3, 1, 6875, 3, 2, 4736, 4, 1, 47453, 4, 2, 6472, // 4, 1 + 3, 2, 6168, 3, 3, 4291, 4, 2, 49147, 4, 3, 5930, // 4, 2 + 3, 3, 5474, 3, 4, 3846, 4, 3, 50843, 4, 4, 5373, // 4, 3 + 3, 4, 4816, 3, 5, 3415, 4, 4, 52484, 4, 5, 4821, // 4, 4 + 3, 5, 4226, 3, 6, 3023, 4, 5, 53975, 4, 6, 4312, // 4, 5 + 3, 6, 3755, 3, 7, 2710, 4, 6, 55166, 4, 7, 3905, // 4, 6 + 3, 7, 3469, 3, 8, 2524, 4, 7, 55870, 4, 8, 3673, // 4, 7 + 4, 8, 55867, 4, 9, 3671, 5, 8, 3473, 5, 9, 2525, // 4, 8 + 4, 9, 55164, 4, 10, 3902, 5, 9, 3759, 5, 10, 2711, // 4, 9 + 4, 10, 53973, 4, 11, 4309, 5, 10, 4230, 5, 11, 3024, // 4,10 + 4, 11, 52484, 4, 12, 4816, 5, 11, 4822, 5, 12, 3414, // 4,11 + 4, 12, 50844, 4, 13, 5365, 5, 12, 5481, 5, 13, 3846, // 4,12 + 4, 13, 49150, 4, 14, 5920, 5, 13, 6176, 5, 14, 4290, // 4,13 + 4, 14, 47458, 4, 15, 6458, 5, 14, 6886, 5, 15, 4734, // 4,14 + 4, 15, 45799, 4, 16, 6970, 5, 15, 7599, 5, 16, 5168, // 4,15 + 4, 0, 7374, 4, 1, 4971, 5, 0, 46532, 5, 1, 6659, // 5, 0 + 4, 1, 6613, 4, 2, 4505, 5, 1, 48314, 5, 2, 6104, // 5, 1 + 4, 2, 5842, 4, 3, 4020, 5, 2, 50165, 5, 3, 5509, // 5, 2 + 4, 3, 5069, 4, 4, 3523, 5, 3, 52066, 5, 4, 4878, // 5, 3 + 4, 4, 4309, 4, 5, 3023, 5, 4, 53973, 5, 5, 4231, // 5, 4 + 4, 5, 3595, 4, 6, 2546, 5, 5, 55798, 5, 6, 3597, // 5, 5 + 4, 6, 2993, 4, 7, 2138, 5, 6, 57354, 5, 7, 3051, // 5, 6 + 4, 7, 2615, 4, 8, 1884, 5, 7, 58324, 5, 8, 2713, // 5, 7 + 5, 8, 58322, 5, 9, 2713, 6, 8, 2616, 6, 9, 1885, // 5, 8 + 5, 9, 57353, 5, 10, 3050, 6, 9, 2995, 6, 10, 2138, // 5, 9 + 5, 10, 55798, 5, 11, 3595, 6, 10, 3598, 6, 11, 2545, // 5,10 + 5, 11, 53975, 5, 12, 4226, 6, 11, 4313, 6, 12, 3022, // 5,11 + 5, 12, 52069, 5, 13, 4872, 6, 12, 5073, 6, 13, 3522, // 5,12 + 5, 13, 50171, 5, 14, 5499, 6, 13, 5848, 6, 14, 4018, // 5,13 + 5, 14, 48322, 5, 15, 6092, 6, 14, 6620, 6, 15, 4502, // 5,14 + 5, 15, 46541, 5, 16, 6644, 6, 15, 7383, 6, 16, 4968, // 5,15 + 5, 0, 7227, 5, 1, 4818, 6, 0, 47086, 6, 1, 6405, // 6, 0 + 5, 1, 6425, 5, 2, 4330, 6, 1, 48960, 6, 2, 5821, // 6, 1 + 5, 2, 5602, 5, 3, 3815, 6, 2, 50935, 6, 3, 5184, // 6, 2 + 5, 3, 4759, 5, 4, 3274, 6, 3, 53008, 6, 4, 4495, // 6, 3 + 5, 4, 3902, 5, 5, 2711, 6, 4, 55164, 6, 5, 3759, // 6, 4 + 5, 5, 3050, 5, 6, 2138, 6, 5, 57353, 6, 6, 2995, // 6, 5 + 5, 6, 2258, 5, 7, 1597, 6, 6, 59422, 6, 7, 2259, // 6, 6 + 5, 7, 1695, 5, 8, 1209, 6, 7, 60906, 6, 8, 1726, // 6, 7 + 6, 8, 60905, 6, 9, 1726, 7, 8, 1695, 7, 9, 1210, // 6, 8 + 6, 9, 59422, 6, 10, 2258, 7, 9, 2259, 7, 10, 1597, // 6, 9 + 6, 10, 57354, 6, 11, 2993, 7, 10, 3051, 7, 11, 2138, // 6,10 + 6, 11, 55166, 6, 12, 3755, 7, 11, 3904, 7, 12, 2711, // 6,11 + 6, 12, 53012, 6, 13, 4489, 7, 12, 4762, 7, 13, 3273, // 6,12 + 6, 13, 50942, 6, 14, 5175, 7, 13, 5606, 7, 14, 3813, // 6,13 + 6, 14, 48969, 6, 15, 5809, 7, 14, 6430, 7, 15, 4328, // 6,14 + 6, 15, 47098, 6, 16, 6391, 7, 15, 7233, 7, 16, 4814, // 6,15 + 6, 0, 7158, 6, 1, 4722, 7, 0, 47426, 7, 1, 6230, // 7, 0 + 6, 1, 6332, 6, 2, 4224, 7, 1, 49347, 7, 2, 5633, // 7, 1 + 6, 2, 5478, 6, 3, 3693, 7, 2, 51387, 7, 3, 4978, // 7, 2 + 6, 3, 4592, 6, 4, 3128, 7, 3, 53557, 7, 4, 4259, // 7, 3 + 6, 4, 3671, 6, 5, 2525, 7, 4, 55867, 7, 5, 3473, // 7, 4 + 6, 5, 2713, 6, 6, 1884, 7, 5, 58322, 7, 6, 2617, // 7, 5 + 6, 6, 1726, 6, 7, 1210, 7, 6, 60905, 7, 7, 1695, // 7, 6 + 6, 7, 789, 6, 8, 558, 7, 7, 63399, 7, 8, 790, // 7, 7 + 7, 8, 63399, 7, 9, 789, 8, 8, 789, 8, 9, 559, // 7, 8 + 7, 9, 60906, 7, 10, 1695, 8, 9, 1726, 8, 10, 1209, // 7, 9 + 7, 10, 58324, 7, 11, 2615, 8, 10, 2714, 8, 11, 1883, // 7,10 + 7, 11, 55870, 7, 12, 3469, 8, 11, 3672, 8, 12, 2525, // 7,11 + 7, 12, 53562, 7, 13, 4254, 8, 12, 4594, 8, 13, 3126, // 7,12 + 7, 13, 51395, 7, 14, 4970, 8, 13, 5480, 8, 14, 3691, // 7,13 + 7, 14, 49358, 7, 15, 5623, 8, 14, 6335, 8, 15, 4220, // 7,14 + 7, 15, 47440, 7, 16, 6217, 8, 15, 7161, 8, 16, 4718, // 7,15 + 7, -1, 4718, 7, 0, 7161, 8, -1, 6217, 8, 0, 47440, // 8, 0 + 7, 0, 4221, 7, 1, 6335, 8, 0, 5623, 8, 1, 49357, // 8, 1 + 7, 1, 3691, 7, 2, 5480, 8, 1, 4970, 8, 2, 51395, // 8, 2 + 7, 2, 3126, 7, 3, 4594, 8, 2, 4254, 8, 3, 53562, // 8, 3 + 7, 3, 2524, 7, 4, 3672, 8, 3, 3469, 8, 4, 55871, // 8, 4 + 7, 4, 1884, 7, 5, 2714, 8, 4, 2615, 8, 5, 58323, // 8, 5 + 7, 5, 1209, 7, 6, 1726, 8, 5, 1695, 8, 6, 60906, // 8, 6 + 7, 6, 558, 7, 7, 789, 8, 6, 789, 8, 7, 63400, // 8, 7 + 8, 7, 789, 8, 8, 63399, 9, 7, 558, 9, 8, 790, // 8, 8 + 8, 8, 1695, 8, 9, 60905, 9, 8, 1210, 9, 9, 1726, // 8, 9 + 8, 9, 2616, 8, 10, 58322, 9, 9, 1884, 9, 10, 2714, // 8,10 + 8, 10, 3473, 8, 11, 55867, 9, 10, 2525, 9, 11, 3671, // 8,11 + 8, 11, 4259, 8, 12, 53557, 9, 11, 3128, 9, 12, 4592, // 8,12 + 8, 12, 4978, 8, 13, 51387, 9, 12, 3693, 9, 13, 5478, // 8,13 + 8, 13, 5633, 8, 14, 49347, 9, 13, 4224, 9, 14, 6332, // 8,14 + 8, 14, 6230, 8, 15, 47426, 9, 14, 4722, 9, 15, 7158, // 8,15 + 8, -1, 4814, 8, 0, 7233, 9, -1, 6391, 9, 0, 47098, // 9, 0 + 8, 0, 4327, 8, 1, 6430, 9, 0, 5809, 9, 1, 48970, // 9, 1 + 8, 1, 3813, 8, 2, 5606, 9, 1, 5175, 9, 2, 50942, // 9, 2 + 8, 2, 3273, 8, 3, 4762, 9, 2, 4489, 9, 3, 53012, // 9, 3 + 8, 3, 2710, 8, 4, 3904, 9, 3, 3755, 9, 4, 55167, // 9, 4 + 8, 4, 2138, 8, 5, 3051, 9, 4, 2993, 9, 5, 57354, // 9, 5 + 8, 5, 1597, 8, 6, 2259, 9, 5, 2258, 9, 6, 59422, // 9, 6 + 8, 6, 1210, 8, 7, 1695, 9, 6, 1726, 9, 7, 60905, // 9, 7 + 9, 7, 1726, 9, 8, 60906, 10, 7, 1209, 10, 8, 1695, // 9, 8 + 9, 8, 2259, 9, 9, 59422, 10, 8, 1597, 10, 9, 2258, // 9, 9 + 9, 9, 2995, 9, 10, 57353, 10, 9, 2138, 10, 10, 3050, // 9,10 + 9, 10, 3759, 9, 11, 55164, 10, 10, 2711, 10, 11, 3902, // 9,11 + 9, 11, 4495, 9, 12, 53008, 10, 11, 3274, 10, 12, 4759, // 9,12 + 9, 12, 5184, 9, 13, 50935, 10, 12, 3815, 10, 13, 5602, // 9,13 + 9, 13, 5820, 9, 14, 48960, 10, 13, 4330, 10, 14, 6426, // 9,14 + 9, 14, 6405, 9, 15, 47086, 10, 14, 4818, 10, 15, 7227, // 9,15 + 9, -1, 4967, 9, 0, 7383, 10, -1, 6644, 10, 0, 46542, // 10, 0 + 9, 0, 4502, 9, 1, 6620, 10, 0, 6092, 10, 1, 48322, // 10, 1 + 9, 1, 4019, 9, 2, 5848, 10, 1, 5499, 10, 2, 50170, // 10, 2 + 9, 2, 3522, 9, 3, 5073, 10, 2, 4872, 10, 3, 52069, // 10, 3 + 9, 3, 3023, 9, 4, 4313, 10, 3, 4226, 10, 4, 53974, // 10, 4 + 9, 4, 2546, 9, 5, 3598, 10, 4, 3595, 10, 5, 55797, // 10, 5 + 9, 5, 2138, 9, 6, 2995, 10, 5, 3050, 10, 6, 57353, // 10, 6 + 9, 6, 1884, 9, 7, 2616, 10, 6, 2713, 10, 7, 58323, // 10, 7 + 10, 7, 2714, 10, 8, 58324, 11, 7, 1884, 11, 8, 2614, // 10, 8 + 10, 8, 3051, 10, 9, 57354, 11, 8, 2138, 11, 9, 2993, // 10, 9 + 10, 9, 3598, 10, 10, 55798, 11, 9, 2546, 11, 10, 3594, // 10,10 + 10, 10, 4230, 10, 11, 53973, 11, 10, 3023, 11, 11, 4310, // 10,11 + 10, 11, 4879, 10, 12, 52066, 11, 11, 3523, 11, 12, 5068, // 10,12 + 10, 12, 5508, 10, 13, 50165, 11, 12, 4020, 11, 13, 5843, // 10,13 + 10, 13, 6104, 10, 14, 48314, 11, 13, 4505, 11, 14, 6613, // 10,14 + 10, 14, 6659, 10, 15, 46532, 11, 14, 4971, 11, 15, 7374, // 10,15 + 10, -1, 5169, 10, 0, 7599, 11, -1, 6970, 11, 0, 45798, // 11, 0 + 10, 0, 4734, 10, 1, 6886, 11, 0, 6458, 11, 1, 47458, // 11, 1 + 10, 1, 4290, 10, 2, 6176, 11, 1, 5920, 11, 2, 49150, // 11, 2 + 10, 2, 3845, 10, 3, 5481, 11, 2, 5365, 11, 3, 50845, // 11, 3 + 10, 3, 3415, 10, 4, 4822, 11, 3, 4816, 11, 4, 52483, // 11, 4 + 10, 4, 3023, 10, 5, 4230, 11, 4, 4309, 11, 5, 53974, // 11, 5 + 10, 5, 2711, 10, 6, 3759, 11, 5, 3902, 11, 6, 55164, // 11, 6 + 10, 6, 2525, 10, 7, 3473, 11, 6, 3671, 11, 7, 55867, // 11, 7 + 11, 7, 3672, 11, 8, 55870, 12, 7, 2524, 12, 8, 3470, // 11, 8 + 11, 8, 3904, 11, 9, 55166, 12, 8, 2710, 12, 9, 3756, // 11, 9 + 11, 9, 4313, 11, 10, 53975, 12, 9, 3023, 12, 10, 4225, // 11,10 + 11, 10, 4822, 11, 11, 52484, 12, 10, 3415, 12, 11, 4815, // 11,11 + 11, 11, 5373, 11, 12, 50843, 12, 11, 3846, 12, 12, 5474, // 11,12 + 11, 12, 5930, 11, 13, 49147, 12, 12, 4291, 12, 13, 6168, // 11,13 + 11, 13, 6472, 11, 14, 47453, 12, 13, 4736, 12, 14, 6875, // 11,14 + 11, 14, 6986, 11, 15, 45791, 12, 14, 5172, 12, 15, 7587, // 11,15 + 11, -1, 5410, 11, 0, 7863, 12, -1, 7356, 12, 0, 44907, // 12, 0 + 11, 0, 5009, 11, 1, 7204, 12, 0, 6892, 12, 1, 46431, // 12, 1 + 11, 1, 4607, 11, 2, 6560, 12, 1, 6414, 12, 2, 47955, // 12, 2 + 11, 2, 4214, 11, 3, 5943, 12, 2, 5934, 12, 3, 49445, // 12, 3 + 11, 3, 3846, 11, 4, 5373, 12, 3, 5474, 12, 4, 50843, // 12, 4 + 11, 4, 3523, 11, 5, 4879, 12, 4, 5069, 12, 5, 52065, // 12, 5 + 11, 5, 3274, 11, 6, 4495, 12, 5, 4759, 12, 6, 53008, // 12, 6 + 11, 6, 3128, 11, 7, 4259, 12, 6, 4592, 12, 7, 53557, // 12, 7 + 12, 7, 4594, 12, 8, 53562, 13, 7, 3126, 13, 8, 4254, // 12, 8 + 12, 8, 4762, 12, 9, 53012, 13, 8, 3273, 13, 9, 4489, // 12, 9 + 12, 9, 5073, 12, 10, 52069, 13, 9, 3522, 13, 10, 4872, // 12,10 + 12, 10, 5481, 12, 11, 50844, 13, 10, 3845, 13, 11, 5366, // 12,11 + 12, 11, 5943, 12, 12, 49445, 13, 11, 4214, 13, 12, 5934, // 12,12 + 12, 12, 6426, 12, 13, 47953, 13, 12, 4608, 13, 13, 6549, // 12,13 + 12, 13, 6908, 12, 14, 46427, 13, 13, 5011, 13, 14, 7190, // 12,14 + 12, 14, 7374, 12, 15, 44901, 13, 14, 5413, 13, 15, 7848, // 12,15 + 12, -1, 5682, 12, 0, 8159, 13, -1, 7791, 13, 0, 43904, // 13, 0 + 12, 0, 5315, 12, 1, 7555, 13, 0, 7378, 13, 1, 45288, // 13, 1 + 12, 1, 4954, 12, 2, 6973, 13, 1, 6959, 13, 2, 46650, // 13, 2 + 12, 2, 4608, 12, 3, 6426, 13, 2, 6549, 13, 3, 47953, // 13, 3 + 12, 3, 4291, 12, 4, 5930, 13, 3, 6168, 13, 4, 49147, // 13, 4 + 12, 4, 4020, 12, 5, 5508, 13, 4, 5842, 13, 5, 50166, // 13, 5 + 12, 5, 3815, 12, 6, 5184, 13, 5, 5602, 13, 6, 50935, // 13, 6 + 12, 6, 3693, 12, 7, 4978, 13, 6, 5478, 13, 7, 51387, // 13, 7 + 13, 7, 5480, 13, 8, 51395, 14, 7, 3691, 14, 8, 4970, // 13, 8 + 13, 8, 5606, 13, 9, 50942, 14, 8, 3813, 14, 9, 5175, // 13, 9 + 13, 9, 5848, 13, 10, 50171, 14, 9, 4019, 14, 10, 5498, // 13,10 + 13, 10, 6176, 13, 11, 49150, 14, 10, 4290, 14, 11, 5920, // 13,11 + 13, 11, 6560, 13, 12, 47955, 14, 11, 4607, 14, 12, 6414, // 13,12 + 13, 12, 6973, 13, 13, 46650, 14, 12, 4954, 14, 13, 6959, // 13,13 + 13, 13, 7395, 13, 14, 45286, 14, 13, 5316, 14, 14, 7539, // 13,14 + 13, 14, 7812, 13, 15, 43900, 14, 14, 5684, 14, 15, 8140, // 13,15 + 13, -1, 5974, 13, 0, 8474, 14, -1, 8265, 14, 0, 42823, // 14, 0 + 13, 0, 5640, 13, 1, 7921, 14, 0, 7901, 14, 1, 44074, // 14, 1 + 13, 1, 5316, 13, 2, 7395, 14, 1, 7539, 14, 2, 45286, // 14, 2 + 13, 2, 5011, 13, 3, 6908, 14, 2, 7191, 14, 3, 46426, // 14, 3 + 13, 3, 4736, 13, 4, 6472, 14, 3, 6875, 14, 4, 47453, // 14, 4 + 13, 4, 4505, 13, 5, 6104, 14, 4, 6613, 14, 5, 48314, // 14, 5 + 13, 5, 4330, 13, 6, 5820, 14, 5, 6425, 14, 6, 48961, // 14, 6 + 13, 6, 4224, 13, 7, 5633, 14, 6, 6332, 14, 7, 49347, // 14, 7 + 14, 7, 6335, 14, 8, 49358, 15, 7, 4221, 15, 8, 5622, // 14, 8 + 14, 8, 6430, 14, 9, 48969, 15, 8, 4327, 15, 9, 5810, // 14, 9 + 14, 9, 6620, 14, 10, 48322, 15, 9, 4502, 15, 10, 6092, // 14,10 + 14, 10, 6886, 14, 11, 47458, 15, 10, 4734, 15, 11, 6458, // 14,11 + 14, 11, 7204, 14, 12, 46430, 15, 11, 5009, 15, 12, 6893, // 14,12 + 14, 12, 7555, 14, 13, 45288, 15, 12, 5315, 15, 13, 7378, // 14,13 + 14, 13, 7921, 14, 14, 44074, 15, 13, 5640, 15, 14, 7901, // 14,14 + 14, 14, 8288, 14, 15, 42821, 15, 14, 5975, 15, 15, 8452, // 14,15 + 14, -1, 6280, 14, 0, 8795, 15, -1, 8769, 15, 0, 41692, // 15, 0 + 14, 0, 5975, 14, 1, 8288, 15, 0, 8452, 15, 1, 42821, // 15, 1 + 14, 1, 5684, 14, 2, 7812, 15, 1, 8141, 15, 2, 43899, // 15, 2 + 14, 2, 5413, 14, 3, 7374, 15, 2, 7848, 15, 3, 44901, // 15, 3 + 14, 3, 5172, 14, 4, 6986, 15, 3, 7587, 15, 4, 45791, // 15, 4 + 14, 4, 4971, 14, 5, 6659, 15, 4, 7374, 15, 5, 46532, // 15, 5 + 14, 5, 4818, 14, 6, 6405, 15, 5, 7227, 15, 6, 47086, // 15, 6 + 14, 6, 4722, 14, 7, 6230, 15, 6, 7158, 15, 7, 47426, // 15, 7 + 15, 7, 7161, 15, 8, 47440, 16, 7, 4718, 16, 8, 6217, // 15, 8 + 15, 8, 7233, 15, 9, 47098, 16, 8, 4814, 16, 9, 6391, // 15, 9 + 15, 9, 7383, 15, 10, 46541, 16, 9, 4967, 16, 10, 6645, // 15,10 + 15, 10, 7599, 15, 11, 45799, 16, 10, 5169, 16, 11, 6969, // 15,11 + 15, 11, 7863, 15, 12, 44907, 16, 11, 5410, 16, 12, 7356, // 15,12 + 15, 12, 8159, 15, 13, 43904, 16, 12, 5682, 16, 13, 7791, // 15,13 + 15, 13, 8474, 15, 14, 42823, 16, 13, 5974, 16, 14, 8265, // 15,14 + 15, 14, 8795, 15, 15, 41693, 16, 14, 6280, 16, 15, 8768, // 15,15 + // angle of -0.5 degrees + -1, 0, 5106, -1, 1, 3621, 0, 0, 51699, 0, 1, 5110, // 0, 0 + -1, 1, 4803, -1, 2, 3421, 0, 1, 52457, 0, 2, 4855, // 0, 1 + -1, 2, 4521, -1, 3, 3235, 0, 2, 53168, 0, 3, 4612, // 0, 2 + -1, 3, 4264, -1, 4, 3064, 0, 3, 53815, 0, 4, 4393, // 0, 3 + -1, 4, 4041, -1, 5, 2916, 0, 4, 54378, 0, 5, 4201, // 0, 4 + -1, 5, 3858, -1, 6, 2796, 0, 5, 54835, 0, 6, 4047, // 0, 5 + -1, 6, 3722, -1, 7, 2709, 0, 6, 55166, 0, 7, 3939, // 0, 6 + -1, 7, 3638, -1, 8, 2659, 0, 7, 55354, 0, 8, 3885, // 0, 7 + 0, 8, 55352, 0, 9, 3885, 1, 8, 3640, 1, 9, 2659, // 0, 8 + 0, 9, 55164, 0, 10, 3939, 1, 9, 3724, 1, 10, 2709, // 0, 9 + 0, 10, 54833, 0, 11, 4046, 1, 10, 3860, 1, 11, 2797, // 0,10 + 0, 11, 54376, 0, 12, 4200, 1, 11, 4043, 1, 12, 2917, // 0,11 + 0, 12, 53814, 0, 13, 4390, 1, 12, 4267, 1, 13, 3065, // 0,12 + 0, 13, 53168, 0, 14, 4610, 1, 13, 4523, 1, 14, 3235, // 0,13 + 0, 14, 52457, 0, 15, 4851, 1, 14, 4806, 1, 15, 3422, // 0,14 + 0, 15, 51699, 0, 16, 5106, 1, 15, 5110, 1, 16, 3621, // 0,15 + 0, 0, 4851, 0, 1, 3422, 1, 0, 52457, 1, 1, 4806, // 1, 0 + 0, 1, 4522, 0, 2, 3204, 1, 1, 53285, 1, 2, 4525, // 1, 1 + 0, 2, 4212, 0, 3, 2998, 1, 2, 54072, 1, 3, 4254, // 1, 2 + 0, 3, 3927, 0, 4, 2808, 1, 3, 54796, 1, 4, 4005, // 1, 3 + 0, 4, 3677, 0, 5, 2640, 1, 4, 55435, 1, 5, 3784, // 1, 4 + 0, 5, 3470, 0, 6, 2502, 1, 5, 55959, 1, 6, 3605, // 1, 5 + 0, 6, 3317, 0, 7, 2402, 1, 6, 56340, 1, 7, 3477, // 1, 6 + 0, 7, 3225, 0, 8, 2346, 1, 7, 56554, 1, 8, 3411, // 1, 7 + 1, 8, 56552, 1, 9, 3411, 2, 8, 3227, 2, 9, 2346, // 1, 8 + 1, 9, 56339, 1, 10, 3476, 2, 9, 3319, 2, 10, 2402, // 1, 9 + 1, 10, 55958, 1, 11, 3604, 2, 10, 3472, 2, 11, 2502, // 1,10 + 1, 11, 55434, 1, 12, 3783, 2, 11, 3678, 2, 12, 2641, // 1,11 + 1, 12, 54796, 1, 13, 4003, 2, 12, 3929, 2, 13, 2808, // 1,12 + 1, 13, 54071, 1, 14, 4253, 2, 13, 4214, 2, 14, 2998, // 1,13 + 1, 14, 53285, 1, 15, 4522, 2, 14, 4525, 2, 15, 3204, // 1,14 + 1, 15, 52457, 1, 16, 4803, 2, 15, 4854, 2, 16, 3422, // 1,15 + 1, 0, 4610, 1, 1, 3235, 2, 0, 53168, 2, 1, 4523, // 2, 0 + 1, 1, 4253, 1, 2, 2998, 2, 1, 54071, 2, 2, 4214, // 2, 1 + 1, 2, 3911, 1, 3, 2770, 2, 2, 54941, 2, 3, 3914, // 2, 2 + 1, 3, 3594, 1, 4, 2556, 2, 3, 55756, 2, 4, 3630, // 2, 3 + 1, 4, 3310, 1, 5, 2365, 2, 4, 56487, 2, 5, 3374, // 2, 4 + 1, 5, 3073, 1, 6, 2205, 2, 5, 57096, 2, 6, 3162, // 2, 5 + 1, 6, 2897, 1, 7, 2088, 2, 6, 57545, 2, 7, 3006, // 2, 6 + 1, 7, 2794, 1, 8, 2022, 2, 7, 57795, 2, 8, 2925, // 2, 7 + 2, 8, 57793, 2, 9, 2926, 3, 8, 2795, 3, 9, 2022, // 2, 8 + 2, 9, 57544, 2, 10, 3007, 3, 9, 2898, 3, 10, 2087, // 2, 9 + 2, 10, 57095, 2, 11, 3161, 3, 10, 3074, 3, 11, 2206, // 2,10 + 2, 11, 56486, 2, 12, 3373, 3, 11, 3311, 3, 12, 2366, // 2,11 + 2, 12, 55756, 2, 13, 3628, 3, 12, 3595, 3, 13, 2557, // 2,12 + 2, 13, 54941, 2, 14, 3911, 3, 13, 3913, 3, 14, 2771, // 2,13 + 2, 14, 54072, 2, 15, 4212, 3, 14, 4255, 3, 15, 2997, // 2,14 + 2, 15, 53168, 2, 16, 4521, 3, 15, 4612, 3, 16, 3235, // 2,15 + 2, 0, 4390, 2, 1, 3065, 3, 0, 53814, 3, 1, 4267, // 3, 0 + 2, 1, 4003, 2, 2, 2808, 3, 1, 54796, 3, 2, 3929, // 3, 1 + 2, 2, 3628, 2, 3, 2557, 3, 2, 55756, 3, 3, 3595, // 3, 2 + 2, 3, 3273, 2, 4, 2317, 3, 3, 56673, 3, 4, 3273, // 3, 3 + 2, 4, 2948, 2, 5, 2096, 3, 4, 57514, 3, 5, 2978, // 3, 4 + 2, 5, 2672, 2, 6, 1908, 3, 5, 58234, 3, 6, 2722, // 3, 5 + 2, 6, 2463, 2, 7, 1766, 3, 6, 58775, 3, 7, 2532, // 3, 6 + 2, 7, 2342, 2, 8, 1687, 3, 7, 59077, 3, 8, 2430, // 3, 7 + 3, 8, 59076, 3, 9, 2430, 4, 8, 2343, 4, 9, 1687, // 3, 8 + 3, 9, 58774, 3, 10, 2532, 4, 9, 2464, 4, 10, 1766, // 3, 9 + 3, 10, 58233, 3, 11, 2722, 4, 10, 2673, 4, 11, 1908, // 3,10 + 3, 11, 57514, 3, 12, 2976, 4, 11, 2950, 4, 12, 2096, // 3,11 + 3, 12, 56673, 3, 13, 3273, 4, 12, 3274, 4, 13, 2316, // 3,12 + 3, 13, 55756, 3, 14, 3594, 4, 13, 3630, 4, 14, 2556, // 3,13 + 3, 14, 54796, 3, 15, 3927, 4, 14, 4005, 4, 15, 2808, // 3,14 + 3, 15, 53815, 3, 16, 4264, 4, 15, 4392, 4, 16, 3065, // 3,15 + 3, 0, 4200, 3, 1, 2917, 4, 0, 54376, 4, 1, 4043, // 4, 0 + 3, 1, 3783, 3, 2, 2640, 4, 1, 55434, 4, 2, 3679, // 4, 1 + 3, 2, 3373, 3, 3, 2365, 4, 2, 56486, 4, 3, 3312, // 4, 2 + 3, 3, 2976, 3, 4, 2096, 4, 3, 57514, 4, 4, 2950, // 4, 3 + 3, 4, 2604, 3, 5, 1843, 4, 4, 58484, 4, 5, 2605, // 4, 4 + 3, 5, 2276, 3, 6, 1617, 4, 5, 59346, 4, 6, 2297, // 4, 5 + 3, 6, 2020, 3, 7, 1442, 4, 6, 60018, 4, 7, 2056, // 4, 6 + 3, 7, 1871, 3, 8, 1341, 4, 7, 60402, 4, 8, 1922, // 4, 7 + 4, 8, 60402, 4, 9, 1922, 5, 8, 1871, 5, 9, 1341, // 4, 8 + 4, 9, 60017, 4, 10, 2057, 5, 9, 2020, 5, 10, 1442, // 4, 9 + 4, 10, 59345, 4, 11, 2297, 5, 10, 2276, 5, 11, 1618, // 4,10 + 4, 11, 58484, 4, 12, 2604, 5, 11, 2605, 5, 12, 1843, // 4,11 + 4, 12, 57514, 4, 13, 2948, 5, 12, 2977, 5, 13, 2097, // 4,12 + 4, 13, 56487, 4, 14, 3310, 5, 13, 3374, 5, 14, 2365, // 4,13 + 4, 14, 55435, 4, 15, 3677, 5, 14, 3785, 5, 15, 2639, // 4,14 + 4, 15, 54378, 4, 16, 4041, 5, 15, 4201, 5, 16, 2916, // 4,15 + 4, 0, 4046, 4, 1, 2797, 5, 0, 54833, 5, 1, 3860, // 5, 0 + 4, 1, 3604, 4, 2, 2503, 5, 1, 55958, 5, 2, 3471, // 5, 1 + 4, 2, 3161, 4, 3, 2205, 5, 2, 57095, 5, 3, 3075, // 5, 2 + 4, 3, 2722, 4, 4, 1908, 5, 3, 58233, 5, 4, 2673, // 5, 3 + 4, 4, 2297, 4, 5, 1617, 5, 4, 59345, 5, 5, 2277, // 5, 4 + 4, 5, 1904, 4, 6, 1347, 5, 5, 60381, 5, 6, 1904, // 5, 5 + 4, 6, 1578, 4, 7, 1121, 5, 6, 61243, 5, 7, 1594, // 5, 6 + 4, 7, 1380, 4, 8, 985, 5, 7, 61767, 5, 8, 1404, // 5, 7 + 5, 8, 61767, 5, 9, 1405, 6, 8, 1380, 6, 9, 984, // 5, 8 + 5, 9, 61243, 5, 10, 1593, 6, 9, 1579, 6, 10, 1121, // 5, 9 + 5, 10, 60381, 5, 11, 1904, 6, 10, 1904, 6, 11, 1347, // 5,10 + 5, 11, 59346, 5, 12, 2276, 6, 11, 2297, 6, 12, 1617, // 5,11 + 5, 12, 58234, 5, 13, 2672, 6, 12, 2723, 6, 13, 1907, // 5,12 + 5, 13, 57096, 5, 14, 3073, 6, 13, 3161, 6, 14, 2206, // 5,13 + 5, 14, 55959, 5, 15, 3470, 6, 14, 3605, 6, 15, 2502, // 5,14 + 5, 15, 54835, 5, 16, 3858, 6, 15, 4047, 6, 16, 2796, // 5,15 + 5, 0, 3939, 5, 1, 2709, 6, 0, 55164, 6, 1, 3724, // 6, 0 + 5, 1, 3476, 5, 2, 2403, 6, 1, 56339, 6, 2, 3318, // 6, 1 + 5, 2, 3007, 5, 3, 2088, 6, 2, 57544, 6, 3, 2897, // 6, 2 + 5, 3, 2532, 5, 4, 1767, 6, 3, 58774, 6, 4, 2463, // 6, 3 + 5, 4, 2057, 5, 5, 1442, 6, 4, 60017, 6, 5, 2020, // 6, 4 + 5, 5, 1593, 5, 6, 1121, 6, 5, 61243, 6, 6, 1579, // 6, 5 + 5, 6, 1170, 5, 7, 827, 6, 6, 62369, 6, 7, 1170, // 6, 6 + 5, 7, 875, 5, 8, 622, 6, 7, 63156, 6, 8, 883, // 6, 7 + 6, 8, 63156, 6, 9, 883, 7, 8, 875, 7, 9, 622, // 6, 8 + 6, 9, 62369, 6, 10, 1170, 7, 9, 1170, 7, 10, 827, // 6, 9 + 6, 10, 61243, 6, 11, 1578, 7, 10, 1593, 7, 11, 1122, // 6,10 + 6, 11, 60018, 6, 12, 2020, 7, 11, 2057, 7, 12, 1441, // 6,11 + 6, 12, 58775, 6, 13, 2463, 7, 12, 2532, 7, 13, 1766, // 6,12 + 6, 13, 57545, 6, 14, 2897, 7, 13, 3007, 7, 14, 2087, // 6,13 + 6, 14, 56340, 6, 15, 3317, 7, 14, 3477, 7, 15, 2402, // 6,14 + 6, 15, 55166, 6, 16, 3722, 7, 15, 3940, 7, 16, 2708, // 6,15 + 6, 0, 3885, 6, 1, 2659, 7, 0, 55352, 7, 1, 3640, // 7, 0 + 6, 1, 3411, 6, 2, 2346, 7, 1, 56552, 7, 2, 3227, // 7, 1 + 6, 2, 2926, 6, 3, 2022, 7, 2, 57793, 7, 3, 2795, // 7, 2 + 6, 3, 2430, 6, 4, 1687, 7, 3, 59076, 7, 4, 2343, // 7, 3 + 6, 4, 1922, 6, 5, 1341, 7, 4, 60402, 7, 5, 1871, // 7, 4 + 6, 5, 1405, 6, 6, 985, 7, 5, 61767, 7, 6, 1379, // 7, 5 + 6, 6, 883, 6, 7, 622, 7, 6, 63156, 7, 7, 875, // 7, 6 + 6, 7, 399, 6, 8, 282, 7, 7, 64455, 7, 8, 400, // 7, 7 + 7, 8, 64455, 7, 9, 399, 8, 8, 399, 8, 9, 283, // 7, 8 + 7, 9, 63156, 7, 10, 875, 8, 9, 883, 8, 10, 622, // 7, 9 + 7, 10, 61767, 7, 11, 1380, 8, 10, 1405, 8, 11, 984, // 7,10 + 7, 11, 60402, 7, 12, 1871, 8, 11, 1922, 8, 12, 1341, // 7,11 + 7, 12, 59077, 7, 13, 2342, 8, 12, 2430, 8, 13, 1687, // 7,12 + 7, 13, 57795, 7, 14, 2794, 8, 13, 2926, 8, 14, 2021, // 7,13 + 7, 14, 56554, 7, 15, 3225, 8, 14, 3411, 8, 15, 2346, // 7,14 + 7, 15, 55354, 7, 16, 3638, 8, 15, 3885, 8, 16, 2659, // 7,15 + 7, -1, 2659, 7, 0, 3885, 8, -1, 3638, 8, 0, 55354, // 8, 0 + 7, 0, 2346, 7, 1, 3411, 8, 0, 3225, 8, 1, 56554, // 8, 1 + 7, 1, 2022, 7, 2, 2926, 8, 1, 2794, 8, 2, 57794, // 8, 2 + 7, 2, 1687, 7, 3, 2430, 8, 2, 2342, 8, 3, 59077, // 8, 3 + 7, 3, 1341, 7, 4, 1922, 8, 3, 1871, 8, 4, 60402, // 8, 4 + 7, 4, 985, 7, 5, 1405, 8, 4, 1380, 8, 5, 61766, // 8, 5 + 7, 5, 622, 7, 6, 883, 8, 5, 875, 8, 6, 63156, // 8, 6 + 7, 6, 282, 7, 7, 399, 8, 6, 399, 8, 7, 64456, // 8, 7 + 8, 7, 399, 8, 8, 64455, 9, 7, 282, 9, 8, 400, // 8, 8 + 8, 8, 875, 8, 9, 63156, 9, 8, 622, 9, 9, 883, // 8, 9 + 8, 9, 1380, 8, 10, 61767, 9, 9, 985, 9, 10, 1404, // 8,10 + 8, 10, 1871, 8, 11, 60402, 9, 10, 1341, 9, 11, 1922, // 8,11 + 8, 11, 2343, 8, 12, 59076, 9, 11, 1687, 9, 12, 2430, // 8,12 + 8, 12, 2795, 8, 13, 57793, 9, 12, 2022, 9, 13, 2926, // 8,13 + 8, 13, 3227, 8, 14, 56552, 9, 13, 2346, 9, 14, 3411, // 8,14 + 8, 14, 3640, 8, 15, 55352, 9, 14, 2659, 9, 15, 3885, // 8,15 + 8, -1, 2709, 8, 0, 3940, 9, -1, 3722, 9, 0, 55165, // 9, 0 + 8, 0, 2402, 8, 1, 3477, 9, 0, 3317, 9, 1, 56340, // 9, 1 + 8, 1, 2088, 8, 2, 3007, 9, 1, 2897, 9, 2, 57544, // 9, 2 + 8, 2, 1766, 8, 3, 2532, 9, 2, 2463, 9, 3, 58775, // 9, 3 + 8, 3, 1442, 8, 4, 2057, 9, 3, 2020, 9, 4, 60017, // 9, 4 + 8, 4, 1121, 8, 5, 1593, 9, 4, 1578, 9, 5, 61244, // 9, 5 + 8, 5, 827, 8, 6, 1170, 9, 5, 1170, 9, 6, 62369, // 9, 6 + 8, 6, 622, 8, 7, 875, 9, 6, 883, 9, 7, 63156, // 9, 7 + 9, 7, 883, 9, 8, 63156, 10, 7, 622, 10, 8, 875, // 9, 8 + 9, 8, 1170, 9, 9, 62369, 10, 8, 827, 10, 9, 1170, // 9, 9 + 9, 9, 1579, 9, 10, 61243, 10, 9, 1121, 10, 10, 1593, // 9,10 + 9, 10, 2020, 9, 11, 60017, 10, 10, 1442, 10, 11, 2057, // 9,11 + 9, 11, 2464, 9, 12, 58774, 10, 11, 1767, 10, 12, 2531, // 9,12 + 9, 12, 2898, 9, 13, 57544, 10, 12, 2088, 10, 13, 3006, // 9,13 + 9, 13, 3319, 9, 14, 56339, 10, 13, 2403, 10, 14, 3475, // 9,14 + 9, 14, 3724, 9, 15, 55164, 10, 14, 2709, 10, 15, 3939, // 9,15 + 9, -1, 2796, 9, 0, 4047, 10, -1, 3858, 10, 0, 54835, // 10, 0 + 9, 0, 2502, 9, 1, 3605, 10, 0, 3470, 10, 1, 55959, // 10, 1 + 9, 1, 2205, 9, 2, 3161, 10, 1, 3073, 10, 2, 57097, // 10, 2 + 9, 2, 1908, 9, 3, 2723, 10, 2, 2672, 10, 3, 58233, // 10, 3 + 9, 3, 1617, 9, 4, 2297, 10, 3, 2276, 10, 4, 59346, // 10, 4 + 9, 4, 1347, 9, 5, 1904, 10, 4, 1904, 10, 5, 60381, // 10, 5 + 9, 5, 1121, 9, 6, 1579, 10, 5, 1593, 10, 6, 61243, // 10, 6 + 9, 6, 985, 9, 7, 1380, 10, 6, 1405, 10, 7, 61766, // 10, 7 + 10, 7, 1405, 10, 8, 61767, 11, 7, 985, 11, 8, 1379, // 10, 8 + 10, 8, 1593, 10, 9, 61243, 11, 8, 1121, 11, 9, 1579, // 10, 9 + 10, 9, 1904, 10, 10, 60381, 11, 9, 1347, 11, 10, 1904, // 10,10 + 10, 10, 2276, 10, 11, 59345, 11, 10, 1617, 11, 11, 2298, // 10,11 + 10, 11, 2673, 10, 12, 58233, 11, 11, 1908, 11, 12, 2722, // 10,12 + 10, 12, 3074, 10, 13, 57095, 11, 12, 2205, 11, 13, 3162, // 10,13 + 10, 13, 3472, 10, 14, 55958, 11, 13, 2503, 11, 14, 3603, // 10,14 + 10, 14, 3860, 10, 15, 54833, 11, 14, 2797, 11, 15, 4046, // 10,15 + 10, -1, 2916, 10, 0, 4201, 11, -1, 4041, 11, 0, 54378, // 11, 0 + 10, 0, 2640, 10, 1, 3785, 11, 0, 3677, 11, 1, 55434, // 11, 1 + 10, 1, 2365, 10, 2, 3374, 11, 1, 3310, 11, 2, 56487, // 11, 2 + 10, 2, 2096, 10, 3, 2977, 11, 2, 2948, 11, 3, 57515, // 11, 3 + 10, 3, 1843, 10, 4, 2605, 11, 3, 2604, 11, 4, 58484, // 11, 4 + 10, 4, 1617, 10, 5, 2276, 11, 4, 2297, 11, 5, 59346, // 11, 5 + 10, 5, 1442, 10, 6, 2020, 11, 5, 2057, 11, 6, 60017, // 11, 6 + 10, 6, 1341, 10, 7, 1871, 11, 6, 1922, 11, 7, 60402, // 11, 7 + 11, 7, 1922, 11, 8, 60402, 12, 7, 1341, 12, 8, 1871, // 11, 8 + 11, 8, 2057, 11, 9, 60018, 12, 8, 1442, 12, 9, 2019, // 11, 9 + 11, 9, 2297, 11, 10, 59346, 12, 9, 1617, 12, 10, 2276, // 11,10 + 11, 10, 2605, 11, 11, 58484, 12, 10, 1843, 12, 11, 2604, // 11,11 + 11, 11, 2950, 11, 12, 57514, 12, 11, 2096, 12, 12, 2976, // 11,12 + 11, 12, 3311, 11, 13, 56486, 12, 12, 2365, 12, 13, 3374, // 11,13 + 11, 13, 3678, 11, 14, 55434, 12, 13, 2640, 12, 14, 3784, // 11,14 + 11, 14, 4043, 11, 15, 54376, 12, 14, 2917, 12, 15, 4200, // 11,15 + 11, -1, 3064, 11, 0, 4392, 12, -1, 4264, 12, 0, 53816, // 12, 0 + 11, 0, 2808, 11, 1, 4005, 12, 0, 3927, 12, 1, 54796, // 12, 1 + 11, 1, 2556, 11, 2, 3630, 12, 1, 3594, 12, 2, 55756, // 12, 2 + 11, 2, 2317, 11, 3, 3274, 12, 2, 3273, 12, 3, 56672, // 12, 3 + 11, 3, 2096, 11, 4, 2950, 12, 3, 2976, 12, 4, 57514, // 12, 4 + 11, 4, 1908, 11, 5, 2673, 12, 4, 2722, 12, 5, 58233, // 12, 5 + 11, 5, 1767, 11, 6, 2464, 12, 5, 2532, 12, 6, 58773, // 12, 6 + 11, 6, 1687, 11, 7, 2343, 12, 6, 2430, 12, 7, 59076, // 12, 7 + 12, 7, 2430, 12, 8, 59077, 13, 7, 1687, 13, 8, 2342, // 12, 8 + 12, 8, 2532, 12, 9, 58775, 13, 8, 1766, 13, 9, 2463, // 12, 9 + 12, 9, 2723, 12, 10, 58234, 13, 9, 1908, 13, 10, 2671, // 12,10 + 12, 10, 2977, 12, 11, 57514, 13, 10, 2096, 13, 11, 2949, // 12,11 + 12, 11, 3274, 12, 12, 56673, 13, 11, 2317, 13, 12, 3272, // 12,12 + 12, 12, 3595, 12, 13, 55756, 13, 12, 2557, 13, 13, 3628, // 12,13 + 12, 13, 3929, 12, 14, 54796, 13, 13, 2808, 13, 14, 4003, // 12,14 + 12, 14, 4267, 12, 15, 53814, 13, 14, 3065, 13, 15, 4390, // 12,15 + 12, -1, 3235, 12, 0, 4612, 13, -1, 4521, 13, 0, 53168, // 13, 0 + 12, 0, 2998, 12, 1, 4255, 13, 0, 4212, 13, 1, 54071, // 13, 1 + 12, 1, 2770, 12, 2, 3913, 13, 1, 3911, 13, 2, 54942, // 13, 2 + 12, 2, 2557, 12, 3, 3595, 13, 2, 3628, 13, 3, 55756, // 13, 3 + 12, 3, 2365, 12, 4, 3311, 13, 3, 3373, 13, 4, 56487, // 13, 4 + 12, 4, 2205, 12, 5, 3074, 13, 4, 3161, 13, 5, 57096, // 13, 5 + 12, 5, 2088, 12, 6, 2898, 13, 5, 3007, 13, 6, 57543, // 13, 6 + 12, 6, 2022, 12, 7, 2795, 13, 6, 2926, 13, 7, 57793, // 13, 7 + 13, 7, 2926, 13, 8, 57795, 14, 7, 2022, 14, 8, 2793, // 13, 8 + 13, 8, 3007, 13, 9, 57545, 14, 8, 2088, 14, 9, 2896, // 13, 9 + 13, 9, 3161, 13, 10, 57096, 14, 9, 2205, 14, 10, 3074, // 13,10 + 13, 10, 3374, 13, 11, 56487, 14, 10, 2365, 14, 11, 3310, // 13,11 + 13, 11, 3630, 13, 12, 55756, 14, 11, 2556, 14, 12, 3594, // 13,12 + 13, 12, 3913, 13, 13, 54941, 14, 12, 2770, 14, 13, 3912, // 13,13 + 13, 13, 4214, 13, 14, 54071, 14, 13, 2998, 14, 14, 4253, // 13,14 + 13, 14, 4523, 13, 15, 53168, 14, 14, 3235, 14, 15, 4610, // 13,15 + 13, -1, 3421, 13, 0, 4854, 14, -1, 4803, 14, 0, 52458, // 14, 0 + 13, 0, 3204, 13, 1, 4525, 14, 0, 4522, 14, 1, 53285, // 14, 1 + 13, 1, 2998, 13, 2, 4214, 14, 1, 4253, 14, 2, 54071, // 14, 2 + 13, 2, 2808, 13, 3, 3929, 14, 2, 4003, 14, 3, 54796, // 14, 3 + 13, 3, 2640, 13, 4, 3678, 14, 3, 3783, 14, 4, 55435, // 14, 4 + 13, 4, 2503, 13, 5, 3472, 14, 4, 3604, 14, 5, 55957, // 14, 5 + 13, 5, 2403, 13, 6, 3319, 14, 5, 3476, 14, 6, 56338, // 14, 6 + 13, 6, 2346, 13, 7, 3227, 14, 6, 3411, 14, 7, 56552, // 14, 7 + 14, 7, 3411, 14, 8, 56554, 15, 7, 2346, 15, 8, 3225, // 14, 8 + 14, 8, 3477, 14, 9, 56340, 15, 8, 2402, 15, 9, 3317, // 14, 9 + 14, 9, 3605, 14, 10, 55959, 15, 9, 2502, 15, 10, 3470, // 14,10 + 14, 10, 3785, 14, 11, 55435, 15, 10, 2640, 15, 11, 3676, // 14,11 + 14, 11, 4005, 14, 12, 54796, 15, 11, 2808, 15, 12, 3927, // 14,12 + 14, 12, 4255, 14, 13, 54072, 15, 12, 2998, 15, 13, 4211, // 14,13 + 14, 13, 4525, 14, 14, 53285, 15, 13, 3204, 15, 14, 4522, // 14,14 + 14, 14, 4806, 14, 15, 52457, 15, 14, 3422, 15, 15, 4851, // 14,15 + 14, -1, 3621, 14, 0, 5110, 15, -1, 5106, 15, 0, 51699, // 15, 0 + 14, 0, 3422, 14, 1, 4806, 15, 0, 4851, 15, 1, 52457, // 15, 1 + 14, 1, 3235, 14, 2, 4523, 15, 1, 4610, 15, 2, 53168, // 15, 2 + 14, 2, 3065, 14, 3, 4267, 15, 2, 4390, 15, 3, 53814, // 15, 3 + 14, 3, 2917, 14, 4, 4043, 15, 3, 4200, 15, 4, 54376, // 15, 4 + 14, 4, 2797, 14, 5, 3860, 15, 4, 4046, 15, 5, 54833, // 15, 5 + 14, 5, 2709, 14, 6, 3724, 15, 5, 3939, 15, 6, 55164, // 15, 6 + 14, 6, 2659, 14, 7, 3640, 15, 6, 3885, 15, 7, 55352, // 15, 7 + 15, 7, 3885, 15, 8, 55354, 16, 7, 2659, 16, 8, 3638, // 15, 8 + 15, 8, 3940, 15, 9, 55166, 16, 8, 2709, 16, 9, 3721, // 15, 9 + 15, 9, 4047, 15, 10, 54835, 16, 9, 2796, 16, 10, 3858, // 15,10 + 15, 10, 4201, 15, 11, 54378, 16, 10, 2916, 16, 11, 4041, // 15,11 + 15, 11, 4392, 15, 12, 53815, 16, 11, 3064, 16, 12, 4265, // 15,12 + 15, 12, 4612, 15, 13, 53168, 16, 12, 3235, 16, 13, 4521, // 15,13 + 15, 13, 4854, 15, 14, 52457, 16, 13, 3421, 16, 14, 4804, // 15,14 + 15, 14, 5110, 15, 15, 51699, 16, 14, 3621, 16, 15, 5106, // 15,15 + // angle of 0.0 degrees + 0, 0, 16384, 0, 0, 16384, 0, 0, 16384, 0, 0, 16384, // 0, 0 + 0, 1, 16384, 0, 1, 16384, 0, 1, 16384, 0, 1, 16384, // 0, 1 + 0, 2, 16384, 0, 2, 16384, 0, 2, 16384, 0, 2, 16384, // 0, 2 + 0, 3, 16384, 0, 3, 16384, 0, 3, 16384, 0, 3, 16384, // 0, 3 + 0, 4, 16384, 0, 4, 16384, 0, 4, 16384, 0, 4, 16384, // 0, 4 + 0, 5, 16384, 0, 5, 16384, 0, 5, 16384, 0, 5, 16384, // 0, 5 + 0, 6, 16384, 0, 6, 16384, 0, 6, 16384, 0, 6, 16384, // 0, 6 + 0, 7, 16384, 0, 7, 16384, 0, 7, 16384, 0, 7, 16384, // 0, 7 + 0, 8, 16384, 0, 8, 16384, 0, 8, 16384, 0, 8, 16384, // 0, 8 + 0, 9, 16384, 0, 9, 16384, 0, 9, 16384, 0, 9, 16384, // 0, 9 + 0, 10, 16384, 0, 10, 16384, 0, 10, 16384, 0, 10, 16384, // 0,10 + 0, 11, 16384, 0, 11, 16384, 0, 11, 16384, 0, 11, 16384, // 0,11 + 0, 12, 16384, 0, 12, 16384, 0, 12, 16384, 0, 12, 16384, // 0,12 + 0, 13, 16384, 0, 13, 16384, 0, 13, 16384, 0, 13, 16384, // 0,13 + 0, 14, 16384, 0, 14, 16384, 0, 14, 16384, 0, 14, 16384, // 0,14 + 0, 15, 16384, 0, 15, 16384, 0, 15, 16384, 0, 15, 16384, // 0,15 + 1, 0, 16384, 1, 0, 16384, 1, 0, 16384, 1, 0, 16384, // 1, 0 + 1, 1, 16384, 1, 1, 16384, 1, 1, 16384, 1, 1, 16384, // 1, 1 + 1, 2, 16384, 1, 2, 16384, 1, 2, 16384, 1, 2, 16384, // 1, 2 + 1, 3, 16384, 1, 3, 16384, 1, 3, 16384, 1, 3, 16384, // 1, 3 + 1, 4, 16384, 1, 4, 16384, 1, 4, 16384, 1, 4, 16384, // 1, 4 + 1, 5, 16384, 1, 5, 16384, 1, 5, 16384, 1, 5, 16384, // 1, 5 + 1, 6, 16384, 1, 6, 16384, 1, 6, 16384, 1, 6, 16384, // 1, 6 + 1, 7, 16384, 1, 7, 16384, 1, 7, 16384, 1, 7, 16384, // 1, 7 + 1, 8, 16384, 1, 8, 16384, 1, 8, 16384, 1, 8, 16384, // 1, 8 + 1, 9, 16384, 1, 9, 16384, 1, 9, 16384, 1, 9, 16384, // 1, 9 + 1, 10, 16384, 1, 10, 16384, 1, 10, 16384, 1, 10, 16384, // 1,10 + 1, 11, 16384, 1, 11, 16384, 1, 11, 16384, 1, 11, 16384, // 1,11 + 1, 12, 16384, 1, 12, 16384, 1, 12, 16384, 1, 12, 16384, // 1,12 + 1, 13, 16384, 1, 13, 16384, 1, 13, 16384, 1, 13, 16384, // 1,13 + 1, 14, 16384, 1, 14, 16384, 1, 14, 16384, 1, 14, 16384, // 1,14 + 1, 15, 16384, 1, 15, 16384, 1, 15, 16384, 1, 15, 16384, // 1,15 + 2, 0, 16384, 2, 0, 16384, 2, 0, 16384, 2, 0, 16384, // 2, 0 + 2, 1, 16384, 2, 1, 16384, 2, 1, 16384, 2, 1, 16384, // 2, 1 + 2, 2, 16384, 2, 2, 16384, 2, 2, 16384, 2, 2, 16384, // 2, 2 + 2, 3, 16384, 2, 3, 16384, 2, 3, 16384, 2, 3, 16384, // 2, 3 + 2, 4, 16384, 2, 4, 16384, 2, 4, 16384, 2, 4, 16384, // 2, 4 + 2, 5, 16384, 2, 5, 16384, 2, 5, 16384, 2, 5, 16384, // 2, 5 + 2, 6, 16384, 2, 6, 16384, 2, 6, 16384, 2, 6, 16384, // 2, 6 + 2, 7, 16384, 2, 7, 16384, 2, 7, 16384, 2, 7, 16384, // 2, 7 + 2, 8, 16384, 2, 8, 16384, 2, 8, 16384, 2, 8, 16384, // 2, 8 + 2, 9, 16384, 2, 9, 16384, 2, 9, 16384, 2, 9, 16384, // 2, 9 + 2, 10, 16384, 2, 10, 16384, 2, 10, 16384, 2, 10, 16384, // 2,10 + 2, 11, 16384, 2, 11, 16384, 2, 11, 16384, 2, 11, 16384, // 2,11 + 2, 12, 16384, 2, 12, 16384, 2, 12, 16384, 2, 12, 16384, // 2,12 + 2, 13, 16384, 2, 13, 16384, 2, 13, 16384, 2, 13, 16384, // 2,13 + 2, 14, 16384, 2, 14, 16384, 2, 14, 16384, 2, 14, 16384, // 2,14 + 2, 15, 16384, 2, 15, 16384, 2, 15, 16384, 2, 15, 16384, // 2,15 + 3, 0, 16384, 3, 0, 16384, 3, 0, 16384, 3, 0, 16384, // 3, 0 + 3, 1, 16384, 3, 1, 16384, 3, 1, 16384, 3, 1, 16384, // 3, 1 + 3, 2, 16384, 3, 2, 16384, 3, 2, 16384, 3, 2, 16384, // 3, 2 + 3, 3, 16384, 3, 3, 16384, 3, 3, 16384, 3, 3, 16384, // 3, 3 + 3, 4, 16384, 3, 4, 16384, 3, 4, 16384, 3, 4, 16384, // 3, 4 + 3, 5, 16384, 3, 5, 16384, 3, 5, 16384, 3, 5, 16384, // 3, 5 + 3, 6, 16384, 3, 6, 16384, 3, 6, 16384, 3, 6, 16384, // 3, 6 + 3, 7, 16384, 3, 7, 16384, 3, 7, 16384, 3, 7, 16384, // 3, 7 + 3, 8, 16384, 3, 8, 16384, 3, 8, 16384, 3, 8, 16384, // 3, 8 + 3, 9, 16384, 3, 9, 16384, 3, 9, 16384, 3, 9, 16384, // 3, 9 + 3, 10, 16384, 3, 10, 16384, 3, 10, 16384, 3, 10, 16384, // 3,10 + 3, 11, 16384, 3, 11, 16384, 3, 11, 16384, 3, 11, 16384, // 3,11 + 3, 12, 16384, 3, 12, 16384, 3, 12, 16384, 3, 12, 16384, // 3,12 + 3, 13, 16384, 3, 13, 16384, 3, 13, 16384, 3, 13, 16384, // 3,13 + 3, 14, 16384, 3, 14, 16384, 3, 14, 16384, 3, 14, 16384, // 3,14 + 3, 15, 16384, 3, 15, 16384, 3, 15, 16384, 3, 15, 16384, // 3,15 + 4, 0, 16384, 4, 0, 16384, 4, 0, 16384, 4, 0, 16384, // 4, 0 + 4, 1, 16384, 4, 1, 16384, 4, 1, 16384, 4, 1, 16384, // 4, 1 + 4, 2, 16384, 4, 2, 16384, 4, 2, 16384, 4, 2, 16384, // 4, 2 + 4, 3, 16384, 4, 3, 16384, 4, 3, 16384, 4, 3, 16384, // 4, 3 + 4, 4, 16384, 4, 4, 16384, 4, 4, 16384, 4, 4, 16384, // 4, 4 + 4, 5, 16384, 4, 5, 16384, 4, 5, 16384, 4, 5, 16384, // 4, 5 + 4, 6, 16384, 4, 6, 16384, 4, 6, 16384, 4, 6, 16384, // 4, 6 + 4, 7, 16384, 4, 7, 16384, 4, 7, 16384, 4, 7, 16384, // 4, 7 + 4, 8, 16384, 4, 8, 16384, 4, 8, 16384, 4, 8, 16384, // 4, 8 + 4, 9, 16384, 4, 9, 16384, 4, 9, 16384, 4, 9, 16384, // 4, 9 + 4, 10, 16384, 4, 10, 16384, 4, 10, 16384, 4, 10, 16384, // 4,10 + 4, 11, 16384, 4, 11, 16384, 4, 11, 16384, 4, 11, 16384, // 4,11 + 4, 12, 16384, 4, 12, 16384, 4, 12, 16384, 4, 12, 16384, // 4,12 + 4, 13, 16384, 4, 13, 16384, 4, 13, 16384, 4, 13, 16384, // 4,13 + 4, 14, 16384, 4, 14, 16384, 4, 14, 16384, 4, 14, 16384, // 4,14 + 4, 15, 16384, 4, 15, 16384, 4, 15, 16384, 4, 15, 16384, // 4,15 + 5, 0, 16384, 5, 0, 16384, 5, 0, 16384, 5, 0, 16384, // 5, 0 + 5, 1, 16384, 5, 1, 16384, 5, 1, 16384, 5, 1, 16384, // 5, 1 + 5, 2, 16384, 5, 2, 16384, 5, 2, 16384, 5, 2, 16384, // 5, 2 + 5, 3, 16384, 5, 3, 16384, 5, 3, 16384, 5, 3, 16384, // 5, 3 + 5, 4, 16384, 5, 4, 16384, 5, 4, 16384, 5, 4, 16384, // 5, 4 + 5, 5, 16384, 5, 5, 16384, 5, 5, 16384, 5, 5, 16384, // 5, 5 + 5, 6, 16384, 5, 6, 16384, 5, 6, 16384, 5, 6, 16384, // 5, 6 + 5, 7, 16384, 5, 7, 16384, 5, 7, 16384, 5, 7, 16384, // 5, 7 + 5, 8, 16384, 5, 8, 16384, 5, 8, 16384, 5, 8, 16384, // 5, 8 + 5, 9, 16384, 5, 9, 16384, 5, 9, 16384, 5, 9, 16384, // 5, 9 + 5, 10, 16384, 5, 10, 16384, 5, 10, 16384, 5, 10, 16384, // 5,10 + 5, 11, 16384, 5, 11, 16384, 5, 11, 16384, 5, 11, 16384, // 5,11 + 5, 12, 16384, 5, 12, 16384, 5, 12, 16384, 5, 12, 16384, // 5,12 + 5, 13, 16384, 5, 13, 16384, 5, 13, 16384, 5, 13, 16384, // 5,13 + 5, 14, 16384, 5, 14, 16384, 5, 14, 16384, 5, 14, 16384, // 5,14 + 5, 15, 16384, 5, 15, 16384, 5, 15, 16384, 5, 15, 16384, // 5,15 + 6, 0, 16384, 6, 0, 16384, 6, 0, 16384, 6, 0, 16384, // 6, 0 + 6, 1, 16384, 6, 1, 16384, 6, 1, 16384, 6, 1, 16384, // 6, 1 + 6, 2, 16384, 6, 2, 16384, 6, 2, 16384, 6, 2, 16384, // 6, 2 + 6, 3, 16384, 6, 3, 16384, 6, 3, 16384, 6, 3, 16384, // 6, 3 + 6, 4, 16384, 6, 4, 16384, 6, 4, 16384, 6, 4, 16384, // 6, 4 + 6, 5, 16384, 6, 5, 16384, 6, 5, 16384, 6, 5, 16384, // 6, 5 + 6, 6, 16384, 6, 6, 16384, 6, 6, 16384, 6, 6, 16384, // 6, 6 + 6, 7, 16384, 6, 7, 16384, 6, 7, 16384, 6, 7, 16384, // 6, 7 + 6, 8, 16384, 6, 8, 16384, 6, 8, 16384, 6, 8, 16384, // 6, 8 + 6, 9, 16384, 6, 9, 16384, 6, 9, 16384, 6, 9, 16384, // 6, 9 + 6, 10, 16384, 6, 10, 16384, 6, 10, 16384, 6, 10, 16384, // 6,10 + 6, 11, 16384, 6, 11, 16384, 6, 11, 16384, 6, 11, 16384, // 6,11 + 6, 12, 16384, 6, 12, 16384, 6, 12, 16384, 6, 12, 16384, // 6,12 + 6, 13, 16384, 6, 13, 16384, 6, 13, 16384, 6, 13, 16384, // 6,13 + 6, 14, 16384, 6, 14, 16384, 6, 14, 16384, 6, 14, 16384, // 6,14 + 6, 15, 16384, 6, 15, 16384, 6, 15, 16384, 6, 15, 16384, // 6,15 + 7, 0, 16384, 7, 0, 16384, 7, 0, 16384, 7, 0, 16384, // 7, 0 + 7, 1, 16384, 7, 1, 16384, 7, 1, 16384, 7, 1, 16384, // 7, 1 + 7, 2, 16384, 7, 2, 16384, 7, 2, 16384, 7, 2, 16384, // 7, 2 + 7, 3, 16384, 7, 3, 16384, 7, 3, 16384, 7, 3, 16384, // 7, 3 + 7, 4, 16384, 7, 4, 16384, 7, 4, 16384, 7, 4, 16384, // 7, 4 + 7, 5, 16384, 7, 5, 16384, 7, 5, 16384, 7, 5, 16384, // 7, 5 + 7, 6, 16384, 7, 6, 16384, 7, 6, 16384, 7, 6, 16384, // 7, 6 + 7, 7, 16384, 7, 7, 16384, 7, 7, 16384, 7, 7, 16384, // 7, 7 + 7, 8, 16384, 7, 8, 16384, 7, 8, 16384, 7, 8, 16384, // 7, 8 + 7, 9, 16384, 7, 9, 16384, 7, 9, 16384, 7, 9, 16384, // 7, 9 + 7, 10, 16384, 7, 10, 16384, 7, 10, 16384, 7, 10, 16384, // 7,10 + 7, 11, 16384, 7, 11, 16384, 7, 11, 16384, 7, 11, 16384, // 7,11 + 7, 12, 16384, 7, 12, 16384, 7, 12, 16384, 7, 12, 16384, // 7,12 + 7, 13, 16384, 7, 13, 16384, 7, 13, 16384, 7, 13, 16384, // 7,13 + 7, 14, 16384, 7, 14, 16384, 7, 14, 16384, 7, 14, 16384, // 7,14 + 7, 15, 16384, 7, 15, 16384, 7, 15, 16384, 7, 15, 16384, // 7,15 + 8, 0, 16384, 8, 0, 16384, 8, 0, 16384, 8, 0, 16384, // 8, 0 + 8, 1, 16384, 8, 1, 16384, 8, 1, 16384, 8, 1, 16384, // 8, 1 + 8, 2, 16384, 8, 2, 16384, 8, 2, 16384, 8, 2, 16384, // 8, 2 + 8, 3, 16384, 8, 3, 16384, 8, 3, 16384, 8, 3, 16384, // 8, 3 + 8, 4, 16384, 8, 4, 16384, 8, 4, 16384, 8, 4, 16384, // 8, 4 + 8, 5, 16384, 8, 5, 16384, 8, 5, 16384, 8, 5, 16384, // 8, 5 + 8, 6, 16384, 8, 6, 16384, 8, 6, 16384, 8, 6, 16384, // 8, 6 + 8, 7, 16384, 8, 7, 16384, 8, 7, 16384, 8, 7, 16384, // 8, 7 + 8, 8, 16384, 8, 8, 16384, 8, 8, 16384, 8, 8, 16384, // 8, 8 + 8, 9, 16384, 8, 9, 16384, 8, 9, 16384, 8, 9, 16384, // 8, 9 + 8, 10, 16384, 8, 10, 16384, 8, 10, 16384, 8, 10, 16384, // 8,10 + 8, 11, 16384, 8, 11, 16384, 8, 11, 16384, 8, 11, 16384, // 8,11 + 8, 12, 16384, 8, 12, 16384, 8, 12, 16384, 8, 12, 16384, // 8,12 + 8, 13, 16384, 8, 13, 16384, 8, 13, 16384, 8, 13, 16384, // 8,13 + 8, 14, 16384, 8, 14, 16384, 8, 14, 16384, 8, 14, 16384, // 8,14 + 8, 15, 16384, 8, 15, 16384, 8, 15, 16384, 8, 15, 16384, // 8,15 + 9, 0, 16384, 9, 0, 16384, 9, 0, 16384, 9, 0, 16384, // 9, 0 + 9, 1, 16384, 9, 1, 16384, 9, 1, 16384, 9, 1, 16384, // 9, 1 + 9, 2, 16384, 9, 2, 16384, 9, 2, 16384, 9, 2, 16384, // 9, 2 + 9, 3, 16384, 9, 3, 16384, 9, 3, 16384, 9, 3, 16384, // 9, 3 + 9, 4, 16384, 9, 4, 16384, 9, 4, 16384, 9, 4, 16384, // 9, 4 + 9, 5, 16384, 9, 5, 16384, 9, 5, 16384, 9, 5, 16384, // 9, 5 + 9, 6, 16384, 9, 6, 16384, 9, 6, 16384, 9, 6, 16384, // 9, 6 + 9, 7, 16384, 9, 7, 16384, 9, 7, 16384, 9, 7, 16384, // 9, 7 + 9, 8, 16384, 9, 8, 16384, 9, 8, 16384, 9, 8, 16384, // 9, 8 + 9, 9, 16384, 9, 9, 16384, 9, 9, 16384, 9, 9, 16384, // 9, 9 + 9, 10, 16384, 9, 10, 16384, 9, 10, 16384, 9, 10, 16384, // 9,10 + 9, 11, 16384, 9, 11, 16384, 9, 11, 16384, 9, 11, 16384, // 9,11 + 9, 12, 16384, 9, 12, 16384, 9, 12, 16384, 9, 12, 16384, // 9,12 + 9, 13, 16384, 9, 13, 16384, 9, 13, 16384, 9, 13, 16384, // 9,13 + 9, 14, 16384, 9, 14, 16384, 9, 14, 16384, 9, 14, 16384, // 9,14 + 9, 15, 16384, 9, 15, 16384, 9, 15, 16384, 9, 15, 16384, // 9,15 + 10, 0, 16384, 10, 0, 16384, 10, 0, 16384, 10, 0, 16384, // 10, 0 + 10, 1, 16384, 10, 1, 16384, 10, 1, 16384, 10, 1, 16384, // 10, 1 + 10, 2, 16384, 10, 2, 16384, 10, 2, 16384, 10, 2, 16384, // 10, 2 + 10, 3, 16384, 10, 3, 16384, 10, 3, 16384, 10, 3, 16384, // 10, 3 + 10, 4, 16384, 10, 4, 16384, 10, 4, 16384, 10, 4, 16384, // 10, 4 + 10, 5, 16384, 10, 5, 16384, 10, 5, 16384, 10, 5, 16384, // 10, 5 + 10, 6, 16384, 10, 6, 16384, 10, 6, 16384, 10, 6, 16384, // 10, 6 + 10, 7, 16384, 10, 7, 16384, 10, 7, 16384, 10, 7, 16384, // 10, 7 + 10, 8, 16384, 10, 8, 16384, 10, 8, 16384, 10, 8, 16384, // 10, 8 + 10, 9, 16384, 10, 9, 16384, 10, 9, 16384, 10, 9, 16384, // 10, 9 + 10, 10, 16384, 10, 10, 16384, 10, 10, 16384, 10, 10, 16384, // 10,10 + 10, 11, 16384, 10, 11, 16384, 10, 11, 16384, 10, 11, 16384, // 10,11 + 10, 12, 16384, 10, 12, 16384, 10, 12, 16384, 10, 12, 16384, // 10,12 + 10, 13, 16384, 10, 13, 16384, 10, 13, 16384, 10, 13, 16384, // 10,13 + 10, 14, 16384, 10, 14, 16384, 10, 14, 16384, 10, 14, 16384, // 10,14 + 10, 15, 16384, 10, 15, 16384, 10, 15, 16384, 10, 15, 16384, // 10,15 + 11, 0, 16384, 11, 0, 16384, 11, 0, 16384, 11, 0, 16384, // 11, 0 + 11, 1, 16384, 11, 1, 16384, 11, 1, 16384, 11, 1, 16384, // 11, 1 + 11, 2, 16384, 11, 2, 16384, 11, 2, 16384, 11, 2, 16384, // 11, 2 + 11, 3, 16384, 11, 3, 16384, 11, 3, 16384, 11, 3, 16384, // 11, 3 + 11, 4, 16384, 11, 4, 16384, 11, 4, 16384, 11, 4, 16384, // 11, 4 + 11, 5, 16384, 11, 5, 16384, 11, 5, 16384, 11, 5, 16384, // 11, 5 + 11, 6, 16384, 11, 6, 16384, 11, 6, 16384, 11, 6, 16384, // 11, 6 + 11, 7, 16384, 11, 7, 16384, 11, 7, 16384, 11, 7, 16384, // 11, 7 + 11, 8, 16384, 11, 8, 16384, 11, 8, 16384, 11, 8, 16384, // 11, 8 + 11, 9, 16384, 11, 9, 16384, 11, 9, 16384, 11, 9, 16384, // 11, 9 + 11, 10, 16384, 11, 10, 16384, 11, 10, 16384, 11, 10, 16384, // 11,10 + 11, 11, 16384, 11, 11, 16384, 11, 11, 16384, 11, 11, 16384, // 11,11 + 11, 12, 16384, 11, 12, 16384, 11, 12, 16384, 11, 12, 16384, // 11,12 + 11, 13, 16384, 11, 13, 16384, 11, 13, 16384, 11, 13, 16384, // 11,13 + 11, 14, 16384, 11, 14, 16384, 11, 14, 16384, 11, 14, 16384, // 11,14 + 11, 15, 16384, 11, 15, 16384, 11, 15, 16384, 11, 15, 16384, // 11,15 + 12, 0, 16384, 12, 0, 16384, 12, 0, 16384, 12, 0, 16384, // 12, 0 + 12, 1, 16384, 12, 1, 16384, 12, 1, 16384, 12, 1, 16384, // 12, 1 + 12, 2, 16384, 12, 2, 16384, 12, 2, 16384, 12, 2, 16384, // 12, 2 + 12, 3, 16384, 12, 3, 16384, 12, 3, 16384, 12, 3, 16384, // 12, 3 + 12, 4, 16384, 12, 4, 16384, 12, 4, 16384, 12, 4, 16384, // 12, 4 + 12, 5, 16384, 12, 5, 16384, 12, 5, 16384, 12, 5, 16384, // 12, 5 + 12, 6, 16384, 12, 6, 16384, 12, 6, 16384, 12, 6, 16384, // 12, 6 + 12, 7, 16384, 12, 7, 16384, 12, 7, 16384, 12, 7, 16384, // 12, 7 + 12, 8, 16384, 12, 8, 16384, 12, 8, 16384, 12, 8, 16384, // 12, 8 + 12, 9, 16384, 12, 9, 16384, 12, 9, 16384, 12, 9, 16384, // 12, 9 + 12, 10, 16384, 12, 10, 16384, 12, 10, 16384, 12, 10, 16384, // 12,10 + 12, 11, 16384, 12, 11, 16384, 12, 11, 16384, 12, 11, 16384, // 12,11 + 12, 12, 16384, 12, 12, 16384, 12, 12, 16384, 12, 12, 16384, // 12,12 + 12, 13, 16384, 12, 13, 16384, 12, 13, 16384, 12, 13, 16384, // 12,13 + 12, 14, 16384, 12, 14, 16384, 12, 14, 16384, 12, 14, 16384, // 12,14 + 12, 15, 16384, 12, 15, 16384, 12, 15, 16384, 12, 15, 16384, // 12,15 + 13, 0, 16384, 13, 0, 16384, 13, 0, 16384, 13, 0, 16384, // 13, 0 + 13, 1, 16384, 13, 1, 16384, 13, 1, 16384, 13, 1, 16384, // 13, 1 + 13, 2, 16384, 13, 2, 16384, 13, 2, 16384, 13, 2, 16384, // 13, 2 + 13, 3, 16384, 13, 3, 16384, 13, 3, 16384, 13, 3, 16384, // 13, 3 + 13, 4, 16384, 13, 4, 16384, 13, 4, 16384, 13, 4, 16384, // 13, 4 + 13, 5, 16384, 13, 5, 16384, 13, 5, 16384, 13, 5, 16384, // 13, 5 + 13, 6, 16384, 13, 6, 16384, 13, 6, 16384, 13, 6, 16384, // 13, 6 + 13, 7, 16384, 13, 7, 16384, 13, 7, 16384, 13, 7, 16384, // 13, 7 + 13, 8, 16384, 13, 8, 16384, 13, 8, 16384, 13, 8, 16384, // 13, 8 + 13, 9, 16384, 13, 9, 16384, 13, 9, 16384, 13, 9, 16384, // 13, 9 + 13, 10, 16384, 13, 10, 16384, 13, 10, 16384, 13, 10, 16384, // 13,10 + 13, 11, 16384, 13, 11, 16384, 13, 11, 16384, 13, 11, 16384, // 13,11 + 13, 12, 16384, 13, 12, 16384, 13, 12, 16384, 13, 12, 16384, // 13,12 + 13, 13, 16384, 13, 13, 16384, 13, 13, 16384, 13, 13, 16384, // 13,13 + 13, 14, 16384, 13, 14, 16384, 13, 14, 16384, 13, 14, 16384, // 13,14 + 13, 15, 16384, 13, 15, 16384, 13, 15, 16384, 13, 15, 16384, // 13,15 + 14, 0, 16384, 14, 0, 16384, 14, 0, 16384, 14, 0, 16384, // 14, 0 + 14, 1, 16384, 14, 1, 16384, 14, 1, 16384, 14, 1, 16384, // 14, 1 + 14, 2, 16384, 14, 2, 16384, 14, 2, 16384, 14, 2, 16384, // 14, 2 + 14, 3, 16384, 14, 3, 16384, 14, 3, 16384, 14, 3, 16384, // 14, 3 + 14, 4, 16384, 14, 4, 16384, 14, 4, 16384, 14, 4, 16384, // 14, 4 + 14, 5, 16384, 14, 5, 16384, 14, 5, 16384, 14, 5, 16384, // 14, 5 + 14, 6, 16384, 14, 6, 16384, 14, 6, 16384, 14, 6, 16384, // 14, 6 + 14, 7, 16384, 14, 7, 16384, 14, 7, 16384, 14, 7, 16384, // 14, 7 + 14, 8, 16384, 14, 8, 16384, 14, 8, 16384, 14, 8, 16384, // 14, 8 + 14, 9, 16384, 14, 9, 16384, 14, 9, 16384, 14, 9, 16384, // 14, 9 + 14, 10, 16384, 14, 10, 16384, 14, 10, 16384, 14, 10, 16384, // 14,10 + 14, 11, 16384, 14, 11, 16384, 14, 11, 16384, 14, 11, 16384, // 14,11 + 14, 12, 16384, 14, 12, 16384, 14, 12, 16384, 14, 12, 16384, // 14,12 + 14, 13, 16384, 14, 13, 16384, 14, 13, 16384, 14, 13, 16384, // 14,13 + 14, 14, 16384, 14, 14, 16384, 14, 14, 16384, 14, 14, 16384, // 14,14 + 14, 15, 16384, 14, 15, 16384, 14, 15, 16384, 14, 15, 16384, // 14,15 + 15, 0, 16384, 15, 0, 16384, 15, 0, 16384, 15, 0, 16384, // 15, 0 + 15, 1, 16384, 15, 1, 16384, 15, 1, 16384, 15, 1, 16384, // 15, 1 + 15, 2, 16384, 15, 2, 16384, 15, 2, 16384, 15, 2, 16384, // 15, 2 + 15, 3, 16384, 15, 3, 16384, 15, 3, 16384, 15, 3, 16384, // 15, 3 + 15, 4, 16384, 15, 4, 16384, 15, 4, 16384, 15, 4, 16384, // 15, 4 + 15, 5, 16384, 15, 5, 16384, 15, 5, 16384, 15, 5, 16384, // 15, 5 + 15, 6, 16384, 15, 6, 16384, 15, 6, 16384, 15, 6, 16384, // 15, 6 + 15, 7, 16384, 15, 7, 16384, 15, 7, 16384, 15, 7, 16384, // 15, 7 + 15, 8, 16384, 15, 8, 16384, 15, 8, 16384, 15, 8, 16384, // 15, 8 + 15, 9, 16384, 15, 9, 16384, 15, 9, 16384, 15, 9, 16384, // 15, 9 + 15, 10, 16384, 15, 10, 16384, 15, 10, 16384, 15, 10, 16384, // 15,10 + 15, 11, 16384, 15, 11, 16384, 15, 11, 16384, 15, 11, 16384, // 15,11 + 15, 12, 16384, 15, 12, 16384, 15, 12, 16384, 15, 12, 16384, // 15,12 + 15, 13, 16384, 15, 13, 16384, 15, 13, 16384, 15, 13, 16384, // 15,13 + 15, 14, 16384, 15, 14, 16384, 15, 14, 16384, 15, 14, 16384, // 15,14 + 15, 15, 16384, 15, 15, 16384, 15, 15, 16384, 15, 15, 16384, // 15,15 + // angle of 0.5 degrees + 0, -1, 5106, 0, 0, 51699, 1, -1, 3621, 1, 0, 5110, // 0, 0 + 0, 0, 4851, 0, 1, 52457, 1, 0, 3422, 1, 1, 4806, // 0, 1 + 0, 1, 4610, 0, 2, 53168, 1, 1, 3235, 1, 2, 4523, // 0, 2 + 0, 2, 4390, 0, 3, 53814, 1, 2, 3065, 1, 3, 4267, // 0, 3 + 0, 3, 4200, 0, 4, 54376, 1, 3, 2917, 1, 4, 4043, // 0, 4 + 0, 4, 4046, 0, 5, 54833, 1, 4, 2797, 1, 5, 3860, // 0, 5 + 0, 5, 3939, 0, 6, 55164, 1, 5, 2709, 1, 6, 3724, // 0, 6 + 0, 6, 3885, 0, 7, 55352, 1, 6, 2659, 1, 7, 3640, // 0, 7 + -1, 7, 2659, -1, 8, 3638, 0, 7, 3885, 0, 8, 55354, // 0, 8 + -1, 8, 2709, -1, 9, 3722, 0, 8, 3940, 0, 9, 55165, // 0, 9 + -1, 9, 2796, -1, 10, 3858, 0, 9, 4047, 0, 10, 54835, // 0,10 + -1, 10, 2916, -1, 11, 4041, 0, 10, 4201, 0, 11, 54378, // 0,11 + -1, 11, 3064, -1, 12, 4264, 0, 11, 4392, 0, 12, 53816, // 0,12 + -1, 12, 3235, -1, 13, 4521, 0, 12, 4612, 0, 13, 53168, // 0,13 + -1, 13, 3421, -1, 14, 4803, 0, 13, 4854, 0, 14, 52458, // 0,14 + -1, 14, 3621, -1, 15, 5106, 0, 14, 5110, 0, 15, 51699, // 0,15 + 1, -1, 4803, 1, 0, 52457, 2, -1, 3421, 2, 0, 4855, // 1, 0 + 1, 0, 4522, 1, 1, 53285, 2, 0, 3204, 2, 1, 4525, // 1, 1 + 1, 1, 4253, 1, 2, 54071, 2, 1, 2998, 2, 2, 4214, // 1, 2 + 1, 2, 4003, 1, 3, 54796, 2, 2, 2808, 2, 3, 3929, // 1, 3 + 1, 3, 3783, 1, 4, 55434, 2, 3, 2640, 2, 4, 3679, // 1, 4 + 1, 4, 3604, 1, 5, 55958, 2, 4, 2503, 2, 5, 3471, // 1, 5 + 1, 5, 3476, 1, 6, 56339, 2, 5, 2403, 2, 6, 3318, // 1, 6 + 1, 6, 3411, 1, 7, 56552, 2, 6, 2346, 2, 7, 3227, // 1, 7 + 0, 7, 2346, 0, 8, 3225, 1, 7, 3411, 1, 8, 56554, // 1, 8 + 0, 8, 2402, 0, 9, 3317, 1, 8, 3477, 1, 9, 56340, // 1, 9 + 0, 9, 2502, 0, 10, 3470, 1, 9, 3605, 1, 10, 55959, // 1,10 + 0, 10, 2640, 0, 11, 3677, 1, 10, 3785, 1, 11, 55434, // 1,11 + 0, 11, 2808, 0, 12, 3927, 1, 11, 4005, 1, 12, 54796, // 1,12 + 0, 12, 2998, 0, 13, 4212, 1, 12, 4255, 1, 13, 54071, // 1,13 + 0, 13, 3204, 0, 14, 4522, 1, 13, 4525, 1, 14, 53285, // 1,14 + 0, 14, 3422, 0, 15, 4851, 1, 14, 4806, 1, 15, 52457, // 1,15 + 2, -1, 4521, 2, 0, 53168, 3, -1, 3235, 3, 0, 4612, // 2, 0 + 2, 0, 4212, 2, 1, 54072, 3, 0, 2998, 3, 1, 4254, // 2, 1 + 2, 1, 3911, 2, 2, 54941, 3, 1, 2770, 3, 2, 3914, // 2, 2 + 2, 2, 3628, 2, 3, 55756, 3, 2, 2557, 3, 3, 3595, // 2, 3 + 2, 3, 3373, 2, 4, 56486, 3, 3, 2365, 3, 4, 3312, // 2, 4 + 2, 4, 3161, 2, 5, 57095, 3, 4, 2205, 3, 5, 3075, // 2, 5 + 2, 5, 3007, 2, 6, 57544, 3, 5, 2088, 3, 6, 2897, // 2, 6 + 2, 6, 2926, 2, 7, 57793, 3, 6, 2022, 3, 7, 2795, // 2, 7 + 1, 7, 2022, 1, 8, 2794, 2, 7, 2926, 2, 8, 57794, // 2, 8 + 1, 8, 2088, 1, 9, 2897, 2, 8, 3007, 2, 9, 57544, // 2, 9 + 1, 9, 2205, 1, 10, 3073, 2, 9, 3161, 2, 10, 57097, // 2,10 + 1, 10, 2365, 1, 11, 3310, 2, 10, 3374, 2, 11, 56487, // 2,11 + 1, 11, 2556, 1, 12, 3594, 2, 11, 3630, 2, 12, 55756, // 2,12 + 1, 12, 2770, 1, 13, 3911, 2, 12, 3913, 2, 13, 54942, // 2,13 + 1, 13, 2998, 1, 14, 4253, 2, 13, 4214, 2, 14, 54071, // 2,14 + 1, 14, 3235, 1, 15, 4610, 2, 14, 4523, 2, 15, 53168, // 2,15 + 3, -1, 4264, 3, 0, 53815, 4, -1, 3064, 4, 0, 4393, // 3, 0 + 3, 0, 3927, 3, 1, 54796, 4, 0, 2808, 4, 1, 4005, // 3, 1 + 3, 1, 3594, 3, 2, 55756, 4, 1, 2556, 4, 2, 3630, // 3, 2 + 3, 2, 3273, 3, 3, 56673, 4, 2, 2317, 4, 3, 3273, // 3, 3 + 3, 3, 2976, 3, 4, 57514, 4, 3, 2096, 4, 4, 2950, // 3, 4 + 3, 4, 2722, 3, 5, 58233, 4, 4, 1908, 4, 5, 2673, // 3, 5 + 3, 5, 2532, 3, 6, 58774, 4, 5, 1767, 4, 6, 2463, // 3, 6 + 3, 6, 2430, 3, 7, 59076, 4, 6, 1687, 4, 7, 2343, // 3, 7 + 2, 7, 1687, 2, 8, 2342, 3, 7, 2430, 3, 8, 59077, // 3, 8 + 2, 8, 1766, 2, 9, 2463, 3, 8, 2532, 3, 9, 58775, // 3, 9 + 2, 9, 1908, 2, 10, 2672, 3, 9, 2723, 3, 10, 58233, // 3,10 + 2, 10, 2096, 2, 11, 2948, 3, 10, 2977, 3, 11, 57515, // 3,11 + 2, 11, 2317, 2, 12, 3273, 3, 11, 3274, 3, 12, 56672, // 3,12 + 2, 12, 2557, 2, 13, 3628, 3, 12, 3595, 3, 13, 55756, // 3,13 + 2, 13, 2808, 2, 14, 4003, 3, 13, 3929, 3, 14, 54796, // 3,14 + 2, 14, 3065, 2, 15, 4390, 3, 14, 4267, 3, 15, 53814, // 3,15 + 4, -1, 4041, 4, 0, 54378, 5, -1, 2916, 5, 0, 4201, // 4, 0 + 4, 0, 3677, 4, 1, 55435, 5, 0, 2640, 5, 1, 3784, // 4, 1 + 4, 1, 3310, 4, 2, 56487, 5, 1, 2365, 5, 2, 3374, // 4, 2 + 4, 2, 2948, 4, 3, 57514, 5, 2, 2096, 5, 3, 2978, // 4, 3 + 4, 3, 2604, 4, 4, 58484, 5, 3, 1843, 5, 4, 2605, // 4, 4 + 4, 4, 2297, 4, 5, 59345, 5, 4, 1617, 5, 5, 2277, // 4, 5 + 4, 5, 2057, 4, 6, 60017, 5, 5, 1442, 5, 6, 2020, // 4, 6 + 4, 6, 1922, 4, 7, 60402, 5, 6, 1341, 5, 7, 1871, // 4, 7 + 3, 7, 1341, 3, 8, 1871, 4, 7, 1922, 4, 8, 60402, // 4, 8 + 3, 8, 1442, 3, 9, 2020, 4, 8, 2057, 4, 9, 60017, // 4, 9 + 3, 9, 1617, 3, 10, 2276, 4, 9, 2297, 4, 10, 59346, // 4,10 + 3, 10, 1843, 3, 11, 2604, 4, 10, 2605, 4, 11, 58484, // 4,11 + 3, 11, 2096, 3, 12, 2976, 4, 11, 2950, 4, 12, 57514, // 4,12 + 3, 12, 2365, 3, 13, 3373, 4, 12, 3311, 4, 13, 56487, // 4,13 + 3, 13, 2640, 3, 14, 3783, 4, 13, 3678, 4, 14, 55435, // 4,14 + 3, 14, 2917, 3, 15, 4200, 4, 14, 4043, 4, 15, 54376, // 4,15 + 5, -1, 3858, 5, 0, 54835, 6, -1, 2796, 6, 0, 4047, // 5, 0 + 5, 0, 3470, 5, 1, 55959, 6, 0, 2502, 6, 1, 3605, // 5, 1 + 5, 1, 3073, 5, 2, 57096, 6, 1, 2205, 6, 2, 3162, // 5, 2 + 5, 2, 2672, 5, 3, 58234, 6, 2, 1908, 6, 3, 2722, // 5, 3 + 5, 3, 2276, 5, 4, 59346, 6, 3, 1617, 6, 4, 2297, // 5, 4 + 5, 4, 1904, 5, 5, 60381, 6, 4, 1347, 6, 5, 1904, // 5, 5 + 5, 5, 1593, 5, 6, 61243, 6, 5, 1121, 6, 6, 1579, // 5, 6 + 5, 6, 1405, 5, 7, 61767, 6, 6, 985, 6, 7, 1379, // 5, 7 + 4, 7, 985, 4, 8, 1380, 5, 7, 1405, 5, 8, 61766, // 5, 8 + 4, 8, 1121, 4, 9, 1578, 5, 8, 1593, 5, 9, 61244, // 5, 9 + 4, 9, 1347, 4, 10, 1904, 5, 9, 1904, 5, 10, 60381, // 5,10 + 4, 10, 1617, 4, 11, 2297, 5, 10, 2276, 5, 11, 59346, // 5,11 + 4, 11, 1908, 4, 12, 2722, 5, 11, 2673, 5, 12, 58233, // 5,12 + 4, 12, 2205, 4, 13, 3161, 5, 12, 3074, 5, 13, 57096, // 5,13 + 4, 13, 2503, 4, 14, 3604, 5, 13, 3472, 5, 14, 55957, // 5,14 + 4, 14, 2797, 4, 15, 4046, 5, 14, 3860, 5, 15, 54833, // 5,15 + 6, -1, 3722, 6, 0, 55166, 7, -1, 2709, 7, 0, 3939, // 6, 0 + 6, 0, 3317, 6, 1, 56340, 7, 0, 2402, 7, 1, 3477, // 6, 1 + 6, 1, 2897, 6, 2, 57545, 7, 1, 2088, 7, 2, 3006, // 6, 2 + 6, 2, 2463, 6, 3, 58775, 7, 2, 1766, 7, 3, 2532, // 6, 3 + 6, 3, 2020, 6, 4, 60018, 7, 3, 1442, 7, 4, 2056, // 6, 4 + 6, 4, 1578, 6, 5, 61243, 7, 4, 1121, 7, 5, 1594, // 6, 5 + 6, 5, 1170, 6, 6, 62369, 7, 5, 827, 7, 6, 1170, // 6, 6 + 6, 6, 883, 6, 7, 63156, 7, 6, 622, 7, 7, 875, // 6, 7 + 5, 7, 622, 5, 8, 875, 6, 7, 883, 6, 8, 63156, // 6, 8 + 5, 8, 827, 5, 9, 1170, 6, 8, 1170, 6, 9, 62369, // 6, 9 + 5, 9, 1121, 5, 10, 1593, 6, 9, 1579, 6, 10, 61243, // 6,10 + 5, 10, 1442, 5, 11, 2057, 6, 10, 2020, 6, 11, 60017, // 6,11 + 5, 11, 1767, 5, 12, 2532, 6, 11, 2464, 6, 12, 58773, // 6,12 + 5, 12, 2088, 5, 13, 3007, 6, 12, 2898, 6, 13, 57543, // 6,13 + 5, 13, 2403, 5, 14, 3476, 6, 13, 3319, 6, 14, 56338, // 6,14 + 5, 14, 2709, 5, 15, 3939, 6, 14, 3724, 6, 15, 55164, // 6,15 + 7, -1, 3638, 7, 0, 55354, 8, -1, 2659, 8, 0, 3885, // 7, 0 + 7, 0, 3225, 7, 1, 56554, 8, 0, 2346, 8, 1, 3411, // 7, 1 + 7, 1, 2794, 7, 2, 57795, 8, 1, 2022, 8, 2, 2925, // 7, 2 + 7, 2, 2342, 7, 3, 59077, 8, 2, 1687, 8, 3, 2430, // 7, 3 + 7, 3, 1871, 7, 4, 60402, 8, 3, 1341, 8, 4, 1922, // 7, 4 + 7, 4, 1380, 7, 5, 61767, 8, 4, 985, 8, 5, 1404, // 7, 5 + 7, 5, 875, 7, 6, 63156, 8, 5, 622, 8, 6, 883, // 7, 6 + 7, 6, 399, 7, 7, 64455, 8, 6, 282, 8, 7, 400, // 7, 7 + 6, 7, 282, 6, 8, 399, 7, 7, 399, 7, 8, 64456, // 7, 8 + 6, 8, 622, 6, 9, 883, 7, 8, 875, 7, 9, 63156, // 7, 9 + 6, 9, 985, 6, 10, 1405, 7, 9, 1380, 7, 10, 61766, // 7,10 + 6, 10, 1341, 6, 11, 1922, 7, 10, 1871, 7, 11, 60402, // 7,11 + 6, 11, 1687, 6, 12, 2430, 7, 11, 2343, 7, 12, 59076, // 7,12 + 6, 12, 2022, 6, 13, 2926, 7, 12, 2795, 7, 13, 57793, // 7,13 + 6, 13, 2346, 6, 14, 3411, 7, 13, 3227, 7, 14, 56552, // 7,14 + 6, 14, 2659, 6, 15, 3885, 7, 14, 3640, 7, 15, 55352, // 7,15 + 8, 0, 55352, 8, 1, 3640, 9, 0, 3885, 9, 1, 2659, // 8, 0 + 8, 1, 56552, 8, 2, 3227, 9, 1, 3411, 9, 2, 2346, // 8, 1 + 8, 2, 57793, 8, 3, 2795, 9, 2, 2926, 9, 3, 2022, // 8, 2 + 8, 3, 59076, 8, 4, 2343, 9, 3, 2430, 9, 4, 1687, // 8, 3 + 8, 4, 60402, 8, 5, 1871, 9, 4, 1922, 9, 5, 1341, // 8, 4 + 8, 5, 61767, 8, 6, 1380, 9, 5, 1405, 9, 6, 984, // 8, 5 + 8, 6, 63156, 8, 7, 875, 9, 6, 883, 9, 7, 622, // 8, 6 + 8, 7, 64455, 8, 8, 399, 9, 7, 399, 9, 8, 283, // 8, 7 + 7, 8, 399, 7, 9, 282, 8, 8, 64455, 8, 9, 400, // 8, 8 + 7, 9, 883, 7, 10, 622, 8, 9, 63156, 8, 10, 875, // 8, 9 + 7, 10, 1405, 7, 11, 985, 8, 10, 61767, 8, 11, 1379, // 8,10 + 7, 11, 1922, 7, 12, 1341, 8, 11, 60402, 8, 12, 1871, // 8,11 + 7, 12, 2430, 7, 13, 1687, 8, 12, 59077, 8, 13, 2342, // 8,12 + 7, 13, 2926, 7, 14, 2022, 8, 13, 57795, 8, 14, 2793, // 8,13 + 7, 14, 3411, 7, 15, 2346, 8, 14, 56554, 8, 15, 3225, // 8,14 + 7, 15, 3885, 7, 16, 2659, 8, 15, 55354, 8, 16, 3638, // 8,15 + 9, 0, 55164, 9, 1, 3724, 10, 0, 3939, 10, 1, 2709, // 9, 0 + 9, 1, 56339, 9, 2, 3319, 10, 1, 3476, 10, 2, 2402, // 9, 1 + 9, 2, 57544, 9, 3, 2898, 10, 2, 3007, 10, 3, 2087, // 9, 2 + 9, 3, 58774, 9, 4, 2464, 10, 3, 2532, 10, 4, 1766, // 9, 3 + 9, 4, 60017, 9, 5, 2020, 10, 4, 2057, 10, 5, 1442, // 9, 4 + 9, 5, 61243, 9, 6, 1579, 10, 5, 1593, 10, 6, 1121, // 9, 5 + 9, 6, 62369, 9, 7, 1170, 10, 6, 1170, 10, 7, 827, // 9, 6 + 9, 7, 63156, 9, 8, 883, 10, 7, 875, 10, 8, 622, // 9, 7 + 8, 8, 875, 8, 9, 622, 9, 8, 63156, 9, 9, 883, // 9, 8 + 8, 9, 1170, 8, 10, 827, 9, 9, 62369, 9, 10, 1170, // 9, 9 + 8, 10, 1593, 8, 11, 1121, 9, 10, 61243, 9, 11, 1579, // 9,10 + 8, 11, 2057, 8, 12, 1442, 9, 11, 60018, 9, 12, 2019, // 9,11 + 8, 12, 2532, 8, 13, 1766, 9, 12, 58775, 9, 13, 2463, // 9,12 + 8, 13, 3007, 8, 14, 2088, 9, 13, 57545, 9, 14, 2896, // 9,13 + 8, 14, 3477, 8, 15, 2402, 9, 14, 56340, 9, 15, 3317, // 9,14 + 8, 15, 3940, 8, 16, 2709, 9, 15, 55166, 9, 16, 3721, // 9,15 + 10, 0, 54833, 10, 1, 3860, 11, 0, 4046, 11, 1, 2797, // 10, 0 + 10, 1, 55958, 10, 2, 3472, 11, 1, 3604, 11, 2, 2502, // 10, 1 + 10, 2, 57095, 10, 3, 3074, 11, 2, 3161, 11, 3, 2206, // 10, 2 + 10, 3, 58233, 10, 4, 2673, 11, 3, 2722, 11, 4, 1908, // 10, 3 + 10, 4, 59345, 10, 5, 2276, 11, 4, 2297, 11, 5, 1618, // 10, 4 + 10, 5, 60381, 10, 6, 1904, 11, 5, 1904, 11, 6, 1347, // 10, 5 + 10, 6, 61243, 10, 7, 1593, 11, 6, 1578, 11, 7, 1122, // 10, 6 + 10, 7, 61767, 10, 8, 1405, 11, 7, 1380, 11, 8, 984, // 10, 7 + 9, 8, 1380, 9, 9, 985, 10, 8, 61767, 10, 9, 1404, // 10, 8 + 9, 9, 1579, 9, 10, 1121, 10, 9, 61243, 10, 10, 1593, // 10, 9 + 9, 10, 1904, 9, 11, 1347, 10, 10, 60381, 10, 11, 1904, // 10,10 + 9, 11, 2297, 9, 12, 1617, 10, 11, 59346, 10, 12, 2276, // 10,11 + 9, 12, 2723, 9, 13, 1908, 10, 12, 58234, 10, 13, 2671, // 10,12 + 9, 13, 3161, 9, 14, 2205, 10, 13, 57096, 10, 14, 3074, // 10,13 + 9, 14, 3605, 9, 15, 2502, 10, 14, 55959, 10, 15, 3470, // 10,14 + 9, 15, 4047, 9, 16, 2796, 10, 15, 54835, 10, 16, 3858, // 10,15 + 11, 0, 54376, 11, 1, 4043, 12, 0, 4200, 12, 1, 2917, // 11, 0 + 11, 1, 55434, 11, 2, 3678, 12, 1, 3783, 12, 2, 2641, // 11, 1 + 11, 2, 56486, 11, 3, 3311, 12, 2, 3373, 12, 3, 2366, // 11, 2 + 11, 3, 57514, 11, 4, 2950, 12, 3, 2976, 12, 4, 2096, // 11, 3 + 11, 4, 58484, 11, 5, 2605, 12, 4, 2604, 12, 5, 1843, // 11, 4 + 11, 5, 59346, 11, 6, 2297, 12, 5, 2276, 12, 6, 1617, // 11, 5 + 11, 6, 60018, 11, 7, 2057, 12, 6, 2020, 12, 7, 1441, // 11, 6 + 11, 7, 60402, 11, 8, 1922, 12, 7, 1871, 12, 8, 1341, // 11, 7 + 10, 8, 1871, 10, 9, 1341, 11, 8, 60402, 11, 9, 1922, // 11, 8 + 10, 9, 2020, 10, 10, 1442, 11, 9, 60017, 11, 10, 2057, // 11, 9 + 10, 10, 2276, 10, 11, 1617, 11, 10, 59345, 11, 11, 2298, // 11,10 + 10, 11, 2605, 10, 12, 1843, 11, 11, 58484, 11, 12, 2604, // 11,11 + 10, 12, 2977, 10, 13, 2096, 11, 12, 57514, 11, 13, 2949, // 11,12 + 10, 13, 3374, 10, 14, 2365, 11, 13, 56487, 11, 14, 3310, // 11,13 + 10, 14, 3785, 10, 15, 2640, 11, 14, 55435, 11, 15, 3676, // 11,14 + 10, 15, 4201, 10, 16, 2916, 11, 15, 54378, 11, 16, 4041, // 11,15 + 12, 0, 53814, 12, 1, 4267, 13, 0, 4390, 13, 1, 3065, // 12, 0 + 12, 1, 54796, 12, 2, 3929, 13, 1, 4003, 13, 2, 2808, // 12, 1 + 12, 2, 55756, 12, 3, 3595, 13, 2, 3628, 13, 3, 2557, // 12, 2 + 12, 3, 56673, 12, 4, 3274, 13, 3, 3273, 13, 4, 2316, // 12, 3 + 12, 4, 57514, 12, 5, 2977, 13, 4, 2948, 13, 5, 2097, // 12, 4 + 12, 5, 58234, 12, 6, 2723, 13, 5, 2672, 13, 6, 1907, // 12, 5 + 12, 6, 58775, 12, 7, 2532, 13, 6, 2463, 13, 7, 1766, // 12, 6 + 12, 7, 59077, 12, 8, 2430, 13, 7, 2342, 13, 8, 1687, // 12, 7 + 11, 8, 2343, 11, 9, 1687, 12, 8, 59076, 12, 9, 2430, // 12, 8 + 11, 9, 2464, 11, 10, 1767, 12, 9, 58774, 12, 10, 2531, // 12, 9 + 11, 10, 2673, 11, 11, 1908, 12, 10, 58233, 12, 11, 2722, // 12,10 + 11, 11, 2950, 11, 12, 2096, 12, 11, 57514, 12, 12, 2976, // 12,11 + 11, 12, 3274, 11, 13, 2317, 12, 12, 56673, 12, 13, 3272, // 12,12 + 11, 13, 3630, 11, 14, 2556, 12, 13, 55756, 12, 14, 3594, // 12,13 + 11, 14, 4005, 11, 15, 2808, 12, 14, 54796, 12, 15, 3927, // 12,14 + 11, 15, 4392, 11, 16, 3064, 12, 15, 53815, 12, 16, 4265, // 12,15 + 13, 0, 53168, 13, 1, 4523, 14, 0, 4610, 14, 1, 3235, // 13, 0 + 13, 1, 54071, 13, 2, 4214, 14, 1, 4253, 14, 2, 2998, // 13, 1 + 13, 2, 54941, 13, 3, 3913, 14, 2, 3911, 14, 3, 2771, // 13, 2 + 13, 3, 55756, 13, 4, 3630, 14, 3, 3594, 14, 4, 2556, // 13, 3 + 13, 4, 56487, 13, 5, 3374, 14, 4, 3310, 14, 5, 2365, // 13, 4 + 13, 5, 57096, 13, 6, 3161, 14, 5, 3073, 14, 6, 2206, // 13, 5 + 13, 6, 57545, 13, 7, 3007, 14, 6, 2897, 14, 7, 2087, // 13, 6 + 13, 7, 57795, 13, 8, 2926, 14, 7, 2794, 14, 8, 2021, // 13, 7 + 12, 8, 2795, 12, 9, 2022, 13, 8, 57793, 13, 9, 2926, // 13, 8 + 12, 9, 2898, 12, 10, 2088, 13, 9, 57544, 13, 10, 3006, // 13, 9 + 12, 10, 3074, 12, 11, 2205, 13, 10, 57095, 13, 11, 3162, // 13,10 + 12, 11, 3311, 12, 12, 2365, 13, 11, 56486, 13, 12, 3374, // 13,11 + 12, 12, 3595, 12, 13, 2557, 13, 12, 55756, 13, 13, 3628, // 13,12 + 12, 13, 3913, 12, 14, 2770, 13, 13, 54941, 13, 14, 3912, // 13,13 + 12, 14, 4255, 12, 15, 2998, 13, 14, 54072, 13, 15, 4211, // 13,14 + 12, 15, 4612, 12, 16, 3235, 13, 15, 53168, 13, 16, 4521, // 13,15 + 14, 0, 52457, 14, 1, 4806, 15, 0, 4851, 15, 1, 3422, // 14, 0 + 14, 1, 53285, 14, 2, 4525, 15, 1, 4522, 15, 2, 3204, // 14, 1 + 14, 2, 54072, 14, 3, 4255, 15, 2, 4212, 15, 3, 2997, // 14, 2 + 14, 3, 54796, 14, 4, 4005, 15, 3, 3927, 15, 4, 2808, // 14, 3 + 14, 4, 55435, 14, 5, 3785, 15, 4, 3677, 15, 5, 2639, // 14, 4 + 14, 5, 55959, 14, 6, 3605, 15, 5, 3470, 15, 6, 2502, // 14, 5 + 14, 6, 56340, 14, 7, 3477, 15, 6, 3317, 15, 7, 2402, // 14, 6 + 14, 7, 56554, 14, 8, 3411, 15, 7, 3225, 15, 8, 2346, // 14, 7 + 13, 8, 3227, 13, 9, 2346, 14, 8, 56552, 14, 9, 3411, // 14, 8 + 13, 9, 3319, 13, 10, 2403, 14, 9, 56339, 14, 10, 3475, // 14, 9 + 13, 10, 3472, 13, 11, 2503, 14, 10, 55958, 14, 11, 3603, // 14,10 + 13, 11, 3678, 13, 12, 2640, 14, 11, 55434, 14, 12, 3784, // 14,11 + 13, 12, 3929, 13, 13, 2808, 14, 12, 54796, 14, 13, 4003, // 14,12 + 13, 13, 4214, 13, 14, 2998, 14, 13, 54071, 14, 14, 4253, // 14,13 + 13, 14, 4525, 13, 15, 3204, 14, 14, 53285, 14, 15, 4522, // 14,14 + 13, 15, 4854, 13, 16, 3421, 14, 15, 52457, 14, 16, 4804, // 14,15 + 15, 0, 51699, 15, 1, 5110, 16, 0, 5106, 16, 1, 3621, // 15, 0 + 15, 1, 52457, 15, 2, 4854, 16, 1, 4803, 16, 2, 3422, // 15, 1 + 15, 2, 53168, 15, 3, 4612, 16, 2, 4521, 16, 3, 3235, // 15, 2 + 15, 3, 53815, 15, 4, 4392, 16, 3, 4264, 16, 4, 3065, // 15, 3 + 15, 4, 54378, 15, 5, 4201, 16, 4, 4041, 16, 5, 2916, // 15, 4 + 15, 5, 54835, 15, 6, 4047, 16, 5, 3858, 16, 6, 2796, // 15, 5 + 15, 6, 55166, 15, 7, 3940, 16, 6, 3722, 16, 7, 2708, // 15, 6 + 15, 7, 55354, 15, 8, 3885, 16, 7, 3638, 16, 8, 2659, // 15, 7 + 14, 8, 3640, 14, 9, 2659, 15, 8, 55352, 15, 9, 3885, // 15, 8 + 14, 9, 3724, 14, 10, 2709, 15, 9, 55164, 15, 10, 3939, // 15, 9 + 14, 10, 3860, 14, 11, 2797, 15, 10, 54833, 15, 11, 4046, // 15,10 + 14, 11, 4043, 14, 12, 2917, 15, 11, 54376, 15, 12, 4200, // 15,11 + 14, 12, 4267, 14, 13, 3065, 15, 12, 53814, 15, 13, 4390, // 15,12 + 14, 13, 4523, 14, 14, 3235, 15, 13, 53168, 15, 14, 4610, // 15,13 + 14, 14, 4806, 14, 15, 3422, 15, 14, 52457, 15, 15, 4851, // 15,14 + 14, 15, 5110, 14, 16, 3621, 15, 15, 51699, 15, 16, 5106, // 15,15 + // angle of 1.0 degrees + 0, -1, 8769, 0, 0, 41693, 1, -1, 6280, 1, 0, 8794, // 0, 0 + 0, 0, 8452, 0, 1, 42821, 1, 0, 5975, 1, 1, 8288, // 0, 1 + 0, 1, 8141, 0, 2, 43900, 1, 1, 5684, 1, 2, 7811, // 0, 2 + 0, 2, 7848, 0, 3, 44901, 1, 2, 5413, 1, 3, 7374, // 0, 3 + 0, 3, 7587, 0, 4, 45791, 1, 3, 5172, 1, 4, 6986, // 0, 4 + 0, 4, 7374, 0, 5, 46532, 1, 4, 4971, 1, 5, 6659, // 0, 5 + 0, 5, 7227, 0, 6, 47086, 1, 5, 4818, 1, 6, 6405, // 0, 6 + 0, 6, 7158, 0, 7, 47426, 1, 6, 4722, 1, 7, 6230, // 0, 7 + -1, 7, 4718, -1, 8, 6217, 0, 7, 7161, 0, 8, 47440, // 0, 8 + -1, 8, 4814, -1, 9, 6391, 0, 8, 7233, 0, 9, 47098, // 0, 9 + -1, 9, 4967, -1, 10, 6644, 0, 9, 7383, 0, 10, 46542, // 0,10 + -1, 10, 5169, -1, 11, 6970, 0, 10, 7599, 0, 11, 45798, // 0,11 + -1, 11, 5410, -1, 12, 7356, 0, 11, 7863, 0, 12, 44907, // 0,12 + -1, 12, 5682, -1, 13, 7791, 0, 12, 8159, 0, 13, 43904, // 0,13 + -1, 13, 5974, -1, 14, 8265, 0, 13, 8474, 0, 14, 42823, // 0,14 + -1, 14, 6280, -1, 15, 8769, 0, 14, 8795, 0, 15, 41692, // 0,15 + 1, -1, 8265, 1, 0, 42823, 2, -1, 5974, 2, 0, 8474, // 1, 0 + 1, 0, 7901, 1, 1, 44074, 2, 0, 5640, 2, 1, 7921, // 1, 1 + 1, 1, 7539, 1, 2, 45286, 2, 1, 5316, 2, 2, 7395, // 1, 2 + 1, 2, 7191, 1, 3, 46427, 2, 2, 5011, 2, 3, 6907, // 1, 3 + 1, 3, 6875, 1, 4, 47453, 2, 3, 4736, 2, 4, 6472, // 1, 4 + 1, 4, 6613, 1, 5, 48314, 2, 4, 4505, 2, 5, 6104, // 1, 5 + 1, 5, 6425, 1, 6, 48960, 2, 5, 4330, 2, 6, 5821, // 1, 6 + 1, 6, 6332, 1, 7, 49347, 2, 6, 4224, 2, 7, 5633, // 1, 7 + 0, 7, 4221, 0, 8, 5623, 1, 7, 6335, 1, 8, 49357, // 1, 8 + 0, 8, 4327, 0, 9, 5809, 1, 8, 6430, 1, 9, 48970, // 1, 9 + 0, 9, 4502, 0, 10, 6092, 1, 9, 6620, 1, 10, 48322, // 1,10 + 0, 10, 4734, 0, 11, 6458, 1, 10, 6886, 1, 11, 47458, // 1,11 + 0, 11, 5009, 0, 12, 6892, 1, 11, 7204, 1, 12, 46431, // 1,12 + 0, 12, 5315, 0, 13, 7378, 1, 12, 7555, 1, 13, 45288, // 1,13 + 0, 13, 5640, 0, 14, 7901, 1, 13, 7921, 1, 14, 44074, // 1,14 + 0, 14, 5975, 0, 15, 8452, 1, 14, 8288, 1, 15, 42821, // 1,15 + 2, -1, 7791, 2, 0, 43904, 3, -1, 5682, 3, 0, 8159, // 2, 0 + 2, 0, 7378, 2, 1, 45288, 3, 0, 5315, 3, 1, 7555, // 2, 1 + 2, 1, 6959, 2, 2, 46650, 3, 1, 4954, 3, 2, 6973, // 2, 2 + 2, 2, 6549, 2, 3, 47953, 3, 2, 4608, 3, 3, 6426, // 2, 3 + 2, 3, 6168, 2, 4, 49147, 3, 3, 4291, 3, 4, 5930, // 2, 4 + 2, 4, 5842, 2, 5, 50165, 3, 4, 4020, 3, 5, 5509, // 2, 5 + 2, 5, 5602, 2, 6, 50935, 3, 5, 3815, 3, 6, 5184, // 2, 6 + 2, 6, 5478, 2, 7, 51387, 3, 6, 3693, 3, 7, 4978, // 2, 7 + 1, 7, 3691, 1, 8, 4970, 2, 7, 5480, 2, 8, 51395, // 2, 8 + 1, 8, 3813, 1, 9, 5175, 2, 8, 5606, 2, 9, 50942, // 2, 9 + 1, 9, 4019, 1, 10, 5499, 2, 9, 5848, 2, 10, 50170, // 2,10 + 1, 10, 4290, 1, 11, 5920, 2, 10, 6176, 2, 11, 49150, // 2,11 + 1, 11, 4607, 1, 12, 6414, 2, 11, 6560, 2, 12, 47955, // 2,12 + 1, 12, 4954, 1, 13, 6959, 2, 12, 6973, 2, 13, 46650, // 2,13 + 1, 13, 5316, 1, 14, 7539, 2, 13, 7395, 2, 14, 45286, // 2,14 + 1, 14, 5684, 1, 15, 8141, 2, 14, 7812, 2, 15, 43899, // 2,15 + 3, -1, 7356, 3, 0, 44907, 4, -1, 5410, 4, 0, 7863, // 3, 0 + 3, 0, 6892, 3, 1, 46430, 4, 0, 5009, 4, 1, 7205, // 3, 1 + 3, 1, 6414, 3, 2, 47955, 4, 1, 4607, 4, 2, 6560, // 3, 2 + 3, 2, 5934, 3, 3, 49445, 4, 2, 4214, 4, 3, 5943, // 3, 3 + 3, 3, 5474, 3, 4, 50843, 4, 3, 3846, 4, 4, 5373, // 3, 4 + 3, 4, 5069, 3, 5, 52066, 4, 4, 3523, 4, 5, 4878, // 3, 5 + 3, 5, 4759, 3, 6, 53008, 4, 5, 3274, 4, 6, 4495, // 3, 6 + 3, 6, 4592, 3, 7, 53557, 4, 6, 3128, 4, 7, 4259, // 3, 7 + 2, 7, 3126, 2, 8, 4254, 3, 7, 4594, 3, 8, 53562, // 3, 8 + 2, 8, 3273, 2, 9, 4489, 3, 8, 4762, 3, 9, 53012, // 3, 9 + 2, 9, 3522, 2, 10, 4872, 3, 9, 5073, 3, 10, 52069, // 3,10 + 2, 10, 3845, 2, 11, 5365, 3, 10, 5481, 3, 11, 50845, // 3,11 + 2, 11, 4214, 2, 12, 5934, 3, 11, 5943, 3, 12, 49445, // 3,12 + 2, 12, 4608, 2, 13, 6549, 3, 12, 6426, 3, 13, 47953, // 3,13 + 2, 13, 5011, 2, 14, 7191, 3, 13, 6908, 3, 14, 46426, // 3,14 + 2, 14, 5413, 2, 15, 7848, 3, 14, 7374, 3, 15, 44901, // 3,15 + 4, -1, 6970, 4, 0, 45799, 5, -1, 5169, 5, 0, 7598, // 4, 0 + 4, 0, 6458, 4, 1, 47458, 5, 0, 4734, 5, 1, 6886, // 4, 1 + 4, 1, 5920, 4, 2, 49150, 5, 1, 4290, 5, 2, 6176, // 4, 2 + 4, 2, 5365, 4, 3, 50844, 5, 2, 3845, 5, 3, 5482, // 4, 3 + 4, 3, 4816, 4, 4, 52484, 5, 3, 3415, 5, 4, 4821, // 4, 4 + 4, 4, 4309, 4, 5, 53973, 5, 4, 3023, 5, 5, 4231, // 4, 5 + 4, 5, 3902, 4, 6, 55164, 5, 5, 2711, 5, 6, 3759, // 4, 6 + 4, 6, 3671, 4, 7, 55867, 5, 6, 2525, 5, 7, 3473, // 4, 7 + 3, 7, 2524, 3, 8, 3469, 4, 7, 3672, 4, 8, 55871, // 4, 8 + 3, 8, 2710, 3, 9, 3755, 4, 8, 3904, 4, 9, 55167, // 4, 9 + 3, 9, 3023, 3, 10, 4226, 4, 9, 4313, 4, 10, 53974, // 4,10 + 3, 10, 3415, 3, 11, 4816, 4, 10, 4822, 4, 11, 52483, // 4,11 + 3, 11, 3846, 3, 12, 5474, 4, 11, 5373, 4, 12, 50843, // 4,12 + 3, 12, 4291, 3, 13, 6168, 4, 12, 5930, 4, 13, 49147, // 4,13 + 3, 13, 4736, 3, 14, 6875, 4, 13, 6472, 4, 14, 47453, // 4,14 + 3, 14, 5172, 3, 15, 7587, 4, 14, 6986, 4, 15, 45791, // 4,15 + 5, -1, 6644, 5, 0, 46541, 6, -1, 4967, 6, 0, 7384, // 5, 0 + 5, 0, 6092, 5, 1, 48322, 6, 0, 4502, 6, 1, 6620, // 5, 1 + 5, 1, 5499, 5, 2, 50171, 6, 1, 4019, 6, 2, 5847, // 5, 2 + 5, 2, 4872, 5, 3, 52069, 6, 2, 3522, 6, 3, 5073, // 5, 3 + 5, 3, 4226, 5, 4, 53975, 6, 3, 3023, 6, 4, 4312, // 5, 4 + 5, 4, 3595, 5, 5, 55798, 6, 4, 2546, 6, 5, 3597, // 5, 5 + 5, 5, 3050, 5, 6, 57353, 6, 5, 2138, 6, 6, 2995, // 5, 6 + 5, 6, 2713, 5, 7, 58322, 6, 6, 1884, 6, 7, 2617, // 5, 7 + 4, 7, 1884, 4, 8, 2615, 5, 7, 2714, 5, 8, 58323, // 5, 8 + 4, 8, 2138, 4, 9, 2993, 5, 8, 3051, 5, 9, 57354, // 5, 9 + 4, 9, 2546, 4, 10, 3595, 5, 9, 3598, 5, 10, 55797, // 5,10 + 4, 10, 3023, 4, 11, 4309, 5, 10, 4230, 5, 11, 53974, // 5,11 + 4, 11, 3523, 4, 12, 5069, 5, 11, 4879, 5, 12, 52065, // 5,12 + 4, 12, 4020, 4, 13, 5842, 5, 12, 5508, 5, 13, 50166, // 5,13 + 4, 13, 4505, 4, 14, 6613, 5, 13, 6104, 5, 14, 48314, // 5,14 + 4, 14, 4971, 4, 15, 7374, 5, 14, 6659, 5, 15, 46532, // 5,15 + 6, -1, 6391, 6, 0, 47098, 7, -1, 4814, 7, 0, 7233, // 6, 0 + 6, 0, 5809, 6, 1, 48969, 7, 0, 4327, 7, 1, 6431, // 6, 1 + 6, 1, 5175, 6, 2, 50942, 7, 1, 3813, 7, 2, 5606, // 6, 2 + 6, 2, 4489, 6, 3, 53012, 7, 2, 3273, 7, 3, 4762, // 6, 3 + 6, 3, 3755, 6, 4, 55166, 7, 3, 2710, 7, 4, 3905, // 6, 4 + 6, 4, 2993, 6, 5, 57354, 7, 4, 2138, 7, 5, 3051, // 6, 5 + 6, 5, 2258, 6, 6, 59422, 7, 5, 1597, 7, 6, 2259, // 6, 6 + 6, 6, 1726, 6, 7, 60905, 7, 6, 1210, 7, 7, 1695, // 6, 7 + 5, 7, 1209, 5, 8, 1695, 6, 7, 1726, 6, 8, 60906, // 6, 8 + 5, 8, 1597, 5, 9, 2258, 6, 8, 2259, 6, 9, 59422, // 6, 9 + 5, 9, 2138, 5, 10, 3050, 6, 9, 2995, 6, 10, 57353, // 6,10 + 5, 10, 2711, 5, 11, 3902, 6, 10, 3759, 6, 11, 55164, // 6,11 + 5, 11, 3274, 5, 12, 4759, 6, 11, 4495, 6, 12, 53008, // 6,12 + 5, 12, 3815, 5, 13, 5602, 6, 12, 5184, 6, 13, 50935, // 6,13 + 5, 13, 4330, 5, 14, 6425, 6, 13, 5820, 6, 14, 48961, // 6,14 + 5, 14, 4818, 5, 15, 7227, 6, 14, 6405, 6, 15, 47086, // 6,15 + 7, -1, 6217, 7, 0, 47440, 8, -1, 4718, 8, 0, 7161, // 7, 0 + 7, 0, 5623, 7, 1, 49358, 8, 0, 4221, 8, 1, 6334, // 7, 1 + 7, 1, 4970, 7, 2, 51395, 8, 1, 3691, 8, 2, 5480, // 7, 2 + 7, 2, 4254, 7, 3, 53562, 8, 2, 3126, 8, 3, 4594, // 7, 3 + 7, 3, 3469, 7, 4, 55870, 8, 3, 2524, 8, 4, 3673, // 7, 4 + 7, 4, 2615, 7, 5, 58324, 8, 4, 1884, 8, 5, 2713, // 7, 5 + 7, 5, 1695, 7, 6, 60906, 8, 5, 1209, 8, 6, 1726, // 7, 6 + 7, 6, 789, 7, 7, 63399, 8, 6, 558, 8, 7, 790, // 7, 7 + 6, 7, 558, 6, 8, 789, 7, 7, 789, 7, 8, 63400, // 7, 8 + 6, 8, 1210, 6, 9, 1726, 7, 8, 1695, 7, 9, 60905, // 7, 9 + 6, 9, 1884, 6, 10, 2713, 7, 9, 2616, 7, 10, 58323, // 7,10 + 6, 10, 2525, 6, 11, 3671, 7, 10, 3473, 7, 11, 55867, // 7,11 + 6, 11, 3128, 6, 12, 4592, 7, 11, 4259, 7, 12, 53557, // 7,12 + 6, 12, 3693, 6, 13, 5478, 7, 12, 4978, 7, 13, 51387, // 7,13 + 6, 13, 4224, 6, 14, 6332, 7, 13, 5633, 7, 14, 49347, // 7,14 + 6, 14, 4722, 6, 15, 7158, 7, 14, 6230, 7, 15, 47426, // 7,15 + 8, 0, 47426, 8, 1, 6230, 9, 0, 7158, 9, 1, 4722, // 8, 0 + 8, 1, 49347, 8, 2, 5633, 9, 1, 6332, 9, 2, 4224, // 8, 1 + 8, 2, 51387, 8, 3, 4978, 9, 2, 5478, 9, 3, 3693, // 8, 2 + 8, 3, 53557, 8, 4, 4259, 9, 3, 4592, 9, 4, 3128, // 8, 3 + 8, 4, 55867, 8, 5, 3473, 9, 4, 3671, 9, 5, 2525, // 8, 4 + 8, 5, 58322, 8, 6, 2616, 9, 5, 2713, 9, 6, 1885, // 8, 5 + 8, 6, 60905, 8, 7, 1695, 9, 6, 1726, 9, 7, 1210, // 8, 6 + 8, 7, 63399, 8, 8, 789, 9, 7, 789, 9, 8, 559, // 8, 7 + 7, 8, 789, 7, 9, 558, 8, 8, 63399, 8, 9, 790, // 8, 8 + 7, 9, 1726, 7, 10, 1209, 8, 9, 60906, 8, 10, 1695, // 8, 9 + 7, 10, 2714, 7, 11, 1884, 8, 10, 58324, 8, 11, 2614, // 8,10 + 7, 11, 3672, 7, 12, 2524, 8, 11, 55870, 8, 12, 3470, // 8,11 + 7, 12, 4594, 7, 13, 3126, 8, 12, 53562, 8, 13, 4254, // 8,12 + 7, 13, 5480, 7, 14, 3691, 8, 13, 51395, 8, 14, 4970, // 8,13 + 7, 14, 6335, 7, 15, 4221, 8, 14, 49358, 8, 15, 5622, // 8,14 + 7, 15, 7161, 7, 16, 4718, 8, 15, 47440, 8, 16, 6217, // 8,15 + 9, 0, 47086, 9, 1, 6405, 10, 0, 7227, 10, 1, 4818, // 9, 0 + 9, 1, 48960, 9, 2, 5820, 10, 1, 6425, 10, 2, 4331, // 9, 1 + 9, 2, 50935, 9, 3, 5184, 10, 2, 5602, 10, 3, 3815, // 9, 2 + 9, 3, 53008, 9, 4, 4495, 10, 3, 4759, 10, 4, 3274, // 9, 3 + 9, 4, 55164, 9, 5, 3759, 10, 4, 3902, 10, 5, 2711, // 9, 4 + 9, 5, 57353, 9, 6, 2995, 10, 5, 3050, 10, 6, 2138, // 9, 5 + 9, 6, 59422, 9, 7, 2259, 10, 6, 2258, 10, 7, 1597, // 9, 6 + 9, 7, 60906, 9, 8, 1726, 10, 7, 1695, 10, 8, 1209, // 9, 7 + 8, 8, 1695, 8, 9, 1210, 9, 8, 60905, 9, 9, 1726, // 9, 8 + 8, 9, 2259, 8, 10, 1597, 9, 9, 59422, 9, 10, 2258, // 9, 9 + 8, 10, 3051, 8, 11, 2138, 9, 10, 57354, 9, 11, 2993, // 9,10 + 8, 11, 3904, 8, 12, 2710, 9, 11, 55166, 9, 12, 3756, // 9,11 + 8, 12, 4762, 8, 13, 3273, 9, 12, 53012, 9, 13, 4489, // 9,12 + 8, 13, 5606, 8, 14, 3813, 9, 13, 50942, 9, 14, 5175, // 9,13 + 8, 14, 6430, 8, 15, 4327, 9, 14, 48969, 9, 15, 5810, // 9,14 + 8, 15, 7233, 8, 16, 4814, 9, 15, 47098, 9, 16, 6391, // 9,15 + 10, 0, 46532, 10, 1, 6659, 11, 0, 7374, 11, 1, 4971, // 10, 0 + 10, 1, 48314, 10, 2, 6104, 11, 1, 6613, 11, 2, 4505, // 10, 1 + 10, 2, 50165, 10, 3, 5508, 11, 2, 5842, 11, 3, 4021, // 10, 2 + 10, 3, 52066, 10, 4, 4879, 11, 3, 5069, 11, 4, 3522, // 10, 3 + 10, 4, 53973, 10, 5, 4230, 11, 4, 4309, 11, 5, 3024, // 10, 4 + 10, 5, 55798, 10, 6, 3598, 11, 5, 3595, 11, 6, 2545, // 10, 5 + 10, 6, 57354, 10, 7, 3051, 11, 6, 2993, 11, 7, 2138, // 10, 6 + 10, 7, 58324, 10, 8, 2714, 11, 7, 2615, 11, 8, 1883, // 10, 7 + 9, 8, 2616, 9, 9, 1884, 10, 8, 58322, 10, 9, 2714, // 10, 8 + 9, 9, 2995, 9, 10, 2138, 10, 9, 57353, 10, 10, 3050, // 10, 9 + 9, 10, 3598, 9, 11, 2546, 10, 10, 55798, 10, 11, 3594, // 10,10 + 9, 11, 4313, 9, 12, 3023, 10, 11, 53975, 10, 12, 4225, // 10,11 + 9, 12, 5073, 9, 13, 3522, 10, 12, 52069, 10, 13, 4872, // 10,12 + 9, 13, 5848, 9, 14, 4019, 10, 13, 50171, 10, 14, 5498, // 10,13 + 9, 14, 6620, 9, 15, 4502, 10, 14, 48322, 10, 15, 6092, // 10,14 + 9, 15, 7383, 9, 16, 4967, 10, 15, 46541, 10, 16, 6645, // 10,15 + 11, 0, 45791, 11, 1, 6986, 12, 0, 7587, 12, 1, 5172, // 11, 0 + 11, 1, 47453, 11, 2, 6472, 12, 1, 6875, 12, 2, 4736, // 11, 1 + 11, 2, 49147, 11, 3, 5930, 12, 2, 6168, 12, 3, 4291, // 11, 2 + 11, 3, 50843, 11, 4, 5373, 12, 3, 5474, 12, 4, 3846, // 11, 3 + 11, 4, 52484, 11, 5, 4822, 12, 4, 4816, 12, 5, 3414, // 11, 4 + 11, 5, 53975, 11, 6, 4313, 12, 5, 4226, 12, 6, 3022, // 11, 5 + 11, 6, 55166, 11, 7, 3904, 12, 6, 3755, 12, 7, 2711, // 11, 6 + 11, 7, 55870, 11, 8, 3672, 12, 7, 3469, 12, 8, 2525, // 11, 7 + 10, 8, 3473, 10, 9, 2525, 11, 8, 55867, 11, 9, 3671, // 11, 8 + 10, 9, 3759, 10, 10, 2711, 11, 9, 55164, 11, 10, 3902, // 11, 9 + 10, 10, 4230, 10, 11, 3023, 11, 10, 53973, 11, 11, 4310, // 11,10 + 10, 11, 4822, 10, 12, 3415, 11, 11, 52484, 11, 12, 4815, // 11,11 + 10, 12, 5481, 10, 13, 3845, 11, 12, 50844, 11, 13, 5366, // 11,12 + 10, 13, 6176, 10, 14, 4290, 11, 13, 49150, 11, 14, 5920, // 11,13 + 10, 14, 6886, 10, 15, 4734, 11, 14, 47458, 11, 15, 6458, // 11,14 + 10, 15, 7599, 10, 16, 5169, 11, 15, 45799, 11, 16, 6969, // 11,15 + 12, 0, 44901, 12, 1, 7374, 13, 0, 7848, 13, 1, 5413, // 12, 0 + 12, 1, 46427, 12, 2, 6908, 13, 1, 7191, 13, 2, 5010, // 12, 1 + 12, 2, 47953, 12, 3, 6426, 13, 2, 6549, 13, 3, 4608, // 12, 2 + 12, 3, 49445, 12, 4, 5943, 13, 3, 5934, 13, 4, 4214, // 12, 3 + 12, 4, 50844, 12, 5, 5481, 13, 4, 5365, 13, 5, 3846, // 12, 4 + 12, 5, 52069, 12, 6, 5073, 13, 5, 4872, 13, 6, 3522, // 12, 5 + 12, 6, 53012, 12, 7, 4762, 13, 6, 4489, 13, 7, 3273, // 12, 6 + 12, 7, 53562, 12, 8, 4594, 13, 7, 4254, 13, 8, 3126, // 12, 7 + 11, 8, 4259, 11, 9, 3128, 12, 8, 53557, 12, 9, 4592, // 12, 8 + 11, 9, 4495, 11, 10, 3274, 12, 9, 53008, 12, 10, 4759, // 12, 9 + 11, 10, 4879, 11, 11, 3523, 12, 10, 52066, 12, 11, 5068, // 12,10 + 11, 11, 5373, 11, 12, 3846, 12, 11, 50843, 12, 12, 5474, // 12,11 + 11, 12, 5943, 11, 13, 4214, 12, 12, 49445, 12, 13, 5934, // 12,12 + 11, 13, 6560, 11, 14, 4607, 12, 13, 47955, 12, 14, 6414, // 12,13 + 11, 14, 7204, 11, 15, 5009, 12, 14, 46430, 12, 15, 6893, // 12,14 + 11, 15, 7863, 11, 16, 5410, 12, 15, 44907, 12, 16, 7356, // 12,15 + 13, 0, 43900, 13, 1, 7812, 14, 0, 8141, 14, 1, 5683, // 13, 0 + 13, 1, 45286, 13, 2, 7395, 14, 1, 7539, 14, 2, 5316, // 13, 1 + 13, 2, 46650, 13, 3, 6973, 14, 2, 6959, 14, 3, 4954, // 13, 2 + 13, 3, 47955, 13, 4, 6560, 14, 3, 6414, 14, 4, 4607, // 13, 3 + 13, 4, 49150, 13, 5, 6176, 14, 4, 5920, 14, 5, 4290, // 13, 4 + 13, 5, 50171, 13, 6, 5848, 14, 5, 5499, 14, 6, 4018, // 13, 5 + 13, 6, 50942, 13, 7, 5606, 14, 6, 5175, 14, 7, 3813, // 13, 6 + 13, 7, 51395, 13, 8, 5480, 14, 7, 4970, 14, 8, 3691, // 13, 7 + 12, 8, 4978, 12, 9, 3693, 13, 8, 51387, 13, 9, 5478, // 13, 8 + 12, 9, 5184, 12, 10, 3815, 13, 9, 50935, 13, 10, 5602, // 13, 9 + 12, 10, 5508, 12, 11, 4020, 13, 10, 50165, 13, 11, 5843, // 13,10 + 12, 11, 5930, 12, 12, 4291, 13, 11, 49147, 13, 12, 6168, // 13,11 + 12, 12, 6426, 12, 13, 4608, 13, 12, 47953, 13, 13, 6549, // 13,12 + 12, 13, 6973, 12, 14, 4954, 13, 13, 46650, 13, 14, 6959, // 13,13 + 12, 14, 7555, 12, 15, 5315, 13, 14, 45288, 13, 15, 7378, // 13,14 + 12, 15, 8159, 12, 16, 5682, 13, 15, 43904, 13, 16, 7791, // 13,15 + 14, 0, 42821, 14, 1, 8288, 15, 0, 8452, 15, 1, 5975, // 14, 0 + 14, 1, 44074, 14, 2, 7921, 15, 1, 7901, 15, 2, 5640, // 14, 1 + 14, 2, 45288, 14, 3, 7555, 15, 2, 7378, 15, 3, 5315, // 14, 2 + 14, 3, 46430, 14, 4, 7204, 15, 3, 6892, 15, 4, 5010, // 14, 3 + 14, 4, 47458, 14, 5, 6886, 15, 4, 6458, 15, 5, 4734, // 14, 4 + 14, 5, 48322, 14, 6, 6620, 15, 5, 6092, 15, 6, 4502, // 14, 5 + 14, 6, 48969, 14, 7, 6430, 15, 6, 5809, 15, 7, 4328, // 14, 6 + 14, 7, 49358, 14, 8, 6335, 15, 7, 5623, 15, 8, 4220, // 14, 7 + 13, 8, 5633, 13, 9, 4224, 14, 8, 49347, 14, 9, 6332, // 14, 8 + 13, 9, 5820, 13, 10, 4330, 14, 9, 48960, 14, 10, 6426, // 14, 9 + 13, 10, 6104, 13, 11, 4505, 14, 10, 48314, 14, 11, 6613, // 14,10 + 13, 11, 6472, 13, 12, 4736, 14, 11, 47453, 14, 12, 6875, // 14,11 + 13, 12, 6908, 13, 13, 5011, 14, 12, 46427, 14, 13, 7190, // 14,12 + 13, 13, 7395, 13, 14, 5316, 14, 13, 45286, 14, 14, 7539, // 14,13 + 13, 14, 7921, 13, 15, 5640, 14, 14, 44074, 14, 15, 7901, // 14,14 + 13, 15, 8474, 13, 16, 5974, 14, 15, 42823, 14, 16, 8265, // 14,15 + 15, 0, 41693, 15, 1, 8795, 16, 0, 8769, 16, 1, 6279, // 15, 0 + 15, 1, 42823, 15, 2, 8474, 16, 1, 8265, 16, 2, 5974, // 15, 1 + 15, 2, 43904, 15, 3, 8159, 16, 2, 7791, 16, 3, 5682, // 15, 2 + 15, 3, 44907, 15, 4, 7863, 16, 3, 7356, 16, 4, 5410, // 15, 3 + 15, 4, 45799, 15, 5, 7599, 16, 4, 6970, 16, 5, 5168, // 15, 4 + 15, 5, 46541, 15, 6, 7383, 16, 5, 6644, 16, 6, 4968, // 15, 5 + 15, 6, 47098, 15, 7, 7233, 16, 6, 6391, 16, 7, 4814, // 15, 6 + 15, 7, 47440, 15, 8, 7161, 16, 7, 6217, 16, 8, 4718, // 15, 7 + 14, 8, 6230, 14, 9, 4722, 15, 8, 47426, 15, 9, 7158, // 15, 8 + 14, 9, 6405, 14, 10, 4818, 15, 9, 47086, 15, 10, 7227, // 15, 9 + 14, 10, 6659, 14, 11, 4971, 15, 10, 46532, 15, 11, 7374, // 15,10 + 14, 11, 6986, 14, 12, 5172, 15, 11, 45791, 15, 12, 7587, // 15,11 + 14, 12, 7374, 14, 13, 5413, 15, 12, 44901, 15, 13, 7848, // 15,12 + 14, 13, 7812, 14, 14, 5684, 15, 13, 43900, 15, 14, 8140, // 15,13 + 14, 14, 8288, 14, 15, 5975, 15, 14, 42821, 15, 15, 8452, // 15,14 + 14, 15, 8795, 14, 16, 6280, 15, 15, 41693, 15, 16, 8768, // 15,15 + // angle of 1.5 degrees + 0, -1, 11440, 0, 0, 34212, 1, -1, 8358, 1, 0, 11526, // 0, 0 + 0, 0, 11192, 0, 1, 35502, 1, 0, 7987, 1, 1, 10855, // 0, 1 + 0, 1, 10930, 0, 2, 36756, 1, 1, 7626, 1, 2, 10224, // 0, 2 + 0, 2, 10670, 0, 3, 37939, 1, 2, 7285, 1, 3, 9642, // 0, 3 + 0, 3, 10430, 0, 4, 39009, 1, 3, 6975, 1, 4, 9122, // 0, 4 + 0, 4, 10232, 0, 5, 39918, 1, 4, 6710, 1, 5, 8676, // 0, 5 + 0, 5, 10100, 0, 6, 40618, 1, 5, 6502, 1, 6, 8316, // 0, 6 + 0, 6, 10052, 0, 7, 41072, 1, 6, 6360, 1, 7, 8052, // 0, 7 + -1, 7, 6346, -1, 8, 8018, 0, 7, 10066, 0, 8, 41106, // 0, 8 + -1, 8, 6489, -1, 9, 8278, 0, 8, 10123, 0, 9, 40646, // 0, 9 + -1, 9, 6699, -1, 10, 8632, 0, 9, 10265, 0, 10, 39940, // 0,10 + -1, 10, 6965, -1, 11, 9072, 0, 10, 10473, 0, 11, 39026, // 0,11 + -1, 11, 7276, -1, 12, 9585, 0, 11, 10723, 0, 12, 37952, // 0,12 + -1, 12, 7620, -1, 13, 10158, 0, 12, 10994, 0, 13, 36764, // 0,13 + -1, 13, 7983, -1, 14, 10780, 0, 13, 11267, 0, 14, 35506, // 0,14 + -1, 14, 8358, -1, 15, 11440, 0, 14, 11526, 0, 15, 34212, // 0,15 + 1, -1, 10780, 1, 0, 35506, 2, -1, 7983, 2, 0, 11267, // 1, 0 + 1, 0, 10467, 1, 1, 36959, 2, 0, 7579, 2, 1, 10531, // 1, 1 + 1, 1, 10133, 1, 2, 38390, 2, 1, 7179, 2, 2, 9834, // 1, 2 + 1, 2, 9796, 1, 3, 39759, 2, 2, 6797, 2, 3, 9184, // 1, 3 + 1, 3, 9478, 1, 4, 41013, 2, 3, 6447, 2, 4, 8598, // 1, 4 + 1, 4, 9206, 1, 5, 42087, 2, 4, 6145, 2, 5, 8098, // 1, 5 + 1, 5, 9014, 1, 6, 42913, 2, 5, 5910, 2, 6, 7699, // 1, 6 + 1, 6, 8929, 1, 7, 43433, 2, 6, 5756, 2, 7, 7418, // 1, 7 + 0, 7, 5745, 0, 8, 7390, 1, 7, 8939, 1, 8, 43462, // 1, 8 + 0, 8, 5900, 0, 9, 7667, 1, 8, 9032, 1, 9, 42937, // 1, 9 + 0, 9, 6137, 0, 10, 8061, 1, 9, 9233, 1, 10, 42105, // 1,10 + 0, 10, 6440, 0, 11, 8557, 1, 10, 9513, 1, 11, 41026, // 1,11 + 0, 11, 6792, 0, 12, 9135, 1, 11, 9841, 1, 12, 39768, // 1,12 + 0, 12, 7177, 0, 13, 9777, 1, 12, 10188, 1, 13, 38394, // 1,13 + 0, 13, 7579, 0, 14, 10467, 1, 13, 10532, 1, 14, 36958, // 1,14 + 0, 14, 7987, 0, 15, 11192, 1, 14, 10855, 1, 15, 35502, // 1,15 + 2, -1, 10158, 2, 0, 36764, 3, -1, 7620, 3, 0, 10994, // 2, 0 + 2, 0, 9777, 2, 1, 38394, 3, 0, 7177, 3, 1, 10188, // 2, 1 + 2, 1, 9366, 2, 2, 40025, 3, 1, 6732, 3, 2, 9413, // 2, 2 + 2, 2, 8941, 2, 3, 41614, 3, 2, 6299, 3, 3, 8682, // 2, 3 + 2, 3, 8530, 2, 4, 43096, 3, 3, 5895, 3, 4, 8015, // 2, 4 + 2, 4, 8167, 2, 5, 44386, 3, 4, 5543, 3, 5, 7440, // 2, 5 + 2, 5, 7899, 2, 6, 45383, 3, 5, 5268, 3, 6, 6986, // 2, 6 + 2, 6, 7766, 2, 7, 45995, 3, 6, 5095, 3, 7, 6680, // 2, 7 + 1, 7, 5087, 1, 8, 6658, 2, 7, 7773, 2, 8, 46018, // 2, 8 + 1, 8, 5261, 1, 9, 6961, 2, 8, 7913, 2, 9, 45401, // 2, 9 + 1, 9, 5537, 1, 10, 7411, 2, 9, 8189, 2, 10, 44399, // 2,10 + 1, 10, 5891, 1, 11, 7981, 2, 10, 8559, 2, 11, 43105, // 2,11 + 1, 11, 6297, 1, 12, 8641, 2, 11, 8979, 2, 12, 41619, // 2,12 + 1, 12, 6732, 1, 13, 9366, 2, 12, 9413, 2, 13, 40025, // 2,13 + 1, 13, 7179, 1, 14, 10133, 2, 13, 9834, 2, 14, 38390, // 2,14 + 1, 14, 7626, 1, 15, 10930, 2, 14, 10224, 2, 15, 36756, // 2,15 + 3, -1, 9585, 3, 0, 37951, 4, -1, 7276, 4, 0, 10724, // 3, 0 + 3, 0, 9135, 3, 1, 39767, 4, 0, 6792, 4, 1, 9842, // 3, 1 + 3, 1, 8641, 3, 2, 41618, 4, 1, 6297, 4, 2, 8980, // 3, 2 + 3, 2, 8120, 3, 3, 43461, 4, 2, 5804, 4, 3, 8151, // 3, 3 + 3, 3, 7598, 3, 4, 45224, 4, 3, 5331, 4, 4, 7383, // 3, 4 + 3, 4, 7121, 3, 5, 46798, 4, 4, 4909, 4, 5, 6708, // 3, 5 + 3, 5, 6750, 3, 6, 48037, 4, 5, 4576, 4, 6, 6173, // 3, 6 + 3, 6, 6552, 3, 7, 48785, 4, 6, 4372, 4, 7, 5827, // 3, 7 + 2, 7, 4366, 2, 8, 5811, 3, 7, 6558, 3, 8, 48801, // 3, 8 + 2, 8, 4572, 2, 9, 6154, 3, 8, 6761, 3, 9, 48049, // 3, 9 + 2, 9, 4906, 2, 10, 6685, 3, 9, 7138, 3, 10, 46807, // 3,10 + 2, 10, 5330, 2, 11, 7356, 3, 10, 7622, 3, 11, 45228, // 3,11 + 2, 11, 5804, 2, 12, 8120, 3, 11, 8151, 3, 12, 43461, // 3,12 + 2, 12, 6299, 2, 13, 8941, 3, 12, 8681, 3, 13, 41615, // 3,13 + 2, 13, 6797, 2, 14, 9796, 3, 13, 9184, 3, 14, 39759, // 3,14 + 2, 14, 7285, 2, 15, 10670, 3, 14, 9642, 3, 15, 37939, // 3,15 + 4, -1, 9072, 4, 0, 39026, 5, -1, 6965, 5, 0, 10473, // 4, 0 + 4, 0, 8557, 4, 1, 41026, 5, 0, 6440, 5, 1, 9513, // 4, 1 + 4, 1, 7981, 4, 2, 43105, 5, 1, 5891, 5, 2, 8559, // 4, 2 + 4, 2, 7356, 4, 3, 45229, 5, 2, 5330, 5, 3, 7621, // 4, 3 + 4, 3, 6708, 4, 4, 47328, 5, 3, 4774, 5, 4, 6726, // 4, 4 + 4, 4, 6086, 4, 5, 49275, 5, 4, 4258, 5, 5, 5917, // 4, 5 + 4, 5, 5573, 4, 6, 50865, 5, 5, 3837, 5, 6, 5261, // 4, 6 + 4, 6, 5280, 4, 7, 51832, 5, 6, 3579, 5, 7, 4845, // 4, 7 + 3, 7, 3575, 3, 8, 4835, 4, 7, 5283, 4, 8, 51843, // 4, 8 + 3, 8, 3834, 3, 9, 5248, 4, 8, 5581, 4, 9, 50873, // 4, 9 + 3, 9, 4257, 3, 10, 5901, 4, 9, 6099, 4, 10, 49279, // 4,10 + 3, 10, 4774, 3, 11, 6708, 4, 10, 6727, 4, 11, 47327, // 4,11 + 3, 11, 5331, 3, 12, 7598, 4, 11, 7382, 4, 12, 45225, // 4,12 + 3, 12, 5895, 3, 13, 8530, 4, 12, 8015, 4, 13, 43096, // 4,13 + 3, 13, 6447, 3, 14, 9478, 4, 13, 8599, 4, 14, 41012, // 4,14 + 3, 14, 6975, 3, 15, 10430, 4, 14, 9122, 4, 15, 39009, // 4,15 + 5, -1, 8632, 5, 0, 39940, 6, -1, 6699, 6, 0, 10265, // 5, 0 + 5, 0, 8061, 5, 1, 42105, 6, 0, 6137, 6, 1, 9233, // 5, 1 + 5, 1, 7411, 5, 2, 44399, 6, 1, 5537, 6, 2, 8189, // 5, 2 + 5, 2, 6685, 5, 3, 46806, 6, 2, 4906, 6, 3, 7139, // 5, 3 + 5, 3, 5901, 5, 4, 49279, 6, 3, 4257, 6, 4, 6099, // 5, 4 + 5, 4, 5103, 5, 5, 51700, 6, 4, 3621, 6, 5, 5112, // 5, 5 + 5, 5, 4388, 5, 6, 53813, 6, 5, 3065, 6, 6, 4270, // 5, 6 + 5, 6, 3938, 5, 7, 55162, 6, 6, 2710, 6, 7, 3726, // 5, 7 + 4, 7, 2708, 4, 8, 3720, 5, 7, 3940, 5, 8, 55168, // 5, 8 + 4, 8, 3064, 4, 9, 4262, 5, 8, 4394, 5, 9, 53816, // 5, 9 + 4, 9, 3621, 4, 10, 5103, 5, 9, 5113, 5, 10, 51699, // 5,10 + 4, 10, 4258, 4, 11, 6086, 5, 10, 5917, 5, 11, 49275, // 5,11 + 4, 11, 4909, 4, 12, 7121, 5, 11, 6707, 5, 12, 46799, // 5,12 + 4, 12, 5543, 4, 13, 8167, 5, 12, 7440, 5, 13, 44386, // 5,13 + 4, 13, 6145, 4, 14, 9206, 5, 13, 8098, 5, 14, 42087, // 5,14 + 4, 14, 6710, 4, 15, 10232, 5, 14, 8676, 5, 15, 39918, // 5,15 + 6, -1, 8278, 6, 0, 40646, 7, -1, 6489, 7, 0, 10123, // 6, 0 + 6, 0, 7667, 6, 1, 42936, 7, 0, 5900, 7, 1, 9033, // 6, 1 + 6, 1, 6961, 6, 2, 45401, 7, 1, 5261, 7, 2, 7913, // 6, 2 + 6, 2, 6154, 6, 3, 48049, 7, 2, 4572, 7, 3, 6761, // 6, 3 + 6, 3, 5248, 6, 4, 50873, 7, 3, 3834, 7, 4, 5581, // 6, 4 + 6, 4, 4262, 6, 5, 53816, 7, 4, 3064, 7, 5, 4394, // 6, 5 + 6, 5, 3271, 6, 6, 56673, 7, 5, 2316, 7, 6, 3276, // 6, 6 + 6, 6, 2532, 6, 7, 58773, 7, 6, 1767, 7, 7, 2464, // 6, 7 + 5, 7, 1766, 5, 8, 2462, 6, 7, 2533, 6, 8, 58775, // 6, 8 + 5, 8, 2316, 5, 9, 3271, 6, 8, 3275, 6, 9, 56674, // 6, 9 + 5, 9, 3065, 5, 10, 4388, 6, 9, 4269, 6, 10, 53814, // 6,10 + 5, 10, 3837, 5, 11, 5573, 6, 10, 5261, 6, 11, 50865, // 6,11 + 5, 11, 4576, 5, 12, 6750, 6, 11, 6173, 6, 12, 48037, // 6,12 + 5, 12, 5268, 5, 13, 7899, 6, 12, 6986, 6, 13, 45383, // 6,13 + 5, 13, 5910, 5, 14, 9014, 6, 13, 7699, 6, 14, 42913, // 6,14 + 5, 14, 6502, 5, 15, 10100, 6, 14, 8316, 6, 15, 40618, // 6,15 + 7, -1, 8018, 7, 0, 41106, 8, -1, 6346, 8, 0, 10066, // 7, 0 + 7, 0, 7390, 7, 1, 43461, 8, 0, 5745, 8, 1, 8940, // 7, 1 + 7, 1, 6658, 7, 2, 46017, 8, 1, 5087, 8, 2, 7774, // 7, 2 + 7, 2, 5811, 7, 3, 48801, 8, 2, 4366, 8, 3, 6558, // 7, 3 + 7, 3, 4835, 7, 4, 51842, 8, 3, 3575, 8, 4, 5284, // 7, 4 + 7, 4, 3720, 7, 5, 55168, 8, 4, 2708, 8, 5, 3940, // 7, 5 + 7, 5, 2462, 7, 6, 58775, 8, 5, 1766, 8, 6, 2533, // 7, 6 + 7, 6, 1170, 7, 7, 62369, 8, 6, 827, 8, 7, 1170, // 7, 7 + 6, 7, 827, 6, 8, 1170, 7, 7, 1170, 7, 8, 62369, // 7, 8 + 6, 8, 1767, 6, 9, 2532, 7, 8, 2464, 7, 9, 58773, // 7, 9 + 6, 9, 2710, 6, 10, 3938, 7, 9, 3726, 7, 10, 55162, // 7,10 + 6, 10, 3579, 6, 11, 5280, 7, 10, 4846, 7, 11, 51831, // 7,11 + 6, 11, 4372, 6, 12, 6552, 7, 11, 5827, 7, 12, 48785, // 7,12 + 6, 12, 5095, 6, 13, 7766, 7, 12, 6680, 7, 13, 45995, // 7,13 + 6, 13, 5756, 6, 14, 8929, 7, 13, 7418, 7, 14, 43433, // 7,14 + 6, 14, 6360, 6, 15, 10052, 7, 14, 8052, 7, 15, 41072, // 7,15 + 8, 0, 41072, 8, 1, 8052, 9, 0, 10052, 9, 1, 6360, // 8, 0 + 8, 1, 43433, 8, 2, 7418, 9, 1, 8929, 9, 2, 5756, // 8, 1 + 8, 2, 45995, 8, 3, 6680, 9, 2, 7766, 9, 3, 5095, // 8, 2 + 8, 3, 48785, 8, 4, 5827, 9, 3, 6552, 9, 4, 4372, // 8, 3 + 8, 4, 51832, 8, 5, 4846, 9, 4, 5280, 9, 5, 3578, // 8, 4 + 8, 5, 55162, 8, 6, 3726, 9, 5, 3938, 9, 6, 2710, // 8, 5 + 8, 6, 58773, 8, 7, 2464, 9, 6, 2532, 9, 7, 1767, // 8, 6 + 8, 7, 62369, 8, 8, 1170, 9, 7, 1170, 9, 8, 827, // 8, 7 + 7, 8, 1170, 7, 9, 827, 8, 8, 62369, 8, 9, 1170, // 8, 8 + 7, 9, 2533, 7, 10, 1766, 8, 9, 58775, 8, 10, 2462, // 8, 9 + 7, 10, 3940, 7, 11, 2708, 8, 10, 55168, 8, 11, 3720, // 8,10 + 7, 11, 5283, 7, 12, 3575, 8, 11, 51842, 8, 12, 4836, // 8,11 + 7, 12, 6558, 7, 13, 4366, 8, 12, 48801, 8, 13, 5811, // 8,12 + 7, 13, 7773, 7, 14, 5087, 8, 13, 46017, 8, 14, 6659, // 8,13 + 7, 14, 8939, 7, 15, 5745, 8, 14, 43461, 8, 15, 7391, // 8,14 + 7, 15, 10066, 7, 16, 6346, 8, 15, 41106, 8, 16, 8018, // 8,15 + 9, 0, 40618, 9, 1, 8316, 10, 0, 10100, 10, 1, 6502, // 9, 0 + 9, 1, 42913, 9, 2, 7699, 10, 1, 9014, 10, 2, 5910, // 9, 1 + 9, 2, 45383, 9, 3, 6986, 10, 2, 7899, 10, 3, 5268, // 9, 2 + 9, 3, 48037, 9, 4, 6173, 10, 3, 6750, 10, 4, 4576, // 9, 3 + 9, 4, 50865, 9, 5, 5261, 10, 4, 5573, 10, 5, 3837, // 9, 4 + 9, 5, 53813, 9, 6, 4269, 10, 5, 4388, 10, 6, 3066, // 9, 5 + 9, 6, 56673, 9, 7, 3275, 10, 6, 3271, 10, 7, 2317, // 9, 6 + 9, 7, 58775, 9, 8, 2533, 10, 7, 2462, 10, 8, 1766, // 9, 7 + 8, 8, 2464, 8, 9, 1767, 9, 8, 58773, 9, 9, 2532, // 9, 8 + 8, 9, 3275, 8, 10, 2316, 9, 9, 56673, 9, 10, 3272, // 9, 9 + 8, 10, 4394, 8, 11, 3064, 9, 10, 53816, 9, 11, 4262, // 9,10 + 8, 11, 5581, 8, 12, 3834, 9, 11, 50873, 9, 12, 5248, // 9,11 + 8, 12, 6761, 8, 13, 4572, 9, 12, 48049, 9, 13, 6154, // 9,12 + 8, 13, 7913, 8, 14, 5261, 9, 13, 45401, 9, 14, 6961, // 9,13 + 8, 14, 9032, 8, 15, 5900, 9, 14, 42936, 9, 15, 7668, // 9,14 + 8, 15, 10123, 8, 16, 6489, 9, 15, 40646, 9, 16, 8278, // 9,15 + 10, 0, 39918, 10, 1, 8676, 11, 0, 10232, 11, 1, 6710, // 10, 0 + 10, 1, 42087, 10, 2, 8098, 11, 1, 9206, 11, 2, 6145, // 10, 1 + 10, 2, 44386, 10, 3, 7440, 11, 2, 8167, 11, 3, 5543, // 10, 2 + 10, 3, 46798, 10, 4, 6707, 11, 3, 7121, 11, 4, 4910, // 10, 3 + 10, 4, 49275, 10, 5, 5917, 11, 4, 6086, 11, 5, 4258, // 10, 4 + 10, 5, 51700, 10, 6, 5113, 11, 5, 5103, 11, 6, 3620, // 10, 5 + 10, 6, 53816, 10, 7, 4394, 11, 6, 4262, 11, 7, 3064, // 10, 6 + 10, 7, 55168, 10, 8, 3940, 11, 7, 3720, 11, 8, 2708, // 10, 7 + 9, 8, 3726, 9, 9, 2710, 10, 8, 55162, 10, 9, 3938, // 10, 8 + 9, 9, 4269, 9, 10, 3065, 10, 9, 53813, 10, 10, 4389, // 10, 9 + 9, 10, 5113, 9, 11, 3621, 10, 10, 51700, 10, 11, 5102, // 10,10 + 9, 11, 6099, 9, 12, 4257, 10, 11, 49279, 10, 12, 5901, // 10,11 + 9, 12, 7138, 9, 13, 4906, 10, 12, 46806, 10, 13, 6686, // 10,12 + 9, 13, 8189, 9, 14, 5537, 10, 13, 44399, 10, 14, 7411, // 10,13 + 9, 14, 9233, 9, 15, 6137, 10, 14, 42105, 10, 15, 8061, // 10,14 + 9, 15, 10265, 9, 16, 6699, 10, 15, 39940, 10, 16, 8632, // 10,15 + 11, 0, 39009, 11, 1, 9122, 12, 0, 10430, 12, 1, 6975, // 11, 0 + 11, 1, 41013, 11, 2, 8599, 12, 1, 9478, 12, 2, 6446, // 11, 1 + 11, 2, 43096, 11, 3, 8015, 12, 2, 8530, 12, 3, 5895, // 11, 2 + 11, 3, 45224, 11, 4, 7382, 12, 3, 7598, 12, 4, 5332, // 11, 3 + 11, 4, 47328, 11, 5, 6727, 12, 4, 6708, 12, 5, 4773, // 11, 4 + 11, 5, 49279, 11, 6, 6099, 12, 5, 5901, 12, 6, 4257, // 11, 5 + 11, 6, 50873, 11, 7, 5581, 12, 6, 5248, 12, 7, 3834, // 11, 6 + 11, 7, 51842, 11, 8, 5283, 12, 7, 4835, 12, 8, 3576, // 11, 7 + 10, 8, 4846, 10, 9, 3579, 11, 8, 51832, 11, 9, 5279, // 11, 8 + 10, 9, 5261, 10, 10, 3837, 11, 9, 50865, 11, 10, 5573, // 11, 9 + 10, 10, 5917, 10, 11, 4258, 11, 10, 49275, 11, 11, 6086, // 11,10 + 10, 11, 6727, 10, 12, 4774, 11, 11, 47328, 11, 12, 6707, // 11,11 + 10, 12, 7622, 10, 13, 5330, 11, 12, 45229, 11, 13, 7355, // 11,12 + 10, 13, 8559, 10, 14, 5891, 11, 13, 43105, 11, 14, 7981, // 11,13 + 10, 14, 9513, 10, 15, 6440, 11, 14, 41026, 11, 15, 8557, // 11,14 + 10, 15, 10473, 10, 16, 6965, 11, 15, 39026, 11, 16, 9072, // 11,15 + 12, 0, 37939, 12, 1, 9642, 13, 0, 10670, 13, 1, 7285, // 12, 0 + 12, 1, 39759, 12, 2, 9184, 13, 1, 9796, 13, 2, 6797, // 12, 1 + 12, 2, 41614, 12, 3, 8681, 13, 2, 8941, 13, 3, 6300, // 12, 2 + 12, 3, 43461, 12, 4, 8151, 13, 3, 8120, 13, 4, 5804, // 12, 3 + 12, 4, 45229, 12, 5, 7622, 13, 4, 7356, 13, 5, 5329, // 12, 4 + 12, 5, 46806, 12, 6, 7138, 13, 5, 6685, 13, 6, 4907, // 12, 5 + 12, 6, 48049, 12, 7, 6761, 13, 6, 6154, 13, 7, 4572, // 12, 6 + 12, 7, 48801, 12, 8, 6558, 13, 7, 5811, 13, 8, 4366, // 12, 7 + 11, 8, 5827, 11, 9, 4372, 12, 8, 48785, 12, 9, 6552, // 12, 8 + 11, 9, 6173, 11, 10, 4576, 12, 9, 48037, 12, 10, 6750, // 12, 9 + 11, 10, 6707, 11, 11, 4909, 12, 10, 46798, 12, 11, 7122, // 12,10 + 11, 11, 7382, 11, 12, 5331, 12, 11, 45224, 12, 12, 7599, // 12,11 + 11, 12, 8151, 11, 13, 5804, 12, 12, 43461, 12, 13, 8120, // 12,12 + 11, 13, 8979, 11, 14, 6297, 12, 13, 41618, 12, 14, 8642, // 12,13 + 11, 14, 9841, 11, 15, 6792, 12, 14, 39767, 12, 15, 9136, // 12,14 + 11, 15, 10723, 11, 16, 7276, 12, 15, 37951, 12, 16, 9586, // 12,15 + 13, 0, 36756, 13, 1, 10224, 14, 0, 10930, 14, 1, 7626, // 13, 0 + 13, 1, 38390, 13, 2, 9834, 14, 1, 10133, 14, 2, 7179, // 13, 1 + 13, 2, 40025, 13, 3, 9413, 14, 2, 9366, 14, 3, 6732, // 13, 2 + 13, 3, 41618, 13, 4, 8979, 14, 3, 8641, 14, 4, 6298, // 13, 3 + 13, 4, 43105, 13, 5, 8559, 14, 4, 7981, 14, 5, 5891, // 13, 4 + 13, 5, 44399, 13, 6, 8189, 14, 5, 7411, 14, 6, 5537, // 13, 5 + 13, 6, 45401, 13, 7, 7913, 14, 6, 6961, 14, 7, 5261, // 13, 6 + 13, 7, 46017, 13, 8, 7773, 14, 7, 6658, 14, 8, 5088, // 13, 7 + 12, 8, 6680, 12, 9, 5095, 13, 8, 45995, 13, 9, 7766, // 13, 8 + 12, 9, 6986, 12, 10, 5268, 13, 9, 45383, 13, 10, 7899, // 13, 9 + 12, 10, 7440, 12, 11, 5543, 13, 10, 44386, 13, 11, 8167, // 13,10 + 12, 11, 8015, 12, 12, 5895, 13, 11, 43096, 13, 12, 8530, // 13,11 + 12, 12, 8681, 12, 13, 6299, 13, 12, 41614, 13, 13, 8942, // 13,12 + 12, 13, 9413, 12, 14, 6732, 13, 13, 40025, 13, 14, 9366, // 13,13 + 12, 14, 10188, 12, 15, 7177, 13, 14, 38394, 13, 15, 9777, // 13,14 + 12, 15, 10994, 12, 16, 7620, 13, 15, 36764, 13, 16, 10158, // 13,15 + 14, 0, 35502, 14, 1, 10855, 15, 0, 11192, 15, 1, 7987, // 14, 0 + 14, 1, 36959, 14, 2, 10532, 15, 1, 10467, 15, 2, 7578, // 14, 1 + 14, 2, 38394, 14, 3, 10188, 15, 2, 9777, 15, 3, 7177, // 14, 2 + 14, 3, 39767, 14, 4, 9841, 15, 3, 9135, 15, 4, 6793, // 14, 3 + 14, 4, 41026, 14, 5, 9513, 15, 4, 8557, 15, 5, 6440, // 14, 4 + 14, 5, 42105, 14, 6, 9233, 15, 5, 8061, 15, 6, 6137, // 14, 5 + 14, 6, 42936, 14, 7, 9032, 15, 6, 7667, 15, 7, 5901, // 14, 6 + 14, 7, 43461, 14, 8, 8939, 15, 7, 7390, 15, 8, 5746, // 14, 7 + 13, 8, 7418, 13, 9, 5756, 14, 8, 43433, 14, 9, 8929, // 14, 8 + 13, 9, 7699, 13, 10, 5910, 14, 9, 42913, 14, 10, 9014, // 14, 9 + 13, 10, 8098, 13, 11, 6145, 14, 10, 42087, 14, 11, 9206, // 14,10 + 13, 11, 8599, 13, 12, 6447, 14, 11, 41013, 14, 12, 9477, // 14,11 + 13, 12, 9184, 13, 13, 6797, 14, 12, 39759, 14, 13, 9796, // 14,12 + 13, 13, 9834, 13, 14, 7179, 14, 13, 38390, 14, 14, 10133, // 14,13 + 13, 14, 10532, 13, 15, 7579, 14, 14, 36959, 14, 15, 10466, // 14,14 + 13, 15, 11267, 13, 16, 7983, 14, 15, 35506, 14, 16, 10780, // 14,15 + 15, 0, 34212, 15, 1, 11526, 16, 0, 11440, 16, 1, 8358, // 15, 0 + 15, 1, 35506, 15, 2, 11267, 16, 1, 10780, 16, 2, 7983, // 15, 1 + 15, 2, 36764, 15, 3, 10994, 16, 2, 10158, 16, 3, 7620, // 15, 2 + 15, 3, 37951, 15, 4, 10723, 16, 3, 9585, 16, 4, 7277, // 15, 3 + 15, 4, 39026, 15, 5, 10473, 16, 4, 9072, 16, 5, 6965, // 15, 4 + 15, 5, 39940, 15, 6, 10265, 16, 5, 8632, 16, 6, 6699, // 15, 5 + 15, 6, 40646, 15, 7, 10123, 16, 6, 8278, 16, 7, 6489, // 15, 6 + 15, 7, 41106, 15, 8, 10066, 16, 7, 8018, 16, 8, 6346, // 15, 7 + 14, 8, 8052, 14, 9, 6360, 15, 8, 41072, 15, 9, 10052, // 15, 8 + 14, 9, 8316, 14, 10, 6502, 15, 9, 40618, 15, 10, 10100, // 15, 9 + 14, 10, 8676, 14, 11, 6710, 15, 10, 39918, 15, 11, 10232, // 15,10 + 14, 11, 9122, 14, 12, 6975, 15, 11, 39009, 15, 12, 10430, // 15,11 + 14, 12, 9642, 14, 13, 7285, 15, 12, 37939, 15, 13, 10670, // 15,12 + 14, 13, 10224, 14, 14, 7626, 15, 13, 36756, 15, 14, 10930, // 15,13 + 14, 14, 10855, 14, 15, 7987, 15, 14, 35502, 15, 15, 11192, // 15,14 + 14, 15, 11526, 14, 16, 8358, 15, 15, 34212, 15, 16, 11440, // 15,15 + // angle of 2.0 degrees + 0, -1, 13368, 0, 0, 28495, 1, -1, 10104, 1, 0, 13569, // 0, 0 + 0, 0, 13291, 0, 1, 29828, 1, 0, 9671, 1, 1, 12746, // 0, 1 + 0, 1, 13176, 0, 2, 31138, 1, 1, 9245, 1, 2, 11977, // 0, 2 + 0, 2, 13038, 0, 3, 32391, 1, 2, 8838, 1, 3, 11269, // 0, 3 + 0, 3, 12899, 0, 4, 33539, 1, 3, 8463, 1, 4, 10635, // 0, 4 + 0, 4, 12783, 0, 5, 34532, 1, 4, 8135, 1, 5, 10086, // 0, 5 + 0, 5, 12717, 0, 6, 35315, 1, 5, 7868, 1, 6, 9636, // 0, 6 + 0, 6, 12728, 0, 7, 35844, 1, 6, 7674, 1, 7, 9290, // 0, 7 + -1, 7, 7643, -1, 8, 9224, 0, 7, 12764, 0, 8, 35905, // 0, 8 + -1, 8, 7839, -1, 9, 9558, 0, 8, 12777, 0, 9, 35362, // 0, 9 + -1, 9, 8107, -1, 10, 9995, 0, 9, 12867, 0, 10, 34567, // 0,10 + -1, 10, 8438, -1, 11, 10528, 0, 10, 13007, 0, 11, 33563, // 0,11 + -1, 11, 8816, -1, 12, 11143, 0, 11, 13171, 0, 12, 32406, // 0,12 + -1, 12, 9229, -1, 13, 11829, 0, 12, 13332, 0, 13, 31146, // 0,13 + -1, 13, 9662, -1, 14, 12574, 0, 13, 13470, 0, 14, 29830, // 0,14 + -1, 14, 10104, -1, 15, 13368, 0, 14, 13569, 0, 15, 28495, // 0,15 + 1, -1, 12574, 1, 0, 29831, 2, -1, 9662, 2, 0, 13469, // 1, 0 + 1, 0, 12412, 1, 1, 31358, 2, 0, 9202, 2, 1, 12564, // 1, 1 + 1, 1, 12203, 1, 2, 32881, 2, 1, 8742, 2, 2, 11710, // 1, 2 + 1, 2, 11964, 1, 3, 34358, 2, 2, 8296, 2, 3, 10918, // 1, 3 + 1, 3, 11721, 1, 4, 35730, 2, 3, 7881, 2, 4, 10204, // 1, 4 + 1, 4, 11507, 1, 5, 36926, 2, 4, 7517, 2, 5, 9586, // 1, 5 + 1, 5, 11360, 1, 6, 37866, 2, 5, 7224, 2, 6, 9086, // 1, 6 + 1, 6, 11317, 1, 7, 38481, 2, 6, 7020, 2, 7, 8718, // 1, 7 + 0, 7, 6997, 0, 8, 8662, 1, 7, 11344, 1, 8, 38533, // 1, 8 + 0, 8, 7202, 0, 9, 9020, 1, 8, 11407, 1, 9, 37907, // 1, 9 + 0, 9, 7497, 0, 10, 9509, 1, 9, 11575, 1, 10, 36955, // 1,10 + 0, 10, 7865, 0, 11, 10111, 1, 10, 11810, 1, 11, 35750, // 1,11 + 0, 11, 8284, 0, 12, 10808, 1, 11, 12074, 1, 12, 34370, // 1,12 + 0, 12, 8735, 0, 13, 11580, 1, 12, 12334, 1, 13, 32887, // 1,13 + 0, 13, 9202, 0, 14, 12412, 1, 13, 12564, 1, 14, 31358, // 1,14 + 0, 14, 9671, 0, 15, 13291, 1, 14, 12746, 1, 15, 29828, // 1,15 + 2, -1, 11829, 2, 0, 31146, 3, -1, 9229, 3, 0, 13332, // 2, 0 + 2, 0, 11580, 2, 1, 32886, 3, 0, 8735, 3, 1, 12335, // 2, 1 + 2, 1, 11272, 2, 2, 34650, 3, 1, 8232, 3, 2, 11382, // 2, 2 + 2, 2, 10922, 2, 3, 36392, 3, 2, 7734, 3, 3, 10488, // 2, 3 + 2, 3, 10559, 2, 4, 38042, 3, 3, 7261, 3, 4, 9674, // 2, 4 + 2, 4, 10226, 2, 5, 39503, 3, 4, 6842, 3, 5, 8965, // 2, 5 + 2, 5, 9977, 2, 6, 40656, 3, 5, 6506, 3, 6, 8397, // 2, 6 + 2, 6, 9867, 2, 7, 41389, 3, 6, 6284, 3, 7, 7996, // 2, 7 + 1, 7, 6266, 1, 8, 7951, 2, 7, 9886, 2, 8, 41433, // 2, 8 + 1, 8, 6491, 1, 9, 8344, 2, 8, 10013, 2, 9, 40688, // 2, 9 + 1, 9, 6829, 1, 10, 8902, 2, 9, 10279, 2, 10, 39526, // 2,10 + 1, 10, 7252, 1, 11, 9597, 2, 10, 10630, 2, 11, 38057, // 2,11 + 1, 11, 7728, 1, 12, 10397, 2, 11, 11012, 2, 12, 36399, // 2,12 + 1, 12, 8232, 1, 13, 11272, 2, 12, 11382, 2, 13, 34650, // 2,13 + 1, 13, 8742, 1, 14, 12203, 2, 13, 11709, 2, 14, 32882, // 2,14 + 1, 14, 9245, 1, 15, 13176, 2, 14, 11977, 2, 15, 31138, // 2,15 + 3, -1, 11143, 3, 0, 32406, 4, -1, 8816, 4, 0, 13171, // 3, 0 + 3, 0, 10808, 3, 1, 34369, 4, 0, 8284, 4, 1, 12075, // 3, 1 + 3, 1, 10397, 3, 2, 36399, 4, 1, 7728, 4, 2, 11012, // 3, 2 + 3, 2, 9924, 3, 3, 38450, 4, 2, 7164, 4, 3, 9998, // 3, 3 + 3, 3, 9421, 3, 4, 40444, 4, 3, 6615, 4, 4, 9056, // 3, 4 + 3, 4, 8940, 3, 5, 42256, 4, 4, 6116, 4, 5, 8224, // 3, 5 + 3, 5, 8558, 3, 6, 43710, 4, 5, 5712, 4, 6, 7556, // 3, 6 + 3, 6, 8359, 3, 7, 44616, 4, 6, 5454, 4, 7, 7107, // 3, 7 + 2, 7, 5443, 2, 8, 7072, 3, 7, 8373, 3, 8, 44648, // 3, 8 + 2, 8, 5703, 2, 9, 7516, 3, 8, 8584, 3, 9, 43733, // 3, 9 + 2, 9, 6108, 2, 10, 8175, 3, 9, 8982, 3, 10, 42271, // 3,10 + 2, 10, 6611, 2, 11, 8995, 3, 10, 9478, 3, 11, 40452, // 3,11 + 2, 11, 7164, 2, 12, 9924, 3, 11, 9998, 3, 12, 38450, // 3,12 + 2, 12, 7734, 2, 13, 10922, 3, 12, 10488, 3, 13, 36392, // 3,13 + 2, 13, 8296, 2, 14, 11964, 3, 13, 10918, 3, 14, 34358, // 3,14 + 2, 14, 8838, 2, 15, 13038, 3, 14, 11269, 3, 15, 32391, // 3,15 + 4, -1, 10528, 4, 0, 33564, 5, -1, 8438, 5, 0, 13006, // 4, 0 + 4, 0, 10111, 4, 1, 35750, 5, 0, 7865, 5, 1, 11810, // 4, 1 + 4, 1, 9597, 4, 2, 38057, 5, 1, 7252, 5, 2, 10630, // 4, 2 + 4, 2, 8995, 4, 3, 40452, 5, 2, 6611, 5, 3, 9478, // 4, 3 + 4, 3, 8332, 4, 4, 42861, 5, 3, 5965, 5, 4, 8378, // 4, 4 + 4, 4, 7667, 4, 5, 45139, 5, 4, 5353, 5, 5, 7377, // 4, 5 + 4, 5, 7100, 4, 6, 47035, 5, 5, 4843, 5, 6, 6558, // 4, 6 + 4, 6, 6774, 4, 7, 48218, 5, 6, 4521, 5, 7, 6023, // 4, 7 + 3, 7, 4513, 3, 8, 6000, 4, 7, 6783, 4, 8, 48240, // 4, 8 + 3, 8, 4838, 3, 9, 6530, 4, 8, 7119, 4, 9, 47049, // 4, 9 + 3, 9, 5350, 3, 10, 7342, 4, 9, 7698, 4, 10, 45146, // 4,10 + 3, 10, 5965, 3, 11, 8332, 4, 10, 8378, 4, 11, 42861, // 4,11 + 3, 11, 6615, 3, 12, 9421, 4, 11, 9056, 4, 12, 40444, // 4,12 + 3, 12, 7261, 3, 13, 10559, 4, 12, 9674, 4, 13, 38042, // 4,13 + 3, 13, 7881, 3, 14, 11721, 4, 13, 10204, 4, 14, 35730, // 4,14 + 3, 14, 8463, 3, 15, 12899, 4, 14, 10635, 4, 15, 33539, // 4,15 + 5, -1, 9995, 5, 0, 34567, 6, -1, 8107, 6, 0, 12867, // 5, 0 + 5, 0, 9509, 5, 1, 36955, 6, 0, 7497, 6, 1, 11575, // 5, 1 + 5, 1, 8902, 5, 2, 39526, 6, 1, 6829, 6, 2, 10279, // 5, 2 + 5, 2, 8175, 5, 3, 42271, 6, 2, 6108, 6, 3, 8982, // 5, 3 + 5, 3, 7342, 5, 4, 45146, 6, 3, 5350, 6, 4, 7698, // 5, 4 + 5, 4, 6451, 5, 5, 48019, 6, 4, 4591, 6, 5, 6475, // 5, 5 + 5, 5, 5624, 5, 6, 50581, 6, 5, 3913, 6, 6, 5418, // 5, 6 + 5, 6, 5092, 5, 7, 52253, 6, 6, 3470, 6, 7, 4721, // 5, 7 + 4, 7, 3466, 4, 8, 4708, 5, 7, 5097, 5, 8, 52265, // 5, 8 + 4, 8, 3911, 4, 9, 5400, 5, 8, 5637, 5, 9, 50588, // 5, 9 + 4, 9, 4591, 4, 10, 6451, 5, 9, 6475, 5, 10, 48019, // 5,10 + 4, 10, 5353, 4, 11, 7667, 5, 10, 7377, 5, 11, 45139, // 5,11 + 4, 11, 6116, 4, 12, 8940, 5, 11, 8224, 5, 12, 42256, // 5,12 + 4, 12, 6842, 4, 13, 10226, 5, 12, 8966, 5, 13, 39502, // 5,13 + 4, 13, 7517, 4, 14, 11507, 5, 13, 9587, 5, 14, 36925, // 5,14 + 4, 14, 8135, 4, 15, 12783, 5, 14, 10086, 5, 15, 34532, // 5,15 + 6, -1, 9558, 6, 0, 35362, 7, -1, 7839, 7, 0, 12777, // 6, 0 + 6, 0, 9020, 6, 1, 37906, 7, 0, 7202, 7, 1, 11408, // 6, 1 + 6, 1, 8344, 6, 2, 40688, 7, 1, 6491, 7, 2, 10013, // 6, 2 + 6, 2, 7516, 6, 3, 43733, 7, 2, 5703, 7, 3, 8584, // 6, 3 + 6, 3, 6530, 6, 4, 47049, 7, 3, 4838, 7, 4, 7119, // 6, 4 + 6, 4, 5400, 6, 5, 50587, 7, 4, 3911, 7, 5, 5638, // 6, 5 + 6, 5, 4217, 6, 6, 54105, 7, 5, 2989, 7, 6, 4225, // 6, 6 + 6, 6, 3303, 6, 7, 56751, 7, 6, 2295, 7, 7, 3187, // 6, 7 + 5, 7, 2294, 5, 8, 3180, 6, 7, 3306, 6, 8, 56756, // 6, 8 + 5, 8, 2989, 5, 9, 4217, 6, 8, 4225, 6, 9, 54105, // 6, 9 + 5, 9, 3913, 5, 10, 5624, 6, 9, 5418, 6, 10, 50581, // 6,10 + 5, 10, 4843, 5, 11, 7100, 6, 10, 6558, 6, 11, 47035, // 6,11 + 5, 11, 5712, 5, 12, 8558, 6, 11, 7556, 6, 12, 43710, // 6,12 + 5, 12, 6506, 5, 13, 9977, 6, 12, 8397, 6, 13, 40656, // 6,13 + 5, 13, 7224, 5, 14, 11360, 6, 13, 9086, 6, 14, 37866, // 6,14 + 5, 14, 7868, 5, 15, 12717, 6, 14, 9635, 6, 15, 35316, // 6,15 + 7, -1, 9224, 7, 0, 35905, 8, -1, 7643, 8, 0, 12764, // 7, 0 + 7, 0, 8662, 7, 1, 38534, 8, 0, 6997, 8, 1, 11343, // 7, 1 + 7, 1, 7951, 7, 2, 41432, 8, 1, 6266, 8, 2, 9887, // 7, 2 + 7, 2, 7072, 7, 3, 44649, 8, 2, 5443, 8, 3, 8372, // 7, 3 + 7, 3, 6000, 7, 4, 48240, 8, 3, 4513, 8, 4, 6783, // 7, 4 + 7, 4, 4708, 7, 5, 52266, 8, 4, 3466, 8, 5, 5096, // 7, 5 + 7, 5, 3180, 7, 6, 56756, 8, 5, 2294, 8, 6, 3306, // 7, 6 + 7, 6, 1541, 7, 7, 61364, 8, 6, 1090, 8, 7, 1541, // 7, 7 + 6, 7, 1090, 6, 8, 1541, 7, 7, 1542, 7, 8, 61363, // 7, 8 + 6, 8, 2295, 6, 9, 3303, 7, 8, 3186, 7, 9, 56752, // 7, 9 + 6, 9, 3470, 6, 10, 5092, 7, 9, 4721, 7, 10, 52253, // 7,10 + 6, 10, 4521, 6, 11, 6774, 7, 10, 6023, 7, 11, 48218, // 7,11 + 6, 11, 5454, 6, 12, 8359, 7, 11, 7106, 7, 12, 44617, // 7,12 + 6, 12, 6284, 6, 13, 9867, 7, 12, 7996, 7, 13, 41389, // 7,13 + 6, 13, 7020, 6, 14, 11317, 7, 13, 8718, 7, 14, 38481, // 7,14 + 6, 14, 7674, 6, 15, 12728, 7, 14, 9290, 7, 15, 35844, // 7,15 + 8, 0, 35844, 8, 1, 9290, 9, 0, 12728, 9, 1, 7674, // 8, 0 + 8, 1, 38481, 8, 2, 8718, 9, 1, 11317, 9, 2, 7020, // 8, 1 + 8, 2, 41389, 8, 3, 7996, 9, 2, 9867, 9, 3, 6284, // 8, 2 + 8, 3, 44616, 8, 4, 7106, 9, 3, 8359, 9, 4, 5455, // 8, 3 + 8, 4, 48218, 8, 5, 6023, 9, 4, 6774, 9, 5, 4521, // 8, 4 + 8, 5, 52253, 8, 6, 4721, 9, 5, 5092, 9, 6, 3470, // 8, 5 + 8, 6, 56751, 8, 7, 3186, 9, 6, 3303, 9, 7, 2296, // 8, 6 + 8, 7, 61364, 8, 8, 1542, 9, 7, 1541, 9, 8, 1089, // 8, 7 + 7, 8, 1542, 7, 9, 1090, 8, 8, 61364, 8, 9, 1540, // 8, 8 + 7, 9, 3306, 7, 10, 2294, 8, 9, 56756, 8, 10, 3180, // 8, 9 + 7, 10, 5097, 7, 11, 3466, 8, 10, 52266, 8, 11, 4707, // 8,10 + 7, 11, 6783, 7, 12, 4513, 8, 11, 48240, 8, 12, 6000, // 8,11 + 7, 12, 8373, 7, 13, 5443, 8, 12, 44649, 8, 13, 7071, // 8,12 + 7, 13, 9886, 7, 14, 6266, 8, 13, 41432, 8, 14, 7952, // 8,13 + 7, 14, 11344, 7, 15, 6997, 8, 14, 38534, 8, 15, 8661, // 8,14 + 7, 15, 12764, 7, 16, 7643, 8, 15, 35905, 8, 16, 9224, // 8,15 + 9, 0, 35315, 9, 1, 9635, 10, 0, 12717, 10, 1, 7869, // 9, 0 + 9, 1, 37866, 9, 2, 9086, 10, 1, 11360, 10, 2, 7224, // 9, 1 + 9, 2, 40656, 9, 3, 8397, 10, 2, 9977, 10, 3, 6506, // 9, 2 + 9, 3, 43710, 9, 4, 7556, 10, 3, 8558, 10, 4, 5712, // 9, 3 + 9, 4, 47035, 9, 5, 6558, 10, 4, 7100, 10, 5, 4843, // 9, 4 + 9, 5, 50581, 9, 6, 5418, 10, 5, 5624, 10, 6, 3913, // 9, 5 + 9, 6, 54105, 9, 7, 4225, 10, 6, 4217, 10, 7, 2989, // 9, 6 + 9, 7, 56756, 9, 8, 3306, 10, 7, 3180, 10, 8, 2294, // 9, 7 + 8, 8, 3186, 8, 9, 2295, 9, 8, 56751, 9, 9, 3304, // 9, 8 + 8, 9, 4225, 8, 10, 2989, 9, 9, 54105, 9, 10, 4217, // 9, 9 + 8, 10, 5637, 8, 11, 3911, 9, 10, 50587, 9, 11, 5401, // 9,10 + 8, 11, 7119, 8, 12, 4838, 9, 11, 47049, 9, 12, 6530, // 9,11 + 8, 12, 8584, 8, 13, 5703, 9, 12, 43733, 9, 13, 7516, // 9,12 + 8, 13, 10013, 8, 14, 6491, 9, 13, 40688, 9, 14, 8344, // 9,13 + 8, 14, 11407, 8, 15, 7202, 9, 14, 37906, 9, 15, 9021, // 9,14 + 8, 15, 12777, 8, 16, 7839, 9, 15, 35362, 9, 16, 9558, // 9,15 + 10, 0, 34532, 10, 1, 10086, 11, 0, 12783, 11, 1, 8135, // 10, 0 + 10, 1, 36926, 10, 2, 9587, 11, 1, 11507, 11, 2, 7516, // 10, 1 + 10, 2, 39503, 10, 3, 8966, 11, 2, 10226, 11, 3, 6841, // 10, 2 + 10, 3, 42256, 10, 4, 8224, 11, 3, 8940, 11, 4, 6116, // 10, 3 + 10, 4, 45139, 10, 5, 7377, 11, 4, 7667, 11, 5, 5353, // 10, 4 + 10, 5, 48019, 10, 6, 6475, 11, 5, 6451, 11, 6, 4591, // 10, 5 + 10, 6, 50587, 10, 7, 5637, 11, 6, 5400, 11, 7, 3912, // 10, 6 + 10, 7, 52266, 10, 8, 5097, 11, 7, 4708, 11, 8, 3465, // 10, 7 + 9, 8, 4721, 9, 9, 3470, 10, 8, 52253, 10, 9, 5092, // 10, 8 + 9, 9, 5418, 9, 10, 3913, 10, 9, 50581, 10, 10, 5624, // 10, 9 + 9, 10, 6475, 9, 11, 4591, 10, 10, 48019, 10, 11, 6451, // 10,10 + 9, 11, 7698, 9, 12, 5350, 10, 11, 45146, 10, 12, 7342, // 10,11 + 9, 12, 8982, 9, 13, 6108, 10, 12, 42271, 10, 13, 8175, // 10,12 + 9, 13, 10279, 9, 14, 6829, 10, 13, 39526, 10, 14, 8902, // 10,13 + 9, 14, 11575, 9, 15, 7497, 10, 14, 36955, 10, 15, 9509, // 10,14 + 9, 15, 12867, 9, 16, 8107, 10, 15, 34567, 10, 16, 9995, // 10,15 + 11, 0, 33539, 11, 1, 10635, 12, 0, 12899, 12, 1, 8463, // 11, 0 + 11, 1, 35730, 11, 2, 10204, 12, 1, 11721, 12, 2, 7881, // 11, 1 + 11, 2, 38042, 11, 3, 9674, 12, 2, 10559, 12, 3, 7261, // 11, 2 + 11, 3, 40444, 11, 4, 9056, 12, 3, 9421, 12, 4, 6615, // 11, 3 + 11, 4, 42861, 11, 5, 8378, 12, 4, 8332, 12, 5, 5965, // 11, 4 + 11, 5, 45146, 11, 6, 7698, 12, 5, 7342, 12, 6, 5350, // 11, 5 + 11, 6, 47049, 11, 7, 7119, 12, 6, 6530, 12, 7, 4838, // 11, 6 + 11, 7, 48240, 11, 8, 6783, 12, 7, 6000, 12, 8, 4513, // 11, 7 + 10, 8, 6023, 10, 9, 4521, 11, 8, 48218, 11, 9, 6774, // 11, 8 + 10, 9, 6558, 10, 10, 4843, 11, 9, 47035, 11, 10, 7100, // 11, 9 + 10, 10, 7377, 10, 11, 5353, 11, 10, 45139, 11, 11, 7667, // 11,10 + 10, 11, 8378, 10, 12, 5965, 11, 11, 42861, 11, 12, 8332, // 11,11 + 10, 12, 9478, 10, 13, 6611, 11, 12, 40452, 11, 13, 8995, // 11,12 + 10, 13, 10630, 10, 14, 7252, 11, 13, 38057, 11, 14, 9597, // 11,13 + 10, 14, 11810, 10, 15, 7865, 11, 14, 35750, 11, 15, 10111, // 11,14 + 10, 15, 13007, 10, 16, 8438, 11, 15, 33564, 11, 16, 10527, // 11,15 + 12, 0, 32391, 12, 1, 11269, 13, 0, 13038, 13, 1, 8838, // 12, 0 + 12, 1, 34358, 12, 2, 10918, 13, 1, 11964, 13, 2, 8296, // 12, 1 + 12, 2, 36392, 12, 3, 10488, 13, 2, 10922, 13, 3, 7734, // 12, 2 + 12, 3, 38450, 12, 4, 9998, 13, 3, 9924, 13, 4, 7164, // 12, 3 + 12, 4, 40452, 12, 5, 9478, 13, 4, 8995, 13, 5, 6611, // 12, 4 + 12, 5, 42271, 12, 6, 8982, 13, 5, 8175, 13, 6, 6108, // 12, 5 + 12, 6, 43733, 12, 7, 8584, 13, 6, 7516, 13, 7, 5703, // 12, 6 + 12, 7, 44649, 12, 8, 8373, 13, 7, 7072, 13, 8, 5442, // 12, 7 + 11, 8, 7106, 11, 9, 5454, 12, 8, 44616, 12, 9, 8360, // 12, 8 + 11, 9, 7556, 11, 10, 5712, 12, 9, 43710, 12, 10, 8558, // 12, 9 + 11, 10, 8224, 11, 11, 6116, 12, 10, 42256, 12, 11, 8940, // 12,10 + 11, 11, 9056, 11, 12, 6615, 12, 11, 40444, 12, 12, 9421, // 12,11 + 11, 12, 9998, 11, 13, 7164, 12, 12, 38450, 12, 13, 9924, // 12,12 + 11, 13, 11012, 11, 14, 7728, 12, 13, 36399, 12, 14, 10397, // 12,13 + 11, 14, 12074, 11, 15, 8284, 12, 14, 34369, 12, 15, 10809, // 12,14 + 11, 15, 13171, 11, 16, 8816, 12, 15, 32406, 12, 16, 11143, // 12,15 + 13, 0, 31138, 13, 1, 11977, 14, 0, 13176, 14, 1, 9245, // 13, 0 + 13, 1, 32881, 13, 2, 11709, 14, 1, 12203, 14, 2, 8743, // 13, 1 + 13, 2, 34650, 13, 3, 11382, 14, 2, 11272, 14, 3, 8232, // 13, 2 + 13, 3, 36399, 13, 4, 11012, 14, 3, 10397, 14, 4, 7728, // 13, 3 + 13, 4, 38057, 13, 5, 10630, 14, 4, 9597, 14, 5, 7252, // 13, 4 + 13, 5, 39526, 13, 6, 10279, 14, 5, 8902, 14, 6, 6829, // 13, 5 + 13, 6, 40688, 13, 7, 10013, 14, 6, 8344, 14, 7, 6491, // 13, 6 + 13, 7, 41432, 13, 8, 9886, 14, 7, 7951, 14, 8, 6267, // 13, 7 + 12, 8, 7996, 12, 9, 6284, 13, 8, 41389, 13, 9, 9867, // 13, 8 + 12, 9, 8397, 12, 10, 6506, 13, 9, 40656, 13, 10, 9977, // 13, 9 + 12, 10, 8966, 12, 11, 6842, 13, 10, 39503, 13, 11, 10225, // 13,10 + 12, 11, 9674, 12, 12, 7261, 13, 11, 38042, 13, 12, 10559, // 13,11 + 12, 12, 10488, 12, 13, 7734, 13, 12, 36392, 13, 13, 10922, // 13,12 + 12, 13, 11382, 12, 14, 8232, 13, 13, 34650, 13, 14, 11272, // 13,13 + 12, 14, 12334, 12, 15, 8735, 13, 14, 32886, 13, 15, 11581, // 13,14 + 12, 15, 13332, 12, 16, 9229, 13, 15, 31146, 13, 16, 11829, // 13,15 + 14, 0, 29828, 14, 1, 12746, 15, 0, 13291, 15, 1, 9671, // 14, 0 + 14, 1, 31358, 14, 2, 12564, 15, 1, 12412, 15, 2, 9202, // 14, 1 + 14, 2, 32886, 14, 3, 12334, 15, 2, 11580, 15, 3, 8736, // 14, 2 + 14, 3, 34369, 14, 4, 12074, 15, 3, 10808, 15, 4, 8285, // 14, 3 + 14, 4, 35750, 14, 5, 11810, 15, 4, 10111, 15, 5, 7865, // 14, 4 + 14, 5, 36955, 14, 6, 11575, 15, 5, 9509, 15, 6, 7497, // 14, 5 + 14, 6, 37906, 14, 7, 11407, 15, 6, 9020, 15, 7, 7203, // 14, 6 + 14, 7, 38534, 14, 8, 11344, 15, 7, 8662, 15, 8, 6996, // 14, 7 + 13, 8, 8718, 13, 9, 7020, 14, 8, 38481, 14, 9, 11317, // 14, 8 + 13, 9, 9086, 13, 10, 7224, 14, 9, 37866, 14, 10, 11360, // 14, 9 + 13, 10, 9587, 13, 11, 7517, 14, 10, 36926, 14, 11, 11506, // 14,10 + 13, 11, 10204, 13, 12, 7881, 14, 11, 35730, 14, 12, 11721, // 14,11 + 13, 12, 10918, 13, 13, 8296, 14, 12, 34358, 14, 13, 11964, // 14,12 + 13, 13, 11709, 13, 14, 8742, 14, 13, 32881, 14, 14, 12204, // 14,13 + 13, 14, 12564, 13, 15, 9202, 14, 14, 31358, 14, 15, 12412, // 14,14 + 13, 15, 13470, 13, 16, 9662, 14, 15, 29831, 14, 16, 12573, // 14,15 + 15, 0, 28495, 15, 1, 13569, 16, 0, 13368, 16, 1, 10104, // 15, 0 + 15, 1, 29831, 15, 2, 13470, 16, 1, 12574, 16, 2, 9661, // 15, 1 + 15, 2, 31146, 15, 3, 13332, 16, 2, 11829, 16, 3, 9229, // 15, 2 + 15, 3, 32406, 15, 4, 13171, 16, 3, 11143, 16, 4, 8816, // 15, 3 + 15, 4, 33564, 15, 5, 13007, 16, 4, 10528, 16, 5, 8437, // 15, 4 + 15, 5, 34567, 15, 6, 12867, 16, 5, 9995, 16, 6, 8107, // 15, 5 + 15, 6, 35362, 15, 7, 12777, 16, 6, 9558, 16, 7, 7839, // 15, 6 + 15, 7, 35905, 15, 8, 12764, 16, 7, 9224, 16, 8, 7643, // 15, 7 + 14, 8, 9290, 14, 9, 7674, 15, 8, 35844, 15, 9, 12728, // 15, 8 + 14, 9, 9635, 14, 10, 7868, 15, 9, 35315, 15, 10, 12718, // 15, 9 + 14, 10, 10086, 14, 11, 8135, 15, 10, 34532, 15, 11, 12783, // 15,10 + 14, 11, 10635, 14, 12, 8463, 15, 11, 33539, 15, 12, 12899, // 15,11 + 14, 12, 11269, 14, 13, 8838, 15, 12, 32391, 15, 13, 13038, // 15,12 + 14, 13, 11977, 14, 14, 9245, 15, 13, 31138, 15, 14, 13176, // 15,13 + 14, 14, 12746, 14, 15, 9671, 15, 14, 29828, 15, 15, 13291, // 15,14 + 14, 15, 13569, 14, 16, 10104, 15, 15, 28495, 15, 16, 13368, // 15,15 + // angle of 2.5 degrees + 0, -1, 14696, 0, 0, 24063, 1, -1, 11702, 1, 0, 15075, // 0, 0 + 0, 0, 14872, 0, 1, 25368, 1, 0, 11187, 1, 1, 14109, // 0, 1 + 0, 1, 14990, 0, 2, 26660, 1, 1, 10676, 1, 2, 13210, // 0, 2 + 0, 2, 15060, 0, 3, 27903, 1, 2, 10185, 1, 3, 12388, // 0, 3 + 0, 3, 15100, 0, 4, 29055, 1, 3, 9728, 1, 4, 11653, // 0, 4 + 0, 4, 15135, 0, 5, 30064, 1, 4, 9323, 1, 5, 11014, // 0, 5 + 0, 5, 15193, 0, 6, 30876, 1, 5, 8986, 1, 6, 10481, // 0, 6 + 0, 6, 15301, 0, 7, 31444, 1, 6, 8727, 1, 7, 10064, // 0, 7 + -1, 7, 8669, -1, 8, 9959, 0, 7, 15376, 0, 8, 31532, // 0, 8 + -1, 8, 8927, -1, 9, 10351, 0, 8, 15319, 0, 9, 30939, // 0, 9 + -1, 9, 9265, -1, 10, 10855, 0, 9, 15311, 0, 10, 30105, // 0,10 + -1, 10, 9673, -1, 11, 11461, 0, 10, 15325, 0, 11, 29077, // 0,11 + -1, 11, 10135, -1, 12, 12159, 0, 11, 15330, 0, 12, 27912, // 0,12 + -1, 12, 10637, -1, 13, 12938, 0, 12, 15301, 0, 13, 26660, // 0,13 + -1, 13, 11164, -1, 14, 13787, 0, 13, 15220, 0, 14, 25365, // 0,14 + -1, 14, 11702, -1, 15, 14696, 0, 14, 15076, 0, 15, 24062, // 0,15 + 1, -1, 13787, 1, 0, 25366, 2, -1, 11164, 2, 0, 15219, // 1, 0 + 1, 0, 13853, 1, 1, 26893, 2, 0, 10644, 2, 1, 14146, // 1, 1 + 1, 1, 13850, 1, 2, 28427, 2, 1, 10119, 2, 2, 13140, // 1, 2 + 1, 2, 13789, 1, 3, 29928, 2, 2, 9603, 2, 3, 12216, // 1, 3 + 1, 3, 13694, 1, 4, 31339, 2, 3, 9118, 2, 4, 11385, // 1, 4 + 1, 4, 13600, 1, 5, 32586, 2, 4, 8685, 2, 5, 10665, // 1, 5 + 1, 5, 13548, 1, 6, 33585, 2, 5, 8329, 2, 6, 10074, // 1, 6 + 1, 6, 13582, 1, 7, 34261, 2, 6, 8068, 2, 7, 9625, // 1, 7 + 0, 7, 8024, 0, 8, 9534, 1, 7, 13638, 1, 8, 34340, // 1, 8 + 0, 8, 8286, 0, 9, 9961, 1, 8, 13647, 1, 9, 33642, // 1, 9 + 0, 9, 8645, 0, 10, 10528, 1, 9, 13740, 1, 10, 32623, // 1,10 + 0, 10, 9082, 0, 11, 11218, 1, 10, 13875, 1, 11, 31361, // 1,11 + 0, 11, 9575, 0, 12, 12014, 1, 11, 14009, 1, 12, 29938, // 1,12 + 0, 12, 10102, 0, 13, 12897, 1, 12, 14107, 1, 13, 28430, // 1,13 + 0, 13, 10644, 0, 14, 13853, 1, 13, 14145, 1, 14, 26894, // 1,14 + 0, 14, 11187, 0, 15, 14872, 1, 14, 14109, 1, 15, 25368, // 1,15 + 2, -1, 12938, 2, 0, 26660, 3, -1, 10637, 3, 0, 15301, // 2, 0 + 2, 0, 12897, 2, 1, 28430, 3, 0, 10102, 3, 1, 14107, // 2, 1 + 2, 1, 12769, 2, 2, 30239, 3, 1, 9546, 3, 2, 12982, // 2, 2 + 2, 2, 12569, 2, 3, 32045, 3, 2, 8988, 3, 3, 11934, // 2, 3 + 2, 3, 12323, 2, 4, 33777, 3, 3, 8452, 3, 4, 10984, // 2, 4 + 2, 4, 12079, 2, 5, 35332, 3, 4, 7969, 3, 5, 10156, // 2, 5 + 2, 5, 11897, 2, 6, 36582, 3, 5, 7573, 3, 6, 9484, // 2, 6 + 2, 6, 11842, 2, 7, 37402, 3, 6, 7298, 3, 7, 8994, // 2, 7 + 1, 7, 7266, 1, 8, 8918, 2, 7, 11883, 2, 8, 37469, // 2, 8 + 1, 8, 7543, 1, 9, 9390, 2, 8, 11972, 2, 9, 36631, // 2, 9 + 1, 9, 7943, 1, 10, 10041, 2, 9, 12188, 2, 10, 35364, // 2,10 + 1, 10, 8432, 1, 11, 10842, 2, 10, 12467, 2, 11, 33795, // 2,11 + 1, 11, 8976, 1, 12, 11760, 2, 11, 12747, 2, 12, 32053, // 2,12 + 1, 12, 9546, 1, 13, 12769, 2, 12, 12982, 2, 13, 30239, // 2,13 + 1, 13, 10119, 1, 14, 13850, 2, 13, 13141, 2, 14, 28426, // 2,14 + 1, 14, 10676, 1, 15, 14990, 2, 14, 13211, 2, 15, 26659, // 2,15 + 3, -1, 12159, 3, 0, 27912, 4, -1, 10135, 4, 0, 15330, // 3, 0 + 3, 0, 12014, 3, 1, 29938, 4, 0, 9575, 4, 1, 14009, // 3, 1 + 3, 1, 11760, 3, 2, 32052, 4, 1, 8976, 4, 2, 12748, // 3, 2 + 3, 2, 11411, 3, 3, 34213, 4, 2, 8358, 4, 3, 11554, // 3, 3 + 3, 3, 10995, 3, 4, 36343, 4, 3, 7746, 4, 4, 10452, // 3, 4 + 3, 4, 10569, 3, 5, 38307, 4, 4, 7180, 4, 5, 9480, // 3, 5 + 3, 5, 10221, 3, 6, 39912, 4, 5, 6714, 4, 6, 8689, // 3, 6 + 3, 6, 10051, 3, 7, 40940, 4, 6, 6403, 4, 7, 8142, // 3, 7 + 2, 7, 6381, 2, 8, 8082, 3, 7, 10079, 3, 8, 40994, // 3, 8 + 2, 8, 6695, 2, 9, 8617, 3, 8, 10275, 3, 9, 39949, // 3, 9 + 2, 9, 7165, 2, 10, 9388, 3, 9, 10653, 3, 10, 38330, // 3,10 + 2, 10, 7737, 2, 11, 10337, 3, 10, 11108, 3, 11, 36354, // 3,11 + 2, 11, 8358, 2, 12, 11411, 3, 11, 11554, 3, 12, 34213, // 3,12 + 2, 12, 8988, 2, 13, 12569, 3, 12, 11934, 3, 13, 32045, // 3,13 + 2, 13, 9603, 2, 14, 13789, 3, 13, 12216, 3, 14, 29928, // 3,14 + 2, 14, 10185, 2, 15, 15060, 3, 14, 12388, 3, 15, 27903, // 3,15 + 4, -1, 11461, 4, 0, 29078, 5, -1, 9673, 5, 0, 15324, // 4, 0 + 4, 0, 11218, 4, 1, 31361, 5, 0, 9082, 5, 1, 13875, // 4, 1 + 4, 1, 10842, 4, 2, 33795, 5, 1, 8432, 5, 2, 12467, // 4, 2 + 4, 2, 10337, 4, 3, 36354, 5, 2, 7737, 5, 3, 11108, // 4, 3 + 4, 3, 9730, 4, 4, 38966, 5, 3, 7022, 5, 4, 9818, // 4, 4 + 4, 4, 9081, 4, 5, 41475, 5, 4, 6334, 5, 5, 8646, // 4, 5 + 4, 5, 8507, 4, 6, 43602, 5, 5, 5749, 5, 6, 7678, // 4, 6 + 4, 6, 8177, 4, 7, 44962, 5, 6, 5368, 5, 7, 7029, // 4, 7 + 3, 7, 5354, 3, 8, 6987, 4, 7, 8195, 4, 8, 45000, // 4, 8 + 3, 8, 5739, 3, 9, 7626, 4, 8, 8545, 4, 9, 43626, // 4, 9 + 3, 9, 6328, 3, 10, 8578, 4, 9, 9143, 4, 10, 41487, // 4,10 + 3, 10, 7022, 3, 11, 9730, 4, 10, 9818, 4, 11, 38966, // 4,11 + 3, 11, 7746, 3, 12, 10995, 4, 11, 10452, 4, 12, 36343, // 4,12 + 3, 12, 8452, 3, 13, 12323, 4, 12, 10983, 4, 13, 33778, // 4,13 + 3, 13, 9118, 3, 14, 13694, 4, 13, 11385, 4, 14, 31339, // 4,14 + 3, 14, 9728, 3, 15, 15100, 4, 14, 11652, 4, 15, 29056, // 4,15 + 5, -1, 10855, 5, 0, 30105, 6, -1, 9265, 6, 0, 15311, // 5, 0 + 5, 0, 10528, 5, 1, 32624, 6, 0, 8645, 6, 1, 13739, // 5, 1 + 5, 1, 10041, 5, 2, 35364, 6, 1, 7943, 6, 2, 12188, // 5, 2 + 5, 2, 9388, 5, 3, 38330, 6, 2, 7165, 6, 3, 10653, // 5, 3 + 5, 3, 8578, 5, 4, 41487, 6, 3, 6328, 6, 4, 9143, // 5, 4 + 5, 4, 7659, 5, 5, 44700, 6, 4, 5472, 6, 5, 7705, // 5, 5 + 5, 5, 6768, 5, 6, 47619, 6, 5, 4694, 6, 6, 6455, // 5, 6 + 5, 6, 6183, 5, 7, 49566, 6, 6, 4172, 6, 7, 5615, // 5, 7 + 4, 7, 4164, 4, 8, 5590, 5, 7, 6193, 5, 8, 49589, // 5, 8 + 4, 8, 4690, 4, 9, 6422, 5, 8, 6794, 5, 9, 47630, // 5, 9 + 4, 9, 5472, 4, 10, 7659, 5, 9, 7705, 5, 10, 44700, // 5,10 + 4, 10, 6334, 4, 11, 9081, 5, 10, 8646, 5, 11, 41475, // 5,11 + 4, 11, 7180, 4, 12, 10569, 5, 11, 9479, 5, 12, 38308, // 5,12 + 4, 12, 7969, 4, 13, 12079, 5, 12, 10156, 5, 13, 35332, // 5,13 + 4, 13, 8685, 4, 14, 13600, 5, 13, 10665, 5, 14, 32586, // 5,14 + 4, 14, 9323, 4, 15, 15135, 5, 14, 11013, 5, 15, 30065, // 5,15 + 6, -1, 10351, 6, 0, 30939, 7, -1, 8927, 7, 0, 15319, // 6, 0 + 6, 0, 9961, 6, 1, 33642, 7, 0, 8286, 7, 1, 13647, // 6, 1 + 6, 1, 9390, 6, 2, 36631, 7, 1, 7543, 7, 2, 11972, // 6, 2 + 6, 2, 8617, 6, 3, 39949, 7, 2, 6695, 7, 3, 10275, // 6, 3 + 6, 3, 7626, 6, 4, 43626, 7, 3, 5739, 7, 4, 8545, // 6, 4 + 6, 4, 6422, 6, 5, 47630, 7, 4, 4690, 7, 5, 6794, // 6, 5 + 6, 5, 5099, 6, 6, 51701, 7, 5, 3620, 7, 6, 5116, // 6, 6 + 6, 6, 4044, 6, 7, 54831, 7, 6, 2797, 7, 7, 3864, // 6, 7 + 5, 7, 2795, 5, 8, 3853, 6, 7, 4049, 6, 8, 54839, // 6, 8 + 5, 8, 3620, 5, 9, 5099, 6, 8, 5116, 6, 9, 51701, // 6, 9 + 5, 9, 4694, 5, 10, 6768, 6, 9, 6455, 6, 10, 47619, // 6,10 + 5, 10, 5749, 5, 11, 8507, 6, 10, 7678, 6, 11, 43602, // 6,11 + 5, 11, 6714, 5, 12, 10221, 6, 11, 8690, 6, 12, 39911, // 6,12 + 5, 12, 7573, 5, 13, 11897, 6, 12, 9484, 6, 13, 36582, // 6,13 + 5, 13, 8329, 5, 14, 13548, 6, 13, 10074, 6, 14, 33585, // 6,14 + 5, 14, 8986, 5, 15, 15193, 6, 14, 10482, 6, 15, 30875, // 6,15 + 7, -1, 9959, 7, 0, 31532, 8, -1, 8669, 8, 0, 15376, // 7, 0 + 7, 0, 9534, 7, 1, 34340, 8, 0, 8024, 8, 1, 13638, // 7, 1 + 7, 1, 8918, 7, 2, 37470, 8, 1, 7266, 8, 2, 11882, // 7, 2 + 7, 2, 8082, 7, 3, 40994, 8, 2, 6381, 8, 3, 10079, // 7, 3 + 7, 3, 6987, 7, 4, 44999, 8, 3, 5354, 8, 4, 8196, // 7, 4 + 7, 4, 5590, 7, 5, 49588, 8, 4, 4164, 8, 5, 6194, // 7, 5 + 7, 5, 3853, 7, 6, 54839, 8, 5, 2795, 8, 6, 4049, // 7, 6 + 7, 6, 1903, 7, 7, 60382, 8, 6, 1347, 8, 7, 1904, // 7, 7 + 6, 7, 1347, 6, 8, 1903, 7, 7, 1905, 7, 8, 60381, // 7, 8 + 6, 8, 2797, 6, 9, 4044, 7, 8, 3864, 7, 9, 54831, // 7, 9 + 6, 9, 4172, 6, 10, 6183, 7, 9, 5615, 7, 10, 49566, // 7,10 + 6, 10, 5368, 6, 11, 8177, 7, 10, 7029, 7, 11, 44962, // 7,11 + 6, 11, 6403, 6, 12, 10051, 7, 11, 8141, 7, 12, 40941, // 7,12 + 6, 12, 7298, 6, 13, 11842, 7, 12, 8994, 7, 13, 37402, // 7,13 + 6, 13, 8068, 6, 14, 13582, 7, 13, 9626, 7, 14, 34260, // 7,14 + 6, 14, 8727, 6, 15, 15301, 7, 14, 10065, 7, 15, 31443, // 7,15 + 8, 0, 31444, 8, 1, 10065, 9, 0, 15301, 9, 1, 8726, // 8, 0 + 8, 1, 34261, 8, 2, 9626, 9, 1, 13582, 9, 2, 8067, // 8, 1 + 8, 2, 37402, 8, 3, 8994, 9, 2, 11842, 9, 3, 7298, // 8, 2 + 8, 3, 40940, 8, 4, 8141, 9, 3, 10051, 9, 4, 6404, // 8, 3 + 8, 4, 44962, 8, 5, 7029, 9, 4, 8177, 9, 5, 5368, // 8, 4 + 8, 5, 49566, 8, 6, 5615, 9, 5, 6183, 9, 6, 4172, // 8, 5 + 8, 6, 54831, 8, 7, 3864, 9, 6, 4044, 9, 7, 2797, // 8, 6 + 8, 7, 60382, 8, 8, 1905, 9, 7, 1903, 9, 8, 1346, // 8, 7 + 7, 8, 1905, 7, 9, 1347, 8, 8, 60382, 8, 9, 1902, // 8, 8 + 7, 9, 4049, 7, 10, 2795, 8, 9, 54839, 8, 10, 3853, // 8, 9 + 7, 10, 6193, 7, 11, 4164, 8, 10, 49588, 8, 11, 5591, // 8,10 + 7, 11, 8195, 7, 12, 5354, 8, 11, 44999, 8, 12, 6988, // 8,11 + 7, 12, 10079, 7, 13, 6381, 8, 12, 40994, 8, 13, 8082, // 8,12 + 7, 13, 11883, 7, 14, 7266, 8, 13, 37470, 8, 14, 8917, // 8,13 + 7, 14, 13638, 7, 15, 8024, 8, 14, 34340, 8, 15, 9534, // 8,14 + 7, 15, 15376, 7, 16, 8669, 8, 15, 31532, 8, 16, 9959, // 8,15 + 9, 0, 30876, 9, 1, 10482, 10, 0, 15193, 10, 1, 8985, // 9, 0 + 9, 1, 33585, 9, 2, 10074, 10, 1, 13548, 10, 2, 8329, // 9, 1 + 9, 2, 36582, 9, 3, 9484, 10, 2, 11897, 10, 3, 7573, // 9, 2 + 9, 3, 39912, 9, 4, 8690, 10, 3, 10221, 10, 4, 6713, // 9, 3 + 9, 4, 43602, 9, 5, 7678, 10, 4, 8507, 10, 5, 5749, // 9, 4 + 9, 5, 47619, 9, 6, 6455, 10, 5, 6768, 10, 6, 4694, // 9, 5 + 9, 6, 51701, 9, 7, 5116, 10, 6, 5099, 10, 7, 3620, // 9, 6 + 9, 7, 54839, 9, 8, 4049, 10, 7, 3853, 10, 8, 2795, // 9, 7 + 8, 8, 3864, 8, 9, 2797, 9, 8, 54831, 9, 9, 4044, // 9, 8 + 8, 9, 5116, 8, 10, 3620, 9, 9, 51701, 9, 10, 5099, // 9, 9 + 8, 10, 6794, 8, 11, 4690, 9, 10, 47630, 9, 11, 6422, // 9,10 + 8, 11, 8545, 8, 12, 5739, 9, 11, 43626, 9, 12, 7626, // 9,11 + 8, 12, 10275, 8, 13, 6695, 9, 12, 39949, 9, 13, 8617, // 9,12 + 8, 13, 11972, 8, 14, 7543, 9, 13, 36631, 9, 14, 9390, // 9,13 + 8, 14, 13647, 8, 15, 8286, 9, 14, 33642, 9, 15, 9961, // 9,14 + 8, 15, 15319, 8, 16, 8927, 9, 15, 30939, 9, 16, 10351, // 9,15 + 10, 0, 30064, 10, 1, 11013, 11, 0, 15135, 11, 1, 9324, // 10, 0 + 10, 1, 32586, 10, 2, 10665, 11, 1, 13600, 11, 2, 8685, // 10, 1 + 10, 2, 35332, 10, 3, 10156, 11, 2, 12079, 11, 3, 7969, // 10, 2 + 10, 3, 38307, 10, 4, 9479, 11, 3, 10569, 11, 4, 7181, // 10, 3 + 10, 4, 41475, 10, 5, 8646, 11, 4, 9081, 11, 5, 6334, // 10, 4 + 10, 5, 44700, 10, 6, 7705, 11, 5, 7659, 11, 6, 5472, // 10, 5 + 10, 6, 47630, 10, 7, 6794, 11, 6, 6422, 11, 7, 4690, // 10, 6 + 10, 7, 49588, 10, 8, 6193, 11, 7, 5590, 11, 8, 4165, // 10, 7 + 9, 8, 5615, 9, 9, 4172, 10, 8, 49566, 10, 9, 6183, // 10, 8 + 9, 9, 6455, 9, 10, 4694, 10, 9, 47619, 10, 10, 6768, // 10, 9 + 9, 10, 7705, 9, 11, 5472, 10, 10, 44700, 10, 11, 7659, // 10,10 + 9, 11, 9143, 9, 12, 6328, 10, 11, 41487, 10, 12, 8578, // 10,11 + 9, 12, 10653, 9, 13, 7165, 10, 12, 38330, 10, 13, 9388, // 10,12 + 9, 13, 12188, 9, 14, 7943, 10, 13, 35364, 10, 14, 10041, // 10,13 + 9, 14, 13740, 9, 15, 8645, 10, 14, 32624, 10, 15, 10527, // 10,14 + 9, 15, 15311, 9, 16, 9265, 10, 15, 30105, 10, 16, 10855, // 10,15 + 11, 0, 29055, 11, 1, 11652, 12, 0, 15100, 12, 1, 9729, // 11, 0 + 11, 1, 31339, 11, 2, 11385, 12, 1, 13694, 12, 2, 9118, // 11, 1 + 11, 2, 33777, 11, 3, 10983, 12, 2, 12323, 12, 3, 8453, // 11, 2 + 11, 3, 36343, 11, 4, 10452, 12, 3, 10995, 12, 4, 7746, // 11, 3 + 11, 4, 38966, 11, 5, 9818, 12, 4, 9730, 12, 5, 7022, // 11, 4 + 11, 5, 41487, 11, 6, 9143, 12, 5, 8578, 12, 6, 6328, // 11, 5 + 11, 6, 43626, 11, 7, 8545, 12, 6, 7626, 12, 7, 5739, // 11, 6 + 11, 7, 44999, 11, 8, 8195, 12, 7, 6987, 12, 8, 5355, // 11, 7 + 10, 8, 7029, 10, 9, 5368, 11, 8, 44962, 11, 9, 8177, // 11, 8 + 10, 9, 7678, 10, 10, 5749, 11, 9, 43602, 11, 10, 8507, // 11, 9 + 10, 10, 8646, 10, 11, 6334, 11, 10, 41475, 11, 11, 9081, // 11,10 + 10, 11, 9818, 10, 12, 7022, 11, 11, 38966, 11, 12, 9730, // 11,11 + 10, 12, 11108, 10, 13, 7737, 11, 12, 36354, 11, 13, 10337, // 11,12 + 10, 13, 12467, 10, 14, 8432, 11, 13, 33795, 11, 14, 10842, // 11,13 + 10, 14, 13875, 10, 15, 9082, 11, 14, 31361, 11, 15, 11218, // 11,14 + 10, 15, 15325, 10, 16, 9673, 11, 15, 29078, 11, 16, 11460, // 11,15 + 12, 0, 27903, 12, 1, 12388, 13, 0, 15060, 13, 1, 10185, // 12, 0 + 12, 1, 29928, 12, 2, 12216, 13, 1, 13789, 13, 2, 9603, // 12, 1 + 12, 2, 32045, 12, 3, 11934, 13, 2, 12569, 13, 3, 8988, // 12, 2 + 12, 3, 34213, 12, 4, 11554, 13, 3, 11411, 13, 4, 8358, // 12, 3 + 12, 4, 36354, 12, 5, 11108, 13, 4, 10337, 13, 5, 7737, // 12, 4 + 12, 5, 38330, 12, 6, 10653, 13, 5, 9388, 13, 6, 7165, // 12, 5 + 12, 6, 39949, 12, 7, 10275, 13, 6, 8617, 13, 7, 6695, // 12, 6 + 12, 7, 40994, 12, 8, 10079, 13, 7, 8082, 13, 8, 6381, // 12, 7 + 11, 8, 8141, 11, 9, 6403, 12, 8, 40940, 12, 9, 10052, // 12, 8 + 11, 9, 8690, 11, 10, 6714, 12, 9, 39912, 12, 10, 10220, // 12, 9 + 11, 10, 9479, 11, 11, 7180, 12, 10, 38307, 12, 11, 10570, // 12,10 + 11, 11, 10452, 11, 12, 7746, 12, 11, 36343, 12, 12, 10995, // 12,11 + 11, 12, 11554, 11, 13, 8358, 12, 12, 34213, 12, 13, 11411, // 12,12 + 11, 13, 12747, 11, 14, 8976, 12, 13, 32052, 12, 14, 11761, // 12,13 + 11, 14, 14009, 11, 15, 9575, 12, 14, 29938, 12, 15, 12014, // 12,14 + 11, 15, 15330, 11, 16, 10135, 12, 15, 27912, 12, 16, 12159, // 12,15 + 13, 0, 26660, 13, 1, 13211, 14, 0, 14990, 14, 1, 10675, // 13, 0 + 13, 1, 28427, 13, 2, 13141, 14, 1, 13850, 14, 2, 10118, // 13, 1 + 13, 2, 30239, 13, 3, 12982, 14, 2, 12769, 14, 3, 9546, // 13, 2 + 13, 3, 32052, 13, 4, 12747, 14, 3, 11760, 14, 4, 8977, // 13, 3 + 13, 4, 33795, 13, 5, 12467, 14, 4, 10842, 14, 5, 8432, // 13, 4 + 13, 5, 35364, 13, 6, 12188, 14, 5, 10041, 14, 6, 7943, // 13, 5 + 13, 6, 36631, 13, 7, 11972, 14, 6, 9390, 14, 7, 7543, // 13, 6 + 13, 7, 37470, 13, 8, 11883, 14, 7, 8918, 14, 8, 7265, // 13, 7 + 12, 8, 8994, 12, 9, 7298, 13, 8, 37402, 13, 9, 11842, // 13, 8 + 12, 9, 9484, 12, 10, 7573, 13, 9, 36582, 13, 10, 11897, // 13, 9 + 12, 10, 10156, 12, 11, 7969, 13, 10, 35332, 13, 11, 12079, // 13,10 + 12, 11, 10983, 12, 12, 8452, 13, 11, 33777, 13, 12, 12324, // 13,11 + 12, 12, 11934, 12, 13, 8988, 13, 12, 32045, 13, 13, 12569, // 13,12 + 12, 13, 12982, 12, 14, 9546, 13, 13, 30239, 13, 14, 12769, // 13,13 + 12, 14, 14107, 12, 15, 10102, 13, 14, 28430, 13, 15, 12897, // 13,14 + 12, 15, 15301, 12, 16, 10637, 13, 15, 26660, 13, 16, 12938, // 13,15 + 14, 0, 25368, 14, 1, 14109, 15, 0, 14872, 15, 1, 11187, // 14, 0 + 14, 1, 26893, 14, 2, 14145, 15, 1, 13853, 15, 2, 10645, // 14, 1 + 14, 2, 28430, 14, 3, 14107, 15, 2, 12897, 15, 3, 10102, // 14, 2 + 14, 3, 29938, 14, 4, 14009, 15, 3, 12014, 15, 4, 9575, // 14, 3 + 14, 4, 31361, 14, 5, 13875, 15, 4, 11218, 15, 5, 9082, // 14, 4 + 14, 5, 32624, 14, 6, 13740, 15, 5, 10528, 15, 6, 8644, // 14, 5 + 14, 6, 33642, 14, 7, 13647, 15, 6, 9961, 15, 7, 8286, // 14, 6 + 14, 7, 34340, 14, 8, 13638, 15, 7, 9534, 15, 8, 8024, // 14, 7 + 13, 8, 9626, 13, 9, 8068, 14, 8, 34261, 14, 9, 13581, // 14, 8 + 13, 9, 10074, 13, 10, 8329, 14, 9, 33585, 14, 10, 13548, // 14, 9 + 13, 10, 10665, 13, 11, 8685, 14, 10, 32586, 14, 11, 13600, // 14,10 + 13, 11, 11385, 13, 12, 9118, 14, 11, 31339, 14, 12, 13694, // 14,11 + 13, 12, 12216, 13, 13, 9603, 14, 12, 29928, 14, 13, 13789, // 14,12 + 13, 13, 13141, 13, 14, 10119, 14, 13, 28427, 14, 14, 13849, // 14,13 + 13, 14, 14145, 13, 15, 10644, 14, 14, 26893, 14, 15, 13854, // 14,14 + 13, 15, 15220, 13, 16, 11164, 14, 15, 25366, 14, 16, 13786, // 14,15 + 15, 0, 24063, 15, 1, 15076, 16, 0, 14696, 16, 1, 11701, // 15, 0 + 15, 1, 25366, 15, 2, 15220, 16, 1, 13787, 16, 2, 11163, // 15, 1 + 15, 2, 26660, 15, 3, 15301, 16, 2, 12938, 16, 3, 10637, // 15, 2 + 15, 3, 27912, 15, 4, 15330, 16, 3, 12159, 16, 4, 10135, // 15, 3 + 15, 4, 29078, 15, 5, 15325, 16, 4, 11461, 16, 5, 9672, // 15, 4 + 15, 5, 30105, 15, 6, 15311, 16, 5, 10855, 16, 6, 9265, // 15, 5 + 15, 6, 30939, 15, 7, 15319, 16, 6, 10351, 16, 7, 8927, // 15, 6 + 15, 7, 31532, 15, 8, 15376, 16, 7, 9959, 16, 8, 8669, // 15, 7 + 14, 8, 10065, 14, 9, 8727, 15, 8, 31444, 15, 9, 15300, // 15, 8 + 14, 9, 10482, 14, 10, 8986, 15, 9, 30876, 15, 10, 15192, // 15, 9 + 14, 10, 11013, 14, 11, 9323, 15, 10, 30064, 15, 11, 15136, // 15,10 + 14, 11, 11652, 14, 12, 9728, 15, 11, 29055, 15, 12, 15101, // 15,11 + 14, 12, 12388, 14, 13, 10185, 15, 12, 27903, 15, 13, 15060, // 15,12 + 14, 13, 13211, 14, 14, 10676, 15, 13, 26660, 15, 14, 14989, // 15,13 + 14, 14, 14109, 14, 15, 11187, 15, 14, 25368, 15, 15, 14872, // 15,14 + 14, 15, 15076, 14, 16, 11702, 15, 15, 24063, 15, 16, 14695, // 15,15 diff --git a/vp8/common/rotate2.h b/vp8/common/rotate2.h new file mode 100644 index 000000000..580f55279 --- /dev/null +++ b/vp8/common/rotate2.h @@ -0,0 +1,2827 @@ + // angle of -2.5 degrees + -1, 0, 14696, -1, 1, 11702, 0, 0, 24063, 0, 1, 15075, // 0, 0 + -1, 1, 13787, -1, 2, 11164, 0, 1, 25366, 0, 2, 15219, // 0, 1 + -1, 2, 12938, -1, 3, 10637, 0, 2, 26660, 0, 3, 15301, // 0, 2 + -1, 3, 12159, -1, 4, 10135, 0, 3, 27912, 0, 4, 15330, // 0, 3 + -1, 4, 11461, -1, 5, 9673, 0, 4, 29078, 0, 5, 15324, // 0, 4 + -1, 5, 10855, -1, 6, 9265, 0, 5, 30105, 0, 6, 15311, // 0, 5 + -1, 6, 10351, -1, 7, 8927, 0, 6, 30939, 0, 7, 15319, // 0, 6 + -1, 7, 9959, -1, 8, 8669, 0, 7, 31532, 0, 8, 15376, // 0, 7 + 0, 8, 31444, 0, 9, 15301, 1, 8, 10065, 1, 9, 8726, // 0, 8 + 0, 9, 30876, 0, 10, 15193, 1, 9, 10482, 1, 10, 8985, // 0, 9 + 0, 10, 30064, 0, 11, 15135, 1, 10, 11013, 1, 11, 9324, // 0,10 + 0, 11, 29055, 0, 12, 15100, 1, 11, 11652, 1, 12, 9729, // 0,11 + 0, 12, 27903, 0, 13, 15060, 1, 12, 12388, 1, 13, 10185, // 0,12 + 0, 13, 26660, 0, 14, 14990, 1, 13, 13211, 1, 14, 10675, // 0,13 + 0, 14, 25368, 0, 15, 14872, 1, 14, 14109, 1, 15, 11187, // 0,14 + 0, 15, 24063, 0, 16, 14696, 1, 15, 15076, 1, 16, 11701, // 0,15 + 0, 0, 14872, 0, 1, 11187, 1, 0, 25368, 1, 1, 14109, // 1, 0 + 0, 1, 13853, 0, 2, 10644, 1, 1, 26893, 1, 2, 14146, // 1, 1 + 0, 2, 12897, 0, 3, 10102, 1, 2, 28430, 1, 3, 14107, // 1, 2 + 0, 3, 12014, 0, 4, 9575, 1, 3, 29938, 1, 4, 14009, // 1, 3 + 0, 4, 11218, 0, 5, 9082, 1, 4, 31361, 1, 5, 13875, // 1, 4 + 0, 5, 10528, 0, 6, 8645, 1, 5, 32624, 1, 6, 13739, // 1, 5 + 0, 6, 9961, 0, 7, 8286, 1, 6, 33642, 1, 7, 13647, // 1, 6 + 0, 7, 9534, 0, 8, 8024, 1, 7, 34340, 1, 8, 13638, // 1, 7 + 1, 8, 34261, 1, 9, 13582, 2, 8, 9626, 2, 9, 8067, // 1, 8 + 1, 9, 33585, 1, 10, 13548, 2, 9, 10074, 2, 10, 8329, // 1, 9 + 1, 10, 32586, 1, 11, 13600, 2, 10, 10665, 2, 11, 8685, // 1,10 + 1, 11, 31339, 1, 12, 13694, 2, 11, 11385, 2, 12, 9118, // 1,11 + 1, 12, 29928, 1, 13, 13789, 2, 12, 12216, 2, 13, 9603, // 1,12 + 1, 13, 28427, 1, 14, 13850, 2, 13, 13141, 2, 14, 10118, // 1,13 + 1, 14, 26893, 1, 15, 13853, 2, 14, 14145, 2, 15, 10645, // 1,14 + 1, 15, 25366, 1, 16, 13787, 2, 15, 15220, 2, 16, 11163, // 1,15 + 1, 0, 14990, 1, 1, 10676, 2, 0, 26660, 2, 1, 13210, // 2, 0 + 1, 1, 13850, 1, 2, 10119, 2, 1, 28427, 2, 2, 13140, // 2, 1 + 1, 2, 12769, 1, 3, 9546, 2, 2, 30239, 2, 3, 12982, // 2, 2 + 1, 3, 11760, 1, 4, 8976, 2, 3, 32052, 2, 4, 12748, // 2, 3 + 1, 4, 10842, 1, 5, 8432, 2, 4, 33795, 2, 5, 12467, // 2, 4 + 1, 5, 10041, 1, 6, 7943, 2, 5, 35364, 2, 6, 12188, // 2, 5 + 1, 6, 9390, 1, 7, 7543, 2, 6, 36631, 2, 7, 11972, // 2, 6 + 1, 7, 8918, 1, 8, 7266, 2, 7, 37470, 2, 8, 11882, // 2, 7 + 2, 8, 37402, 2, 9, 11842, 3, 8, 8994, 3, 9, 7298, // 2, 8 + 2, 9, 36582, 2, 10, 11897, 3, 9, 9484, 3, 10, 7573, // 2, 9 + 2, 10, 35332, 2, 11, 12079, 3, 10, 10156, 3, 11, 7969, // 2,10 + 2, 11, 33777, 2, 12, 12323, 3, 11, 10983, 3, 12, 8453, // 2,11 + 2, 12, 32045, 2, 13, 12569, 3, 12, 11934, 3, 13, 8988, // 2,12 + 2, 13, 30239, 2, 14, 12769, 3, 13, 12982, 3, 14, 9546, // 2,13 + 2, 14, 28430, 2, 15, 12897, 3, 14, 14107, 3, 15, 10102, // 2,14 + 2, 15, 26660, 2, 16, 12938, 3, 15, 15301, 3, 16, 10637, // 2,15 + 2, 0, 15060, 2, 1, 10185, 3, 0, 27903, 3, 1, 12388, // 3, 0 + 2, 1, 13789, 2, 2, 9603, 3, 1, 29928, 3, 2, 12216, // 3, 1 + 2, 2, 12569, 2, 3, 8988, 3, 2, 32045, 3, 3, 11934, // 3, 2 + 2, 3, 11411, 2, 4, 8358, 3, 3, 34213, 3, 4, 11554, // 3, 3 + 2, 4, 10337, 2, 5, 7737, 3, 4, 36354, 3, 5, 11108, // 3, 4 + 2, 5, 9388, 2, 6, 7165, 3, 5, 38330, 3, 6, 10653, // 3, 5 + 2, 6, 8617, 2, 7, 6695, 3, 6, 39949, 3, 7, 10275, // 3, 6 + 2, 7, 8082, 2, 8, 6381, 3, 7, 40994, 3, 8, 10079, // 3, 7 + 3, 8, 40940, 3, 9, 10051, 4, 8, 8141, 4, 9, 6404, // 3, 8 + 3, 9, 39912, 3, 10, 10221, 4, 9, 8690, 4, 10, 6713, // 3, 9 + 3, 10, 38307, 3, 11, 10569, 4, 10, 9479, 4, 11, 7181, // 3,10 + 3, 11, 36343, 3, 12, 10995, 4, 11, 10452, 4, 12, 7746, // 3,11 + 3, 12, 34213, 3, 13, 11411, 4, 12, 11554, 4, 13, 8358, // 3,12 + 3, 13, 32052, 3, 14, 11760, 4, 13, 12747, 4, 14, 8977, // 3,13 + 3, 14, 29938, 3, 15, 12014, 4, 14, 14009, 4, 15, 9575, // 3,14 + 3, 15, 27912, 3, 16, 12159, 4, 15, 15330, 4, 16, 10135, // 3,15 + 3, 0, 15100, 3, 1, 9728, 4, 0, 29055, 4, 1, 11653, // 4, 0 + 3, 1, 13694, 3, 2, 9118, 4, 1, 31339, 4, 2, 11385, // 4, 1 + 3, 2, 12323, 3, 3, 8452, 4, 2, 33777, 4, 3, 10984, // 4, 2 + 3, 3, 10995, 3, 4, 7746, 4, 3, 36343, 4, 4, 10452, // 4, 3 + 3, 4, 9730, 3, 5, 7022, 4, 4, 38966, 4, 5, 9818, // 4, 4 + 3, 5, 8578, 3, 6, 6328, 4, 5, 41487, 4, 6, 9143, // 4, 5 + 3, 6, 7626, 3, 7, 5739, 4, 6, 43626, 4, 7, 8545, // 4, 6 + 3, 7, 6987, 3, 8, 5354, 4, 7, 44999, 4, 8, 8196, // 4, 7 + 4, 8, 44962, 4, 9, 8177, 5, 8, 7029, 5, 9, 5368, // 4, 8 + 4, 9, 43602, 4, 10, 8507, 5, 9, 7678, 5, 10, 5749, // 4, 9 + 4, 10, 41475, 4, 11, 9081, 5, 10, 8646, 5, 11, 6334, // 4,10 + 4, 11, 38966, 4, 12, 9730, 5, 11, 9818, 5, 12, 7022, // 4,11 + 4, 12, 36354, 4, 13, 10337, 5, 12, 11108, 5, 13, 7737, // 4,12 + 4, 13, 33795, 4, 14, 10842, 5, 13, 12467, 5, 14, 8432, // 4,13 + 4, 14, 31361, 4, 15, 11218, 5, 14, 13875, 5, 15, 9082, // 4,14 + 4, 15, 29078, 4, 16, 11461, 5, 15, 15325, 5, 16, 9672, // 4,15 + 4, 0, 15135, 4, 1, 9323, 5, 0, 30064, 5, 1, 11014, // 5, 0 + 4, 1, 13600, 4, 2, 8685, 5, 1, 32586, 5, 2, 10665, // 5, 1 + 4, 2, 12079, 4, 3, 7969, 5, 2, 35332, 5, 3, 10156, // 5, 2 + 4, 3, 10569, 4, 4, 7180, 5, 3, 38307, 5, 4, 9480, // 5, 3 + 4, 4, 9081, 4, 5, 6334, 5, 4, 41475, 5, 5, 8646, // 5, 4 + 4, 5, 7659, 4, 6, 5472, 5, 5, 44700, 5, 6, 7705, // 5, 5 + 4, 6, 6422, 4, 7, 4690, 5, 6, 47630, 5, 7, 6794, // 5, 6 + 4, 7, 5590, 4, 8, 4164, 5, 7, 49588, 5, 8, 6194, // 5, 7 + 5, 8, 49566, 5, 9, 6183, 6, 8, 5615, 6, 9, 4172, // 5, 8 + 5, 9, 47619, 5, 10, 6768, 6, 9, 6455, 6, 10, 4694, // 5, 9 + 5, 10, 44700, 5, 11, 7659, 6, 10, 7705, 6, 11, 5472, // 5,10 + 5, 11, 41487, 5, 12, 8578, 6, 11, 9143, 6, 12, 6328, // 5,11 + 5, 12, 38330, 5, 13, 9388, 6, 12, 10653, 6, 13, 7165, // 5,12 + 5, 13, 35364, 5, 14, 10041, 6, 13, 12188, 6, 14, 7943, // 5,13 + 5, 14, 32624, 5, 15, 10528, 6, 14, 13740, 6, 15, 8644, // 5,14 + 5, 15, 30105, 5, 16, 10855, 6, 15, 15311, 6, 16, 9265, // 5,15 + 5, 0, 15193, 5, 1, 8986, 6, 0, 30876, 6, 1, 10481, // 6, 0 + 5, 1, 13548, 5, 2, 8329, 6, 1, 33585, 6, 2, 10074, // 6, 1 + 5, 2, 11897, 5, 3, 7573, 6, 2, 36582, 6, 3, 9484, // 6, 2 + 5, 3, 10221, 5, 4, 6714, 6, 3, 39912, 6, 4, 8689, // 6, 3 + 5, 4, 8507, 5, 5, 5749, 6, 4, 43602, 6, 5, 7678, // 6, 4 + 5, 5, 6768, 5, 6, 4694, 6, 5, 47619, 6, 6, 6455, // 6, 5 + 5, 6, 5099, 5, 7, 3620, 6, 6, 51701, 6, 7, 5116, // 6, 6 + 5, 7, 3853, 5, 8, 2795, 6, 7, 54839, 6, 8, 4049, // 6, 7 + 6, 8, 54831, 6, 9, 4044, 7, 8, 3864, 7, 9, 2797, // 6, 8 + 6, 9, 51701, 6, 10, 5099, 7, 9, 5116, 7, 10, 3620, // 6, 9 + 6, 10, 47630, 6, 11, 6422, 7, 10, 6794, 7, 11, 4690, // 6,10 + 6, 11, 43626, 6, 12, 7626, 7, 11, 8545, 7, 12, 5739, // 6,11 + 6, 12, 39949, 6, 13, 8617, 7, 12, 10275, 7, 13, 6695, // 6,12 + 6, 13, 36631, 6, 14, 9390, 7, 13, 11972, 7, 14, 7543, // 6,13 + 6, 14, 33642, 6, 15, 9961, 7, 14, 13647, 7, 15, 8286, // 6,14 + 6, 15, 30939, 6, 16, 10351, 7, 15, 15319, 7, 16, 8927, // 6,15 + 6, 0, 15301, 6, 1, 8727, 7, 0, 31444, 7, 1, 10064, // 7, 0 + 6, 1, 13582, 6, 2, 8068, 7, 1, 34261, 7, 2, 9625, // 7, 1 + 6, 2, 11842, 6, 3, 7298, 7, 2, 37402, 7, 3, 8994, // 7, 2 + 6, 3, 10051, 6, 4, 6403, 7, 3, 40940, 7, 4, 8142, // 7, 3 + 6, 4, 8177, 6, 5, 5368, 7, 4, 44962, 7, 5, 7029, // 7, 4 + 6, 5, 6183, 6, 6, 4172, 7, 5, 49566, 7, 6, 5615, // 7, 5 + 6, 6, 4044, 6, 7, 2797, 7, 6, 54831, 7, 7, 3864, // 7, 6 + 6, 7, 1903, 6, 8, 1347, 7, 7, 60382, 7, 8, 1904, // 7, 7 + 7, 8, 60382, 7, 9, 1903, 8, 8, 1905, 8, 9, 1346, // 7, 8 + 7, 9, 54839, 7, 10, 3853, 8, 9, 4049, 8, 10, 2795, // 7, 9 + 7, 10, 49588, 7, 11, 5590, 8, 10, 6193, 8, 11, 4165, // 7,10 + 7, 11, 44999, 7, 12, 6987, 8, 11, 8195, 8, 12, 5355, // 7,11 + 7, 12, 40994, 7, 13, 8082, 8, 12, 10079, 8, 13, 6381, // 7,12 + 7, 13, 37470, 7, 14, 8918, 8, 13, 11883, 8, 14, 7265, // 7,13 + 7, 14, 34340, 7, 15, 9534, 8, 14, 13638, 8, 15, 8024, // 7,14 + 7, 15, 31532, 7, 16, 9959, 8, 15, 15376, 8, 16, 8669, // 7,15 + 7, -1, 8669, 7, 0, 15376, 8, -1, 9959, 8, 0, 31532, // 8, 0 + 7, 0, 8024, 7, 1, 13638, 8, 0, 9534, 8, 1, 34340, // 8, 1 + 7, 1, 7266, 7, 2, 11883, 8, 1, 8918, 8, 2, 37469, // 8, 2 + 7, 2, 6381, 7, 3, 10079, 8, 2, 8082, 8, 3, 40994, // 8, 3 + 7, 3, 5354, 7, 4, 8195, 8, 3, 6987, 8, 4, 45000, // 8, 4 + 7, 4, 4164, 7, 5, 6193, 8, 4, 5590, 8, 5, 49589, // 8, 5 + 7, 5, 2795, 7, 6, 4049, 8, 5, 3853, 8, 6, 54839, // 8, 6 + 7, 6, 1347, 7, 7, 1905, 8, 6, 1903, 8, 7, 60381, // 8, 7 + 8, 7, 1905, 8, 8, 60382, 9, 7, 1347, 9, 8, 1902, // 8, 8 + 8, 8, 3864, 8, 9, 54831, 9, 8, 2797, 9, 9, 4044, // 8, 9 + 8, 9, 5615, 8, 10, 49566, 9, 9, 4172, 9, 10, 6183, // 8,10 + 8, 10, 7029, 8, 11, 44962, 9, 10, 5368, 9, 11, 8177, // 8,11 + 8, 11, 8141, 8, 12, 40940, 9, 11, 6403, 9, 12, 10052, // 8,12 + 8, 12, 8994, 8, 13, 37402, 9, 12, 7298, 9, 13, 11842, // 8,13 + 8, 13, 9626, 8, 14, 34261, 9, 13, 8068, 9, 14, 13581, // 8,14 + 8, 14, 10065, 8, 15, 31444, 9, 14, 8727, 9, 15, 15300, // 8,15 + 8, -1, 8927, 8, 0, 15319, 9, -1, 10351, 9, 0, 30939, // 9, 0 + 8, 0, 8286, 8, 1, 13647, 9, 0, 9961, 9, 1, 33642, // 9, 1 + 8, 1, 7543, 8, 2, 11972, 9, 1, 9390, 9, 2, 36631, // 9, 2 + 8, 2, 6695, 8, 3, 10275, 9, 2, 8617, 9, 3, 39949, // 9, 3 + 8, 3, 5739, 8, 4, 8545, 9, 3, 7626, 9, 4, 43626, // 9, 4 + 8, 4, 4690, 8, 5, 6794, 9, 4, 6422, 9, 5, 47630, // 9, 5 + 8, 5, 3620, 8, 6, 5116, 9, 5, 5099, 9, 6, 51701, // 9, 6 + 8, 6, 2797, 8, 7, 3864, 9, 6, 4044, 9, 7, 54831, // 9, 7 + 9, 7, 4049, 9, 8, 54839, 10, 7, 2795, 10, 8, 3853, // 9, 8 + 9, 8, 5116, 9, 9, 51701, 10, 8, 3620, 10, 9, 5099, // 9, 9 + 9, 9, 6455, 9, 10, 47619, 10, 9, 4694, 10, 10, 6768, // 9,10 + 9, 10, 7678, 9, 11, 43602, 10, 10, 5749, 10, 11, 8507, // 9,11 + 9, 11, 8690, 9, 12, 39912, 10, 11, 6714, 10, 12, 10220, // 9,12 + 9, 12, 9484, 9, 13, 36582, 10, 12, 7573, 10, 13, 11897, // 9,13 + 9, 13, 10074, 9, 14, 33585, 10, 13, 8329, 10, 14, 13548, // 9,14 + 9, 14, 10482, 9, 15, 30876, 10, 14, 8986, 10, 15, 15192, // 9,15 + 9, -1, 9265, 9, 0, 15311, 10, -1, 10855, 10, 0, 30105, // 10, 0 + 9, 0, 8645, 9, 1, 13740, 10, 0, 10528, 10, 1, 32623, // 10, 1 + 9, 1, 7943, 9, 2, 12188, 10, 1, 10041, 10, 2, 35364, // 10, 2 + 9, 2, 7165, 9, 3, 10653, 10, 2, 9388, 10, 3, 38330, // 10, 3 + 9, 3, 6328, 9, 4, 9143, 10, 3, 8578, 10, 4, 41487, // 10, 4 + 9, 4, 5472, 9, 5, 7705, 10, 4, 7659, 10, 5, 44700, // 10, 5 + 9, 5, 4694, 9, 6, 6455, 10, 5, 6768, 10, 6, 47619, // 10, 6 + 9, 6, 4172, 9, 7, 5615, 10, 6, 6183, 10, 7, 49566, // 10, 7 + 10, 7, 6193, 10, 8, 49588, 11, 7, 4164, 11, 8, 5591, // 10, 8 + 10, 8, 6794, 10, 9, 47630, 11, 8, 4690, 11, 9, 6422, // 10, 9 + 10, 9, 7705, 10, 10, 44700, 11, 9, 5472, 11, 10, 7659, // 10,10 + 10, 10, 8646, 10, 11, 41475, 11, 10, 6334, 11, 11, 9081, // 10,11 + 10, 11, 9479, 10, 12, 38307, 11, 11, 7180, 11, 12, 10570, // 10,12 + 10, 12, 10156, 10, 13, 35332, 11, 12, 7969, 11, 13, 12079, // 10,13 + 10, 13, 10665, 10, 14, 32586, 11, 13, 8685, 11, 14, 13600, // 10,14 + 10, 14, 11013, 10, 15, 30064, 11, 14, 9323, 11, 15, 15136, // 10,15 + 10, -1, 9673, 10, 0, 15325, 11, -1, 11461, 11, 0, 29077, // 11, 0 + 10, 0, 9082, 10, 1, 13875, 11, 0, 11218, 11, 1, 31361, // 11, 1 + 10, 1, 8432, 10, 2, 12467, 11, 1, 10842, 11, 2, 33795, // 11, 2 + 10, 2, 7737, 10, 3, 11108, 11, 2, 10337, 11, 3, 36354, // 11, 3 + 10, 3, 7022, 10, 4, 9818, 11, 3, 9730, 11, 4, 38966, // 11, 4 + 10, 4, 6334, 10, 5, 8646, 11, 4, 9081, 11, 5, 41475, // 11, 5 + 10, 5, 5749, 10, 6, 7678, 11, 5, 8507, 11, 6, 43602, // 11, 6 + 10, 6, 5368, 10, 7, 7029, 11, 6, 8177, 11, 7, 44962, // 11, 7 + 11, 7, 8195, 11, 8, 44999, 12, 7, 5354, 12, 8, 6988, // 11, 8 + 11, 8, 8545, 11, 9, 43626, 12, 8, 5739, 12, 9, 7626, // 11, 9 + 11, 9, 9143, 11, 10, 41487, 12, 9, 6328, 12, 10, 8578, // 11,10 + 11, 10, 9818, 11, 11, 38966, 12, 10, 7022, 12, 11, 9730, // 11,11 + 11, 11, 10452, 11, 12, 36343, 12, 11, 7746, 12, 12, 10995, // 11,12 + 11, 12, 10983, 11, 13, 33777, 12, 12, 8452, 12, 13, 12324, // 11,13 + 11, 13, 11385, 11, 14, 31339, 12, 13, 9118, 12, 14, 13694, // 11,14 + 11, 14, 11652, 11, 15, 29055, 12, 14, 9728, 12, 15, 15101, // 11,15 + 11, -1, 10135, 11, 0, 15330, 12, -1, 12159, 12, 0, 27912, // 12, 0 + 11, 0, 9575, 11, 1, 14009, 12, 0, 12014, 12, 1, 29938, // 12, 1 + 11, 1, 8976, 11, 2, 12747, 12, 1, 11760, 12, 2, 32053, // 12, 2 + 11, 2, 8358, 11, 3, 11554, 12, 2, 11411, 12, 3, 34213, // 12, 3 + 11, 3, 7746, 11, 4, 10452, 12, 3, 10995, 12, 4, 36343, // 12, 4 + 11, 4, 7180, 11, 5, 9479, 12, 4, 10569, 12, 5, 38308, // 12, 5 + 11, 5, 6714, 11, 6, 8690, 12, 5, 10221, 12, 6, 39911, // 12, 6 + 11, 6, 6403, 11, 7, 8141, 12, 6, 10051, 12, 7, 40941, // 12, 7 + 12, 7, 10079, 12, 8, 40994, 13, 7, 6381, 13, 8, 8082, // 12, 8 + 12, 8, 10275, 12, 9, 39949, 13, 8, 6695, 13, 9, 8617, // 12, 9 + 12, 9, 10653, 12, 10, 38330, 13, 9, 7165, 13, 10, 9388, // 12,10 + 12, 10, 11108, 12, 11, 36354, 13, 10, 7737, 13, 11, 10337, // 12,11 + 12, 11, 11554, 12, 12, 34213, 13, 11, 8358, 13, 12, 11411, // 12,12 + 12, 12, 11934, 12, 13, 32045, 13, 12, 8988, 13, 13, 12569, // 12,13 + 12, 13, 12216, 12, 14, 29928, 13, 13, 9603, 13, 14, 13789, // 12,14 + 12, 14, 12388, 12, 15, 27903, 13, 14, 10185, 13, 15, 15060, // 12,15 + 12, -1, 10637, 12, 0, 15301, 13, -1, 12938, 13, 0, 26660, // 13, 0 + 12, 0, 10102, 12, 1, 14107, 13, 0, 12897, 13, 1, 28430, // 13, 1 + 12, 1, 9546, 12, 2, 12982, 13, 1, 12769, 13, 2, 30239, // 13, 2 + 12, 2, 8988, 12, 3, 11934, 13, 2, 12569, 13, 3, 32045, // 13, 3 + 12, 3, 8452, 12, 4, 10983, 13, 3, 12323, 13, 4, 33778, // 13, 4 + 12, 4, 7969, 12, 5, 10156, 13, 4, 12079, 13, 5, 35332, // 13, 5 + 12, 5, 7573, 12, 6, 9484, 13, 5, 11897, 13, 6, 36582, // 13, 6 + 12, 6, 7298, 12, 7, 8994, 13, 6, 11842, 13, 7, 37402, // 13, 7 + 13, 7, 11883, 13, 8, 37470, 14, 7, 7266, 14, 8, 8917, // 13, 8 + 13, 8, 11972, 13, 9, 36631, 14, 8, 7543, 14, 9, 9390, // 13, 9 + 13, 9, 12188, 13, 10, 35364, 14, 9, 7943, 14, 10, 10041, // 13,10 + 13, 10, 12467, 13, 11, 33795, 14, 10, 8432, 14, 11, 10842, // 13,11 + 13, 11, 12747, 13, 12, 32052, 14, 11, 8976, 14, 12, 11761, // 13,12 + 13, 12, 12982, 13, 13, 30239, 14, 12, 9546, 14, 13, 12769, // 13,13 + 13, 13, 13141, 13, 14, 28427, 14, 13, 10119, 14, 14, 13849, // 13,14 + 13, 14, 13211, 13, 15, 26660, 14, 14, 10676, 14, 15, 14989, // 13,15 + 13, -1, 11164, 13, 0, 15220, 14, -1, 13787, 14, 0, 25365, // 14, 0 + 13, 0, 10644, 13, 1, 14145, 14, 0, 13853, 14, 1, 26894, // 14, 1 + 13, 1, 10119, 13, 2, 13141, 14, 1, 13850, 14, 2, 28426, // 14, 2 + 13, 2, 9603, 13, 3, 12216, 14, 2, 13789, 14, 3, 29928, // 14, 3 + 13, 3, 9118, 13, 4, 11385, 14, 3, 13694, 14, 4, 31339, // 14, 4 + 13, 4, 8685, 13, 5, 10665, 14, 4, 13600, 14, 5, 32586, // 14, 5 + 13, 5, 8329, 13, 6, 10074, 14, 5, 13548, 14, 6, 33585, // 14, 6 + 13, 6, 8068, 13, 7, 9626, 14, 6, 13582, 14, 7, 34260, // 14, 7 + 14, 7, 13638, 14, 8, 34340, 15, 7, 8024, 15, 8, 9534, // 14, 8 + 14, 8, 13647, 14, 9, 33642, 15, 8, 8286, 15, 9, 9961, // 14, 9 + 14, 9, 13740, 14, 10, 32624, 15, 9, 8645, 15, 10, 10527, // 14,10 + 14, 10, 13875, 14, 11, 31361, 15, 10, 9082, 15, 11, 11218, // 14,11 + 14, 11, 14009, 14, 12, 29938, 15, 11, 9575, 15, 12, 12014, // 14,12 + 14, 12, 14107, 14, 13, 28430, 15, 12, 10102, 15, 13, 12897, // 14,13 + 14, 13, 14145, 14, 14, 26893, 15, 13, 10644, 15, 14, 13854, // 14,14 + 14, 14, 14109, 14, 15, 25368, 15, 14, 11187, 15, 15, 14872, // 14,15 + 14, -1, 11702, 14, 0, 15076, 15, -1, 14696, 15, 0, 24062, // 15, 0 + 14, 0, 11187, 14, 1, 14109, 15, 0, 14872, 15, 1, 25368, // 15, 1 + 14, 1, 10676, 14, 2, 13211, 15, 1, 14990, 15, 2, 26659, // 15, 2 + 14, 2, 10185, 14, 3, 12388, 15, 2, 15060, 15, 3, 27903, // 15, 3 + 14, 3, 9728, 14, 4, 11652, 15, 3, 15100, 15, 4, 29056, // 15, 4 + 14, 4, 9323, 14, 5, 11013, 15, 4, 15135, 15, 5, 30065, // 15, 5 + 14, 5, 8986, 14, 6, 10482, 15, 5, 15193, 15, 6, 30875, // 15, 6 + 14, 6, 8727, 14, 7, 10065, 15, 6, 15301, 15, 7, 31443, // 15, 7 + 15, 7, 15376, 15, 8, 31532, 16, 7, 8669, 16, 8, 9959, // 15, 8 + 15, 8, 15319, 15, 9, 30939, 16, 8, 8927, 16, 9, 10351, // 15, 9 + 15, 9, 15311, 15, 10, 30105, 16, 9, 9265, 16, 10, 10855, // 15,10 + 15, 10, 15325, 15, 11, 29078, 16, 10, 9673, 16, 11, 11460, // 15,11 + 15, 11, 15330, 15, 12, 27912, 16, 11, 10135, 16, 12, 12159, // 15,12 + 15, 12, 15301, 15, 13, 26660, 16, 12, 10637, 16, 13, 12938, // 15,13 + 15, 13, 15220, 15, 14, 25366, 16, 13, 11164, 16, 14, 13786, // 15,14 + 15, 14, 15076, 15, 15, 24063, 16, 14, 11702, 16, 15, 14695, // 15,15 + // angle of -2.0 degrees + -1, 0, 13368, -1, 1, 10104, 0, 0, 28495, 0, 1, 13569, // 0, 0 + -1, 1, 12574, -1, 2, 9662, 0, 1, 29831, 0, 2, 13469, // 0, 1 + -1, 2, 11829, -1, 3, 9229, 0, 2, 31146, 0, 3, 13332, // 0, 2 + -1, 3, 11143, -1, 4, 8816, 0, 3, 32406, 0, 4, 13171, // 0, 3 + -1, 4, 10528, -1, 5, 8438, 0, 4, 33564, 0, 5, 13006, // 0, 4 + -1, 5, 9995, -1, 6, 8107, 0, 5, 34567, 0, 6, 12867, // 0, 5 + -1, 6, 9558, -1, 7, 7839, 0, 6, 35362, 0, 7, 12777, // 0, 6 + -1, 7, 9224, -1, 8, 7643, 0, 7, 35905, 0, 8, 12764, // 0, 7 + 0, 8, 35844, 0, 9, 12728, 1, 8, 9290, 1, 9, 7674, // 0, 8 + 0, 9, 35315, 0, 10, 12717, 1, 9, 9635, 1, 10, 7869, // 0, 9 + 0, 10, 34532, 0, 11, 12783, 1, 10, 10086, 1, 11, 8135, // 0,10 + 0, 11, 33539, 0, 12, 12899, 1, 11, 10635, 1, 12, 8463, // 0,11 + 0, 12, 32391, 0, 13, 13038, 1, 12, 11269, 1, 13, 8838, // 0,12 + 0, 13, 31138, 0, 14, 13176, 1, 13, 11977, 1, 14, 9245, // 0,13 + 0, 14, 29828, 0, 15, 13291, 1, 14, 12746, 1, 15, 9671, // 0,14 + 0, 15, 28495, 0, 16, 13368, 1, 15, 13569, 1, 16, 10104, // 0,15 + 0, 0, 13291, 0, 1, 9671, 1, 0, 29828, 1, 1, 12746, // 1, 0 + 0, 1, 12412, 0, 2, 9202, 1, 1, 31358, 1, 2, 12564, // 1, 1 + 0, 2, 11580, 0, 3, 8735, 1, 2, 32886, 1, 3, 12335, // 1, 2 + 0, 3, 10808, 0, 4, 8284, 1, 3, 34369, 1, 4, 12075, // 1, 3 + 0, 4, 10111, 0, 5, 7865, 1, 4, 35750, 1, 5, 11810, // 1, 4 + 0, 5, 9509, 0, 6, 7497, 1, 5, 36955, 1, 6, 11575, // 1, 5 + 0, 6, 9020, 0, 7, 7202, 1, 6, 37906, 1, 7, 11408, // 1, 6 + 0, 7, 8662, 0, 8, 6997, 1, 7, 38534, 1, 8, 11343, // 1, 7 + 1, 8, 38481, 1, 9, 11317, 2, 8, 8718, 2, 9, 7020, // 1, 8 + 1, 9, 37866, 1, 10, 11360, 2, 9, 9086, 2, 10, 7224, // 1, 9 + 1, 10, 36926, 1, 11, 11507, 2, 10, 9587, 2, 11, 7516, // 1,10 + 1, 11, 35730, 1, 12, 11721, 2, 11, 10204, 2, 12, 7881, // 1,11 + 1, 12, 34358, 1, 13, 11964, 2, 12, 10918, 2, 13, 8296, // 1,12 + 1, 13, 32881, 1, 14, 12203, 2, 13, 11709, 2, 14, 8743, // 1,13 + 1, 14, 31358, 1, 15, 12412, 2, 14, 12564, 2, 15, 9202, // 1,14 + 1, 15, 29831, 1, 16, 12574, 2, 15, 13470, 2, 16, 9661, // 1,15 + 1, 0, 13176, 1, 1, 9245, 2, 0, 31138, 2, 1, 11977, // 2, 0 + 1, 1, 12203, 1, 2, 8742, 2, 1, 32881, 2, 2, 11710, // 2, 1 + 1, 2, 11272, 1, 3, 8232, 2, 2, 34650, 2, 3, 11382, // 2, 2 + 1, 3, 10397, 1, 4, 7728, 2, 3, 36399, 2, 4, 11012, // 2, 3 + 1, 4, 9597, 1, 5, 7252, 2, 4, 38057, 2, 5, 10630, // 2, 4 + 1, 5, 8902, 1, 6, 6829, 2, 5, 39526, 2, 6, 10279, // 2, 5 + 1, 6, 8344, 1, 7, 6491, 2, 6, 40688, 2, 7, 10013, // 2, 6 + 1, 7, 7951, 1, 8, 6266, 2, 7, 41432, 2, 8, 9887, // 2, 7 + 2, 8, 41389, 2, 9, 9867, 3, 8, 7996, 3, 9, 6284, // 2, 8 + 2, 9, 40656, 2, 10, 9977, 3, 9, 8397, 3, 10, 6506, // 2, 9 + 2, 10, 39503, 2, 11, 10226, 3, 10, 8966, 3, 11, 6841, // 2,10 + 2, 11, 38042, 2, 12, 10559, 3, 11, 9674, 3, 12, 7261, // 2,11 + 2, 12, 36392, 2, 13, 10922, 3, 12, 10488, 3, 13, 7734, // 2,12 + 2, 13, 34650, 2, 14, 11272, 3, 13, 11382, 3, 14, 8232, // 2,13 + 2, 14, 32886, 2, 15, 11580, 3, 14, 12334, 3, 15, 8736, // 2,14 + 2, 15, 31146, 2, 16, 11829, 3, 15, 13332, 3, 16, 9229, // 2,15 + 2, 0, 13038, 2, 1, 8838, 3, 0, 32391, 3, 1, 11269, // 3, 0 + 2, 1, 11964, 2, 2, 8296, 3, 1, 34358, 3, 2, 10918, // 3, 1 + 2, 2, 10922, 2, 3, 7734, 3, 2, 36392, 3, 3, 10488, // 3, 2 + 2, 3, 9924, 2, 4, 7164, 3, 3, 38450, 3, 4, 9998, // 3, 3 + 2, 4, 8995, 2, 5, 6611, 3, 4, 40452, 3, 5, 9478, // 3, 4 + 2, 5, 8175, 2, 6, 6108, 3, 5, 42271, 3, 6, 8982, // 3, 5 + 2, 6, 7516, 2, 7, 5703, 3, 6, 43733, 3, 7, 8584, // 3, 6 + 2, 7, 7072, 2, 8, 5443, 3, 7, 44649, 3, 8, 8372, // 3, 7 + 3, 8, 44616, 3, 9, 8359, 4, 8, 7106, 4, 9, 5455, // 3, 8 + 3, 9, 43710, 3, 10, 8558, 4, 9, 7556, 4, 10, 5712, // 3, 9 + 3, 10, 42256, 3, 11, 8940, 4, 10, 8224, 4, 11, 6116, // 3,10 + 3, 11, 40444, 3, 12, 9421, 4, 11, 9056, 4, 12, 6615, // 3,11 + 3, 12, 38450, 3, 13, 9924, 4, 12, 9998, 4, 13, 7164, // 3,12 + 3, 13, 36399, 3, 14, 10397, 4, 13, 11012, 4, 14, 7728, // 3,13 + 3, 14, 34369, 3, 15, 10808, 4, 14, 12074, 4, 15, 8285, // 3,14 + 3, 15, 32406, 3, 16, 11143, 4, 15, 13171, 4, 16, 8816, // 3,15 + 3, 0, 12899, 3, 1, 8463, 4, 0, 33539, 4, 1, 10635, // 4, 0 + 3, 1, 11721, 3, 2, 7881, 4, 1, 35730, 4, 2, 10204, // 4, 1 + 3, 2, 10559, 3, 3, 7261, 4, 2, 38042, 4, 3, 9674, // 4, 2 + 3, 3, 9421, 3, 4, 6615, 4, 3, 40444, 4, 4, 9056, // 4, 3 + 3, 4, 8332, 3, 5, 5965, 4, 4, 42861, 4, 5, 8378, // 4, 4 + 3, 5, 7342, 3, 6, 5350, 4, 5, 45146, 4, 6, 7698, // 4, 5 + 3, 6, 6530, 3, 7, 4838, 4, 6, 47049, 4, 7, 7119, // 4, 6 + 3, 7, 6000, 3, 8, 4513, 4, 7, 48240, 4, 8, 6783, // 4, 7 + 4, 8, 48218, 4, 9, 6774, 5, 8, 6023, 5, 9, 4521, // 4, 8 + 4, 9, 47035, 4, 10, 7100, 5, 9, 6558, 5, 10, 4843, // 4, 9 + 4, 10, 45139, 4, 11, 7667, 5, 10, 7377, 5, 11, 5353, // 4,10 + 4, 11, 42861, 4, 12, 8332, 5, 11, 8378, 5, 12, 5965, // 4,11 + 4, 12, 40452, 4, 13, 8995, 5, 12, 9478, 5, 13, 6611, // 4,12 + 4, 13, 38057, 4, 14, 9597, 5, 13, 10630, 5, 14, 7252, // 4,13 + 4, 14, 35750, 4, 15, 10111, 5, 14, 11810, 5, 15, 7865, // 4,14 + 4, 15, 33564, 4, 16, 10528, 5, 15, 13007, 5, 16, 8437, // 4,15 + 4, 0, 12783, 4, 1, 8135, 5, 0, 34532, 5, 1, 10086, // 5, 0 + 4, 1, 11507, 4, 2, 7517, 5, 1, 36926, 5, 2, 9586, // 5, 1 + 4, 2, 10226, 4, 3, 6842, 5, 2, 39503, 5, 3, 8965, // 5, 2 + 4, 3, 8940, 4, 4, 6116, 5, 3, 42256, 5, 4, 8224, // 5, 3 + 4, 4, 7667, 4, 5, 5353, 5, 4, 45139, 5, 5, 7377, // 5, 4 + 4, 5, 6451, 4, 6, 4591, 5, 5, 48019, 5, 6, 6475, // 5, 5 + 4, 6, 5400, 4, 7, 3911, 5, 6, 50587, 5, 7, 5638, // 5, 6 + 4, 7, 4708, 4, 8, 3466, 5, 7, 52266, 5, 8, 5096, // 5, 7 + 5, 8, 52253, 5, 9, 5092, 6, 8, 4721, 6, 9, 3470, // 5, 8 + 5, 9, 50581, 5, 10, 5624, 6, 9, 5418, 6, 10, 3913, // 5, 9 + 5, 10, 48019, 5, 11, 6451, 6, 10, 6475, 6, 11, 4591, // 5,10 + 5, 11, 45146, 5, 12, 7342, 6, 11, 7698, 6, 12, 5350, // 5,11 + 5, 12, 42271, 5, 13, 8175, 6, 12, 8982, 6, 13, 6108, // 5,12 + 5, 13, 39526, 5, 14, 8902, 6, 13, 10279, 6, 14, 6829, // 5,13 + 5, 14, 36955, 5, 15, 9509, 6, 14, 11575, 6, 15, 7497, // 5,14 + 5, 15, 34567, 5, 16, 9995, 6, 15, 12867, 6, 16, 8107, // 5,15 + 5, 0, 12717, 5, 1, 7868, 6, 0, 35315, 6, 1, 9636, // 6, 0 + 5, 1, 11360, 5, 2, 7224, 6, 1, 37866, 6, 2, 9086, // 6, 1 + 5, 2, 9977, 5, 3, 6506, 6, 2, 40656, 6, 3, 8397, // 6, 2 + 5, 3, 8558, 5, 4, 5712, 6, 3, 43710, 6, 4, 7556, // 6, 3 + 5, 4, 7100, 5, 5, 4843, 6, 4, 47035, 6, 5, 6558, // 6, 4 + 5, 5, 5624, 5, 6, 3913, 6, 5, 50581, 6, 6, 5418, // 6, 5 + 5, 6, 4217, 5, 7, 2989, 6, 6, 54105, 6, 7, 4225, // 6, 6 + 5, 7, 3180, 5, 8, 2294, 6, 7, 56756, 6, 8, 3306, // 6, 7 + 6, 8, 56751, 6, 9, 3303, 7, 8, 3186, 7, 9, 2296, // 6, 8 + 6, 9, 54105, 6, 10, 4217, 7, 9, 4225, 7, 10, 2989, // 6, 9 + 6, 10, 50587, 6, 11, 5400, 7, 10, 5637, 7, 11, 3912, // 6,10 + 6, 11, 47049, 6, 12, 6530, 7, 11, 7119, 7, 12, 4838, // 6,11 + 6, 12, 43733, 6, 13, 7516, 7, 12, 8584, 7, 13, 5703, // 6,12 + 6, 13, 40688, 6, 14, 8344, 7, 13, 10013, 7, 14, 6491, // 6,13 + 6, 14, 37906, 6, 15, 9020, 7, 14, 11407, 7, 15, 7203, // 6,14 + 6, 15, 35362, 6, 16, 9558, 7, 15, 12777, 7, 16, 7839, // 6,15 + 6, 0, 12728, 6, 1, 7674, 7, 0, 35844, 7, 1, 9290, // 7, 0 + 6, 1, 11317, 6, 2, 7020, 7, 1, 38481, 7, 2, 8718, // 7, 1 + 6, 2, 9867, 6, 3, 6284, 7, 2, 41389, 7, 3, 7996, // 7, 2 + 6, 3, 8359, 6, 4, 5454, 7, 3, 44616, 7, 4, 7107, // 7, 3 + 6, 4, 6774, 6, 5, 4521, 7, 4, 48218, 7, 5, 6023, // 7, 4 + 6, 5, 5092, 6, 6, 3470, 7, 5, 52253, 7, 6, 4721, // 7, 5 + 6, 6, 3303, 6, 7, 2295, 7, 6, 56751, 7, 7, 3187, // 7, 6 + 6, 7, 1541, 6, 8, 1090, 7, 7, 61364, 7, 8, 1541, // 7, 7 + 7, 8, 61364, 7, 9, 1541, 8, 8, 1542, 8, 9, 1089, // 7, 8 + 7, 9, 56756, 7, 10, 3180, 8, 9, 3306, 8, 10, 2294, // 7, 9 + 7, 10, 52266, 7, 11, 4708, 8, 10, 5097, 8, 11, 3465, // 7,10 + 7, 11, 48240, 7, 12, 6000, 8, 11, 6783, 8, 12, 4513, // 7,11 + 7, 12, 44649, 7, 13, 7072, 8, 12, 8373, 8, 13, 5442, // 7,12 + 7, 13, 41432, 7, 14, 7951, 8, 13, 9886, 8, 14, 6267, // 7,13 + 7, 14, 38534, 7, 15, 8662, 8, 14, 11344, 8, 15, 6996, // 7,14 + 7, 15, 35905, 7, 16, 9224, 8, 15, 12764, 8, 16, 7643, // 7,15 + 7, -1, 7643, 7, 0, 12764, 8, -1, 9224, 8, 0, 35905, // 8, 0 + 7, 0, 6997, 7, 1, 11344, 8, 0, 8662, 8, 1, 38533, // 8, 1 + 7, 1, 6266, 7, 2, 9886, 8, 1, 7951, 8, 2, 41433, // 8, 2 + 7, 2, 5443, 7, 3, 8373, 8, 2, 7072, 8, 3, 44648, // 8, 3 + 7, 3, 4513, 7, 4, 6783, 8, 3, 6000, 8, 4, 48240, // 8, 4 + 7, 4, 3466, 7, 5, 5097, 8, 4, 4708, 8, 5, 52265, // 8, 5 + 7, 5, 2294, 7, 6, 3306, 8, 5, 3180, 8, 6, 56756, // 8, 6 + 7, 6, 1090, 7, 7, 1542, 8, 6, 1541, 8, 7, 61363, // 8, 7 + 8, 7, 1542, 8, 8, 61364, 9, 7, 1090, 9, 8, 1540, // 8, 8 + 8, 8, 3186, 8, 9, 56751, 9, 8, 2295, 9, 9, 3304, // 8, 9 + 8, 9, 4721, 8, 10, 52253, 9, 9, 3470, 9, 10, 5092, // 8,10 + 8, 10, 6023, 8, 11, 48218, 9, 10, 4521, 9, 11, 6774, // 8,11 + 8, 11, 7106, 8, 12, 44616, 9, 11, 5454, 9, 12, 8360, // 8,12 + 8, 12, 7996, 8, 13, 41389, 9, 12, 6284, 9, 13, 9867, // 8,13 + 8, 13, 8718, 8, 14, 38481, 9, 13, 7020, 9, 14, 11317, // 8,14 + 8, 14, 9290, 8, 15, 35844, 9, 14, 7674, 9, 15, 12728, // 8,15 + 8, -1, 7839, 8, 0, 12777, 9, -1, 9558, 9, 0, 35362, // 9, 0 + 8, 0, 7202, 8, 1, 11407, 9, 0, 9020, 9, 1, 37907, // 9, 1 + 8, 1, 6491, 8, 2, 10013, 9, 1, 8344, 9, 2, 40688, // 9, 2 + 8, 2, 5703, 8, 3, 8584, 9, 2, 7516, 9, 3, 43733, // 9, 3 + 8, 3, 4838, 8, 4, 7119, 9, 3, 6530, 9, 4, 47049, // 9, 4 + 8, 4, 3911, 8, 5, 5637, 9, 4, 5400, 9, 5, 50588, // 9, 5 + 8, 5, 2989, 8, 6, 4225, 9, 5, 4217, 9, 6, 54105, // 9, 6 + 8, 6, 2295, 8, 7, 3186, 9, 6, 3303, 9, 7, 56752, // 9, 7 + 9, 7, 3306, 9, 8, 56756, 10, 7, 2294, 10, 8, 3180, // 9, 8 + 9, 8, 4225, 9, 9, 54105, 10, 8, 2989, 10, 9, 4217, // 9, 9 + 9, 9, 5418, 9, 10, 50581, 10, 9, 3913, 10, 10, 5624, // 9,10 + 9, 10, 6558, 9, 11, 47035, 10, 10, 4843, 10, 11, 7100, // 9,11 + 9, 11, 7556, 9, 12, 43710, 10, 11, 5712, 10, 12, 8558, // 9,12 + 9, 12, 8397, 9, 13, 40656, 10, 12, 6506, 10, 13, 9977, // 9,13 + 9, 13, 9086, 9, 14, 37866, 10, 13, 7224, 10, 14, 11360, // 9,14 + 9, 14, 9635, 9, 15, 35315, 10, 14, 7868, 10, 15, 12718, // 9,15 + 9, -1, 8107, 9, 0, 12867, 10, -1, 9995, 10, 0, 34567, // 10, 0 + 9, 0, 7497, 9, 1, 11575, 10, 0, 9509, 10, 1, 36955, // 10, 1 + 9, 1, 6829, 9, 2, 10279, 10, 1, 8902, 10, 2, 39526, // 10, 2 + 9, 2, 6108, 9, 3, 8982, 10, 2, 8175, 10, 3, 42271, // 10, 3 + 9, 3, 5350, 9, 4, 7698, 10, 3, 7342, 10, 4, 45146, // 10, 4 + 9, 4, 4591, 9, 5, 6475, 10, 4, 6451, 10, 5, 48019, // 10, 5 + 9, 5, 3913, 9, 6, 5418, 10, 5, 5624, 10, 6, 50581, // 10, 6 + 9, 6, 3470, 9, 7, 4721, 10, 6, 5092, 10, 7, 52253, // 10, 7 + 10, 7, 5097, 10, 8, 52266, 11, 7, 3466, 11, 8, 4707, // 10, 8 + 10, 8, 5637, 10, 9, 50587, 11, 8, 3911, 11, 9, 5401, // 10, 9 + 10, 9, 6475, 10, 10, 48019, 11, 9, 4591, 11, 10, 6451, // 10,10 + 10, 10, 7377, 10, 11, 45139, 11, 10, 5353, 11, 11, 7667, // 10,11 + 10, 11, 8224, 10, 12, 42256, 11, 11, 6116, 11, 12, 8940, // 10,12 + 10, 12, 8966, 10, 13, 39503, 11, 12, 6842, 11, 13, 10225, // 10,13 + 10, 13, 9587, 10, 14, 36926, 11, 13, 7517, 11, 14, 11506, // 10,14 + 10, 14, 10086, 10, 15, 34532, 11, 14, 8135, 11, 15, 12783, // 10,15 + 10, -1, 8438, 10, 0, 13007, 11, -1, 10528, 11, 0, 33563, // 11, 0 + 10, 0, 7865, 10, 1, 11810, 11, 0, 10111, 11, 1, 35750, // 11, 1 + 10, 1, 7252, 10, 2, 10630, 11, 1, 9597, 11, 2, 38057, // 11, 2 + 10, 2, 6611, 10, 3, 9478, 11, 2, 8995, 11, 3, 40452, // 11, 3 + 10, 3, 5965, 10, 4, 8378, 11, 3, 8332, 11, 4, 42861, // 11, 4 + 10, 4, 5353, 10, 5, 7377, 11, 4, 7667, 11, 5, 45139, // 11, 5 + 10, 5, 4843, 10, 6, 6558, 11, 5, 7100, 11, 6, 47035, // 11, 6 + 10, 6, 4521, 10, 7, 6023, 11, 6, 6774, 11, 7, 48218, // 11, 7 + 11, 7, 6783, 11, 8, 48240, 12, 7, 4513, 12, 8, 6000, // 11, 8 + 11, 8, 7119, 11, 9, 47049, 12, 8, 4838, 12, 9, 6530, // 11, 9 + 11, 9, 7698, 11, 10, 45146, 12, 9, 5350, 12, 10, 7342, // 11,10 + 11, 10, 8378, 11, 11, 42861, 12, 10, 5965, 12, 11, 8332, // 11,11 + 11, 11, 9056, 11, 12, 40444, 12, 11, 6615, 12, 12, 9421, // 11,12 + 11, 12, 9674, 11, 13, 38042, 12, 12, 7261, 12, 13, 10559, // 11,13 + 11, 13, 10204, 11, 14, 35730, 12, 13, 7881, 12, 14, 11721, // 11,14 + 11, 14, 10635, 11, 15, 33539, 12, 14, 8463, 12, 15, 12899, // 11,15 + 11, -1, 8816, 11, 0, 13171, 12, -1, 11143, 12, 0, 32406, // 12, 0 + 11, 0, 8284, 11, 1, 12074, 12, 0, 10808, 12, 1, 34370, // 12, 1 + 11, 1, 7728, 11, 2, 11012, 12, 1, 10397, 12, 2, 36399, // 12, 2 + 11, 2, 7164, 11, 3, 9998, 12, 2, 9924, 12, 3, 38450, // 12, 3 + 11, 3, 6615, 11, 4, 9056, 12, 3, 9421, 12, 4, 40444, // 12, 4 + 11, 4, 6116, 11, 5, 8224, 12, 4, 8940, 12, 5, 42256, // 12, 5 + 11, 5, 5712, 11, 6, 7556, 12, 5, 8558, 12, 6, 43710, // 12, 6 + 11, 6, 5454, 11, 7, 7106, 12, 6, 8359, 12, 7, 44617, // 12, 7 + 12, 7, 8373, 12, 8, 44649, 13, 7, 5443, 13, 8, 7071, // 12, 8 + 12, 8, 8584, 12, 9, 43733, 13, 8, 5703, 13, 9, 7516, // 12, 9 + 12, 9, 8982, 12, 10, 42271, 13, 9, 6108, 13, 10, 8175, // 12,10 + 12, 10, 9478, 12, 11, 40452, 13, 10, 6611, 13, 11, 8995, // 12,11 + 12, 11, 9998, 12, 12, 38450, 13, 11, 7164, 13, 12, 9924, // 12,12 + 12, 12, 10488, 12, 13, 36392, 13, 12, 7734, 13, 13, 10922, // 12,13 + 12, 13, 10918, 12, 14, 34358, 13, 13, 8296, 13, 14, 11964, // 12,14 + 12, 14, 11269, 12, 15, 32391, 13, 14, 8838, 13, 15, 13038, // 12,15 + 12, -1, 9229, 12, 0, 13332, 13, -1, 11829, 13, 0, 31146, // 13, 0 + 12, 0, 8735, 12, 1, 12334, 13, 0, 11580, 13, 1, 32887, // 13, 1 + 12, 1, 8232, 12, 2, 11382, 13, 1, 11272, 13, 2, 34650, // 13, 2 + 12, 2, 7734, 12, 3, 10488, 13, 2, 10922, 13, 3, 36392, // 13, 3 + 12, 3, 7261, 12, 4, 9674, 13, 3, 10559, 13, 4, 38042, // 13, 4 + 12, 4, 6842, 12, 5, 8966, 13, 4, 10226, 13, 5, 39502, // 13, 5 + 12, 5, 6506, 12, 6, 8397, 13, 5, 9977, 13, 6, 40656, // 13, 6 + 12, 6, 6284, 12, 7, 7996, 13, 6, 9867, 13, 7, 41389, // 13, 7 + 13, 7, 9886, 13, 8, 41432, 14, 7, 6266, 14, 8, 7952, // 13, 8 + 13, 8, 10013, 13, 9, 40688, 14, 8, 6491, 14, 9, 8344, // 13, 9 + 13, 9, 10279, 13, 10, 39526, 14, 9, 6829, 14, 10, 8902, // 13,10 + 13, 10, 10630, 13, 11, 38057, 14, 10, 7252, 14, 11, 9597, // 13,11 + 13, 11, 11012, 13, 12, 36399, 14, 11, 7728, 14, 12, 10397, // 13,12 + 13, 12, 11382, 13, 13, 34650, 14, 12, 8232, 14, 13, 11272, // 13,13 + 13, 13, 11709, 13, 14, 32881, 14, 13, 8742, 14, 14, 12204, // 13,14 + 13, 14, 11977, 13, 15, 31138, 14, 14, 9245, 14, 15, 13176, // 13,15 + 13, -1, 9662, 13, 0, 13470, 14, -1, 12574, 14, 0, 29830, // 14, 0 + 13, 0, 9202, 13, 1, 12564, 14, 0, 12412, 14, 1, 31358, // 14, 1 + 13, 1, 8742, 13, 2, 11709, 14, 1, 12203, 14, 2, 32882, // 14, 2 + 13, 2, 8296, 13, 3, 10918, 14, 2, 11964, 14, 3, 34358, // 14, 3 + 13, 3, 7881, 13, 4, 10204, 14, 3, 11721, 14, 4, 35730, // 14, 4 + 13, 4, 7517, 13, 5, 9587, 14, 4, 11507, 14, 5, 36925, // 14, 5 + 13, 5, 7224, 13, 6, 9086, 14, 5, 11360, 14, 6, 37866, // 14, 6 + 13, 6, 7020, 13, 7, 8718, 14, 6, 11317, 14, 7, 38481, // 14, 7 + 14, 7, 11344, 14, 8, 38534, 15, 7, 6997, 15, 8, 8661, // 14, 8 + 14, 8, 11407, 14, 9, 37906, 15, 8, 7202, 15, 9, 9021, // 14, 9 + 14, 9, 11575, 14, 10, 36955, 15, 9, 7497, 15, 10, 9509, // 14,10 + 14, 10, 11810, 14, 11, 35750, 15, 10, 7865, 15, 11, 10111, // 14,11 + 14, 11, 12074, 14, 12, 34369, 15, 11, 8284, 15, 12, 10809, // 14,12 + 14, 12, 12334, 14, 13, 32886, 15, 12, 8735, 15, 13, 11581, // 14,13 + 14, 13, 12564, 14, 14, 31358, 15, 13, 9202, 15, 14, 12412, // 14,14 + 14, 14, 12746, 14, 15, 29828, 15, 14, 9671, 15, 15, 13291, // 14,15 + 14, -1, 10104, 14, 0, 13569, 15, -1, 13368, 15, 0, 28495, // 15, 0 + 14, 0, 9671, 14, 1, 12746, 15, 0, 13291, 15, 1, 29828, // 15, 1 + 14, 1, 9245, 14, 2, 11977, 15, 1, 13176, 15, 2, 31138, // 15, 2 + 14, 2, 8838, 14, 3, 11269, 15, 2, 13038, 15, 3, 32391, // 15, 3 + 14, 3, 8463, 14, 4, 10635, 15, 3, 12899, 15, 4, 33539, // 15, 4 + 14, 4, 8135, 14, 5, 10086, 15, 4, 12783, 15, 5, 34532, // 15, 5 + 14, 5, 7868, 14, 6, 9635, 15, 5, 12717, 15, 6, 35316, // 15, 6 + 14, 6, 7674, 14, 7, 9290, 15, 6, 12728, 15, 7, 35844, // 15, 7 + 15, 7, 12764, 15, 8, 35905, 16, 7, 7643, 16, 8, 9224, // 15, 8 + 15, 8, 12777, 15, 9, 35362, 16, 8, 7839, 16, 9, 9558, // 15, 9 + 15, 9, 12867, 15, 10, 34567, 16, 9, 8107, 16, 10, 9995, // 15,10 + 15, 10, 13007, 15, 11, 33564, 16, 10, 8438, 16, 11, 10527, // 15,11 + 15, 11, 13171, 15, 12, 32406, 16, 11, 8816, 16, 12, 11143, // 15,12 + 15, 12, 13332, 15, 13, 31146, 16, 12, 9229, 16, 13, 11829, // 15,13 + 15, 13, 13470, 15, 14, 29831, 16, 13, 9662, 16, 14, 12573, // 15,14 + 15, 14, 13569, 15, 15, 28495, 16, 14, 10104, 16, 15, 13368, // 15,15 + // angle of -1.5 degrees + -1, 0, 11440, -1, 1, 8358, 0, 0, 34212, 0, 1, 11526, // 0, 0 + -1, 1, 10780, -1, 2, 7983, 0, 1, 35506, 0, 2, 11267, // 0, 1 + -1, 2, 10158, -1, 3, 7620, 0, 2, 36764, 0, 3, 10994, // 0, 2 + -1, 3, 9585, -1, 4, 7276, 0, 3, 37951, 0, 4, 10724, // 0, 3 + -1, 4, 9072, -1, 5, 6965, 0, 4, 39026, 0, 5, 10473, // 0, 4 + -1, 5, 8632, -1, 6, 6699, 0, 5, 39940, 0, 6, 10265, // 0, 5 + -1, 6, 8278, -1, 7, 6489, 0, 6, 40646, 0, 7, 10123, // 0, 6 + -1, 7, 8018, -1, 8, 6346, 0, 7, 41106, 0, 8, 10066, // 0, 7 + 0, 8, 41072, 0, 9, 10052, 1, 8, 8052, 1, 9, 6360, // 0, 8 + 0, 9, 40618, 0, 10, 10100, 1, 9, 8316, 1, 10, 6502, // 0, 9 + 0, 10, 39918, 0, 11, 10232, 1, 10, 8676, 1, 11, 6710, // 0,10 + 0, 11, 39009, 0, 12, 10430, 1, 11, 9122, 1, 12, 6975, // 0,11 + 0, 12, 37939, 0, 13, 10670, 1, 12, 9642, 1, 13, 7285, // 0,12 + 0, 13, 36756, 0, 14, 10930, 1, 13, 10224, 1, 14, 7626, // 0,13 + 0, 14, 35502, 0, 15, 11192, 1, 14, 10855, 1, 15, 7987, // 0,14 + 0, 15, 34212, 0, 16, 11440, 1, 15, 11526, 1, 16, 8358, // 0,15 + 0, 0, 11192, 0, 1, 7987, 1, 0, 35502, 1, 1, 10855, // 1, 0 + 0, 1, 10467, 0, 2, 7579, 1, 1, 36959, 1, 2, 10531, // 1, 1 + 0, 2, 9777, 0, 3, 7177, 1, 2, 38394, 1, 3, 10188, // 1, 2 + 0, 3, 9135, 0, 4, 6792, 1, 3, 39767, 1, 4, 9842, // 1, 3 + 0, 4, 8557, 0, 5, 6440, 1, 4, 41026, 1, 5, 9513, // 1, 4 + 0, 5, 8061, 0, 6, 6137, 1, 5, 42105, 1, 6, 9233, // 1, 5 + 0, 6, 7667, 0, 7, 5900, 1, 6, 42936, 1, 7, 9033, // 1, 6 + 0, 7, 7390, 0, 8, 5745, 1, 7, 43461, 1, 8, 8940, // 1, 7 + 1, 8, 43433, 1, 9, 8929, 2, 8, 7418, 2, 9, 5756, // 1, 8 + 1, 9, 42913, 1, 10, 9014, 2, 9, 7699, 2, 10, 5910, // 1, 9 + 1, 10, 42087, 1, 11, 9206, 2, 10, 8098, 2, 11, 6145, // 1,10 + 1, 11, 41013, 1, 12, 9478, 2, 11, 8599, 2, 12, 6446, // 1,11 + 1, 12, 39759, 1, 13, 9796, 2, 12, 9184, 2, 13, 6797, // 1,12 + 1, 13, 38390, 1, 14, 10133, 2, 13, 9834, 2, 14, 7179, // 1,13 + 1, 14, 36959, 1, 15, 10467, 2, 14, 10532, 2, 15, 7578, // 1,14 + 1, 15, 35506, 1, 16, 10780, 2, 15, 11267, 2, 16, 7983, // 1,15 + 1, 0, 10930, 1, 1, 7626, 2, 0, 36756, 2, 1, 10224, // 2, 0 + 1, 1, 10133, 1, 2, 7179, 2, 1, 38390, 2, 2, 9834, // 2, 1 + 1, 2, 9366, 1, 3, 6732, 2, 2, 40025, 2, 3, 9413, // 2, 2 + 1, 3, 8641, 1, 4, 6297, 2, 3, 41618, 2, 4, 8980, // 2, 3 + 1, 4, 7981, 1, 5, 5891, 2, 4, 43105, 2, 5, 8559, // 2, 4 + 1, 5, 7411, 1, 6, 5537, 2, 5, 44399, 2, 6, 8189, // 2, 5 + 1, 6, 6961, 1, 7, 5261, 2, 6, 45401, 2, 7, 7913, // 2, 6 + 1, 7, 6658, 1, 8, 5087, 2, 7, 46017, 2, 8, 7774, // 2, 7 + 2, 8, 45995, 2, 9, 7766, 3, 8, 6680, 3, 9, 5095, // 2, 8 + 2, 9, 45383, 2, 10, 7899, 3, 9, 6986, 3, 10, 5268, // 2, 9 + 2, 10, 44386, 2, 11, 8167, 3, 10, 7440, 3, 11, 5543, // 2,10 + 2, 11, 43096, 2, 12, 8530, 3, 11, 8015, 3, 12, 5895, // 2,11 + 2, 12, 41614, 2, 13, 8941, 3, 12, 8681, 3, 13, 6300, // 2,12 + 2, 13, 40025, 2, 14, 9366, 3, 13, 9413, 3, 14, 6732, // 2,13 + 2, 14, 38394, 2, 15, 9777, 3, 14, 10188, 3, 15, 7177, // 2,14 + 2, 15, 36764, 2, 16, 10158, 3, 15, 10994, 3, 16, 7620, // 2,15 + 2, 0, 10670, 2, 1, 7285, 3, 0, 37939, 3, 1, 9642, // 3, 0 + 2, 1, 9796, 2, 2, 6797, 3, 1, 39759, 3, 2, 9184, // 3, 1 + 2, 2, 8941, 2, 3, 6299, 3, 2, 41614, 3, 3, 8682, // 3, 2 + 2, 3, 8120, 2, 4, 5804, 3, 3, 43461, 3, 4, 8151, // 3, 3 + 2, 4, 7356, 2, 5, 5330, 3, 4, 45229, 3, 5, 7621, // 3, 4 + 2, 5, 6685, 2, 6, 4906, 3, 5, 46806, 3, 6, 7139, // 3, 5 + 2, 6, 6154, 2, 7, 4572, 3, 6, 48049, 3, 7, 6761, // 3, 6 + 2, 7, 5811, 2, 8, 4366, 3, 7, 48801, 3, 8, 6558, // 3, 7 + 3, 8, 48785, 3, 9, 6552, 4, 8, 5827, 4, 9, 4372, // 3, 8 + 3, 9, 48037, 3, 10, 6750, 4, 9, 6173, 4, 10, 4576, // 3, 9 + 3, 10, 46798, 3, 11, 7121, 4, 10, 6707, 4, 11, 4910, // 3,10 + 3, 11, 45224, 3, 12, 7598, 4, 11, 7382, 4, 12, 5332, // 3,11 + 3, 12, 43461, 3, 13, 8120, 4, 12, 8151, 4, 13, 5804, // 3,12 + 3, 13, 41618, 3, 14, 8641, 4, 13, 8979, 4, 14, 6298, // 3,13 + 3, 14, 39767, 3, 15, 9135, 4, 14, 9841, 4, 15, 6793, // 3,14 + 3, 15, 37951, 3, 16, 9585, 4, 15, 10723, 4, 16, 7277, // 3,15 + 3, 0, 10430, 3, 1, 6975, 4, 0, 39009, 4, 1, 9122, // 4, 0 + 3, 1, 9478, 3, 2, 6447, 4, 1, 41013, 4, 2, 8598, // 4, 1 + 3, 2, 8530, 3, 3, 5895, 4, 2, 43096, 4, 3, 8015, // 4, 2 + 3, 3, 7598, 3, 4, 5331, 4, 3, 45224, 4, 4, 7383, // 4, 3 + 3, 4, 6708, 3, 5, 4774, 4, 4, 47328, 4, 5, 6726, // 4, 4 + 3, 5, 5901, 3, 6, 4257, 4, 5, 49279, 4, 6, 6099, // 4, 5 + 3, 6, 5248, 3, 7, 3834, 4, 6, 50873, 4, 7, 5581, // 4, 6 + 3, 7, 4835, 3, 8, 3575, 4, 7, 51842, 4, 8, 5284, // 4, 7 + 4, 8, 51832, 4, 9, 5280, 5, 8, 4846, 5, 9, 3578, // 4, 8 + 4, 9, 50865, 4, 10, 5573, 5, 9, 5261, 5, 10, 3837, // 4, 9 + 4, 10, 49275, 4, 11, 6086, 5, 10, 5917, 5, 11, 4258, // 4,10 + 4, 11, 47328, 4, 12, 6708, 5, 11, 6727, 5, 12, 4773, // 4,11 + 4, 12, 45229, 4, 13, 7356, 5, 12, 7622, 5, 13, 5329, // 4,12 + 4, 13, 43105, 4, 14, 7981, 5, 13, 8559, 5, 14, 5891, // 4,13 + 4, 14, 41026, 4, 15, 8557, 5, 14, 9513, 5, 15, 6440, // 4,14 + 4, 15, 39026, 4, 16, 9072, 5, 15, 10473, 5, 16, 6965, // 4,15 + 4, 0, 10232, 4, 1, 6710, 5, 0, 39918, 5, 1, 8676, // 5, 0 + 4, 1, 9206, 4, 2, 6145, 5, 1, 42087, 5, 2, 8098, // 5, 1 + 4, 2, 8167, 4, 3, 5543, 5, 2, 44386, 5, 3, 7440, // 5, 2 + 4, 3, 7121, 4, 4, 4909, 5, 3, 46798, 5, 4, 6708, // 5, 3 + 4, 4, 6086, 4, 5, 4258, 5, 4, 49275, 5, 5, 5917, // 5, 4 + 4, 5, 5103, 4, 6, 3621, 5, 5, 51700, 5, 6, 5112, // 5, 5 + 4, 6, 4262, 4, 7, 3064, 5, 6, 53816, 5, 7, 4394, // 5, 6 + 4, 7, 3720, 4, 8, 2708, 5, 7, 55168, 5, 8, 3940, // 5, 7 + 5, 8, 55162, 5, 9, 3938, 6, 8, 3726, 6, 9, 2710, // 5, 8 + 5, 9, 53813, 5, 10, 4388, 6, 9, 4269, 6, 10, 3066, // 5, 9 + 5, 10, 51700, 5, 11, 5103, 6, 10, 5113, 6, 11, 3620, // 5,10 + 5, 11, 49279, 5, 12, 5901, 6, 11, 6099, 6, 12, 4257, // 5,11 + 5, 12, 46806, 5, 13, 6685, 6, 12, 7138, 6, 13, 4907, // 5,12 + 5, 13, 44399, 5, 14, 7411, 6, 13, 8189, 6, 14, 5537, // 5,13 + 5, 14, 42105, 5, 15, 8061, 6, 14, 9233, 6, 15, 6137, // 5,14 + 5, 15, 39940, 5, 16, 8632, 6, 15, 10265, 6, 16, 6699, // 5,15 + 5, 0, 10100, 5, 1, 6502, 6, 0, 40618, 6, 1, 8316, // 6, 0 + 5, 1, 9014, 5, 2, 5910, 6, 1, 42913, 6, 2, 7699, // 6, 1 + 5, 2, 7899, 5, 3, 5268, 6, 2, 45383, 6, 3, 6986, // 6, 2 + 5, 3, 6750, 5, 4, 4576, 6, 3, 48037, 6, 4, 6173, // 6, 3 + 5, 4, 5573, 5, 5, 3837, 6, 4, 50865, 6, 5, 5261, // 6, 4 + 5, 5, 4388, 5, 6, 3065, 6, 5, 53813, 6, 6, 4270, // 6, 5 + 5, 6, 3271, 5, 7, 2316, 6, 6, 56673, 6, 7, 3276, // 6, 6 + 5, 7, 2462, 5, 8, 1766, 6, 7, 58775, 6, 8, 2533, // 6, 7 + 6, 8, 58773, 6, 9, 2532, 7, 8, 2464, 7, 9, 1767, // 6, 8 + 6, 9, 56673, 6, 10, 3271, 7, 9, 3275, 7, 10, 2317, // 6, 9 + 6, 10, 53816, 6, 11, 4262, 7, 10, 4394, 7, 11, 3064, // 6,10 + 6, 11, 50873, 6, 12, 5248, 7, 11, 5581, 7, 12, 3834, // 6,11 + 6, 12, 48049, 6, 13, 6154, 7, 12, 6761, 7, 13, 4572, // 6,12 + 6, 13, 45401, 6, 14, 6961, 7, 13, 7913, 7, 14, 5261, // 6,13 + 6, 14, 42936, 6, 15, 7667, 7, 14, 9032, 7, 15, 5901, // 6,14 + 6, 15, 40646, 6, 16, 8278, 7, 15, 10123, 7, 16, 6489, // 6,15 + 6, 0, 10052, 6, 1, 6360, 7, 0, 41072, 7, 1, 8052, // 7, 0 + 6, 1, 8929, 6, 2, 5756, 7, 1, 43433, 7, 2, 7418, // 7, 1 + 6, 2, 7766, 6, 3, 5095, 7, 2, 45995, 7, 3, 6680, // 7, 2 + 6, 3, 6552, 6, 4, 4372, 7, 3, 48785, 7, 4, 5827, // 7, 3 + 6, 4, 5280, 6, 5, 3579, 7, 4, 51832, 7, 5, 4845, // 7, 4 + 6, 5, 3938, 6, 6, 2710, 7, 5, 55162, 7, 6, 3726, // 7, 5 + 6, 6, 2532, 6, 7, 1767, 7, 6, 58773, 7, 7, 2464, // 7, 6 + 6, 7, 1170, 6, 8, 827, 7, 7, 62369, 7, 8, 1170, // 7, 7 + 7, 8, 62369, 7, 9, 1170, 8, 8, 1170, 8, 9, 827, // 7, 8 + 7, 9, 58775, 7, 10, 2462, 8, 9, 2533, 8, 10, 1766, // 7, 9 + 7, 10, 55168, 7, 11, 3720, 8, 10, 3940, 8, 11, 2708, // 7,10 + 7, 11, 51842, 7, 12, 4835, 8, 11, 5283, 8, 12, 3576, // 7,11 + 7, 12, 48801, 7, 13, 5811, 8, 12, 6558, 8, 13, 4366, // 7,12 + 7, 13, 46017, 7, 14, 6658, 8, 13, 7773, 8, 14, 5088, // 7,13 + 7, 14, 43461, 7, 15, 7390, 8, 14, 8939, 8, 15, 5746, // 7,14 + 7, 15, 41106, 7, 16, 8018, 8, 15, 10066, 8, 16, 6346, // 7,15 + 7, -1, 6346, 7, 0, 10066, 8, -1, 8018, 8, 0, 41106, // 8, 0 + 7, 0, 5745, 7, 1, 8939, 8, 0, 7390, 8, 1, 43462, // 8, 1 + 7, 1, 5087, 7, 2, 7773, 8, 1, 6658, 8, 2, 46018, // 8, 2 + 7, 2, 4366, 7, 3, 6558, 8, 2, 5811, 8, 3, 48801, // 8, 3 + 7, 3, 3575, 7, 4, 5283, 8, 3, 4835, 8, 4, 51843, // 8, 4 + 7, 4, 2708, 7, 5, 3940, 8, 4, 3720, 8, 5, 55168, // 8, 5 + 7, 5, 1766, 7, 6, 2533, 8, 5, 2462, 8, 6, 58775, // 8, 6 + 7, 6, 827, 7, 7, 1170, 8, 6, 1170, 8, 7, 62369, // 8, 7 + 8, 7, 1170, 8, 8, 62369, 9, 7, 827, 9, 8, 1170, // 8, 8 + 8, 8, 2464, 8, 9, 58773, 9, 8, 1767, 9, 9, 2532, // 8, 9 + 8, 9, 3726, 8, 10, 55162, 9, 9, 2710, 9, 10, 3938, // 8,10 + 8, 10, 4846, 8, 11, 51832, 9, 10, 3579, 9, 11, 5279, // 8,11 + 8, 11, 5827, 8, 12, 48785, 9, 11, 4372, 9, 12, 6552, // 8,12 + 8, 12, 6680, 8, 13, 45995, 9, 12, 5095, 9, 13, 7766, // 8,13 + 8, 13, 7418, 8, 14, 43433, 9, 13, 5756, 9, 14, 8929, // 8,14 + 8, 14, 8052, 8, 15, 41072, 9, 14, 6360, 9, 15, 10052, // 8,15 + 8, -1, 6489, 8, 0, 10123, 9, -1, 8278, 9, 0, 40646, // 9, 0 + 8, 0, 5900, 8, 1, 9032, 9, 0, 7667, 9, 1, 42937, // 9, 1 + 8, 1, 5261, 8, 2, 7913, 9, 1, 6961, 9, 2, 45401, // 9, 2 + 8, 2, 4572, 8, 3, 6761, 9, 2, 6154, 9, 3, 48049, // 9, 3 + 8, 3, 3834, 8, 4, 5581, 9, 3, 5248, 9, 4, 50873, // 9, 4 + 8, 4, 3064, 8, 5, 4394, 9, 4, 4262, 9, 5, 53816, // 9, 5 + 8, 5, 2316, 8, 6, 3275, 9, 5, 3271, 9, 6, 56674, // 9, 6 + 8, 6, 1767, 8, 7, 2464, 9, 6, 2532, 9, 7, 58773, // 9, 7 + 9, 7, 2533, 9, 8, 58775, 10, 7, 1766, 10, 8, 2462, // 9, 8 + 9, 8, 3275, 9, 9, 56673, 10, 8, 2316, 10, 9, 3272, // 9, 9 + 9, 9, 4269, 9, 10, 53813, 10, 9, 3065, 10, 10, 4389, // 9,10 + 9, 10, 5261, 9, 11, 50865, 10, 10, 3837, 10, 11, 5573, // 9,11 + 9, 11, 6173, 9, 12, 48037, 10, 11, 4576, 10, 12, 6750, // 9,12 + 9, 12, 6986, 9, 13, 45383, 10, 12, 5268, 10, 13, 7899, // 9,13 + 9, 13, 7699, 9, 14, 42913, 10, 13, 5910, 10, 14, 9014, // 9,14 + 9, 14, 8316, 9, 15, 40618, 10, 14, 6502, 10, 15, 10100, // 9,15 + 9, -1, 6699, 9, 0, 10265, 10, -1, 8632, 10, 0, 39940, // 10, 0 + 9, 0, 6137, 9, 1, 9233, 10, 0, 8061, 10, 1, 42105, // 10, 1 + 9, 1, 5537, 9, 2, 8189, 10, 1, 7411, 10, 2, 44399, // 10, 2 + 9, 2, 4906, 9, 3, 7138, 10, 2, 6685, 10, 3, 46807, // 10, 3 + 9, 3, 4257, 9, 4, 6099, 10, 3, 5901, 10, 4, 49279, // 10, 4 + 9, 4, 3621, 9, 5, 5113, 10, 4, 5103, 10, 5, 51699, // 10, 5 + 9, 5, 3065, 9, 6, 4269, 10, 5, 4388, 10, 6, 53814, // 10, 6 + 9, 6, 2710, 9, 7, 3726, 10, 6, 3938, 10, 7, 55162, // 10, 7 + 10, 7, 3940, 10, 8, 55168, 11, 7, 2708, 11, 8, 3720, // 10, 8 + 10, 8, 4394, 10, 9, 53816, 11, 8, 3064, 11, 9, 4262, // 10, 9 + 10, 9, 5113, 10, 10, 51700, 11, 9, 3621, 11, 10, 5102, // 10,10 + 10, 10, 5917, 10, 11, 49275, 11, 10, 4258, 11, 11, 6086, // 10,11 + 10, 11, 6707, 10, 12, 46798, 11, 11, 4909, 11, 12, 7122, // 10,12 + 10, 12, 7440, 10, 13, 44386, 11, 12, 5543, 11, 13, 8167, // 10,13 + 10, 13, 8098, 10, 14, 42087, 11, 13, 6145, 11, 14, 9206, // 10,14 + 10, 14, 8676, 10, 15, 39918, 11, 14, 6710, 11, 15, 10232, // 10,15 + 10, -1, 6965, 10, 0, 10473, 11, -1, 9072, 11, 0, 39026, // 11, 0 + 10, 0, 6440, 10, 1, 9513, 11, 0, 8557, 11, 1, 41026, // 11, 1 + 10, 1, 5891, 10, 2, 8559, 11, 1, 7981, 11, 2, 43105, // 11, 2 + 10, 2, 5330, 10, 3, 7622, 11, 2, 7356, 11, 3, 45228, // 11, 3 + 10, 3, 4774, 10, 4, 6727, 11, 3, 6708, 11, 4, 47327, // 11, 4 + 10, 4, 4258, 10, 5, 5917, 11, 4, 6086, 11, 5, 49275, // 11, 5 + 10, 5, 3837, 10, 6, 5261, 11, 5, 5573, 11, 6, 50865, // 11, 6 + 10, 6, 3579, 10, 7, 4846, 11, 6, 5280, 11, 7, 51831, // 11, 7 + 11, 7, 5283, 11, 8, 51842, 12, 7, 3575, 12, 8, 4836, // 11, 8 + 11, 8, 5581, 11, 9, 50873, 12, 8, 3834, 12, 9, 5248, // 11, 9 + 11, 9, 6099, 11, 10, 49279, 12, 9, 4257, 12, 10, 5901, // 11,10 + 11, 10, 6727, 11, 11, 47328, 12, 10, 4774, 12, 11, 6707, // 11,11 + 11, 11, 7382, 11, 12, 45224, 12, 11, 5331, 12, 12, 7599, // 11,12 + 11, 12, 8015, 11, 13, 43096, 12, 12, 5895, 12, 13, 8530, // 11,13 + 11, 13, 8599, 11, 14, 41013, 12, 13, 6447, 12, 14, 9477, // 11,14 + 11, 14, 9122, 11, 15, 39009, 12, 14, 6975, 12, 15, 10430, // 11,15 + 11, -1, 7276, 11, 0, 10723, 12, -1, 9585, 12, 0, 37952, // 12, 0 + 11, 0, 6792, 11, 1, 9841, 12, 0, 9135, 12, 1, 39768, // 12, 1 + 11, 1, 6297, 11, 2, 8979, 12, 1, 8641, 12, 2, 41619, // 12, 2 + 11, 2, 5804, 11, 3, 8151, 12, 2, 8120, 12, 3, 43461, // 12, 3 + 11, 3, 5331, 11, 4, 7382, 12, 3, 7598, 12, 4, 45225, // 12, 4 + 11, 4, 4909, 11, 5, 6707, 12, 4, 7121, 12, 5, 46799, // 12, 5 + 11, 5, 4576, 11, 6, 6173, 12, 5, 6750, 12, 6, 48037, // 12, 6 + 11, 6, 4372, 11, 7, 5827, 12, 6, 6552, 12, 7, 48785, // 12, 7 + 12, 7, 6558, 12, 8, 48801, 13, 7, 4366, 13, 8, 5811, // 12, 8 + 12, 8, 6761, 12, 9, 48049, 13, 8, 4572, 13, 9, 6154, // 12, 9 + 12, 9, 7138, 12, 10, 46806, 13, 9, 4906, 13, 10, 6686, // 12,10 + 12, 10, 7622, 12, 11, 45229, 13, 10, 5330, 13, 11, 7355, // 12,11 + 12, 11, 8151, 12, 12, 43461, 13, 11, 5804, 13, 12, 8120, // 12,12 + 12, 12, 8681, 12, 13, 41614, 13, 12, 6299, 13, 13, 8942, // 12,13 + 12, 13, 9184, 12, 14, 39759, 13, 13, 6797, 13, 14, 9796, // 12,14 + 12, 14, 9642, 12, 15, 37939, 13, 14, 7285, 13, 15, 10670, // 12,15 + 12, -1, 7620, 12, 0, 10994, 13, -1, 10158, 13, 0, 36764, // 13, 0 + 12, 0, 7177, 12, 1, 10188, 13, 0, 9777, 13, 1, 38394, // 13, 1 + 12, 1, 6732, 12, 2, 9413, 13, 1, 9366, 13, 2, 40025, // 13, 2 + 12, 2, 6299, 12, 3, 8681, 13, 2, 8941, 13, 3, 41615, // 13, 3 + 12, 3, 5895, 12, 4, 8015, 13, 3, 8530, 13, 4, 43096, // 13, 4 + 12, 4, 5543, 12, 5, 7440, 13, 4, 8167, 13, 5, 44386, // 13, 5 + 12, 5, 5268, 12, 6, 6986, 13, 5, 7899, 13, 6, 45383, // 13, 6 + 12, 6, 5095, 12, 7, 6680, 13, 6, 7766, 13, 7, 45995, // 13, 7 + 13, 7, 7773, 13, 8, 46017, 14, 7, 5087, 14, 8, 6659, // 13, 8 + 13, 8, 7913, 13, 9, 45401, 14, 8, 5261, 14, 9, 6961, // 13, 9 + 13, 9, 8189, 13, 10, 44399, 14, 9, 5537, 14, 10, 7411, // 13,10 + 13, 10, 8559, 13, 11, 43105, 14, 10, 5891, 14, 11, 7981, // 13,11 + 13, 11, 8979, 13, 12, 41618, 14, 11, 6297, 14, 12, 8642, // 13,12 + 13, 12, 9413, 13, 13, 40025, 14, 12, 6732, 14, 13, 9366, // 13,13 + 13, 13, 9834, 13, 14, 38390, 14, 13, 7179, 14, 14, 10133, // 13,14 + 13, 14, 10224, 13, 15, 36756, 14, 14, 7626, 14, 15, 10930, // 13,15 + 13, -1, 7983, 13, 0, 11267, 14, -1, 10780, 14, 0, 35506, // 14, 0 + 13, 0, 7579, 13, 1, 10532, 14, 0, 10467, 14, 1, 36958, // 14, 1 + 13, 1, 7179, 13, 2, 9834, 14, 1, 10133, 14, 2, 38390, // 14, 2 + 13, 2, 6797, 13, 3, 9184, 14, 2, 9796, 14, 3, 39759, // 14, 3 + 13, 3, 6447, 13, 4, 8599, 14, 3, 9478, 14, 4, 41012, // 14, 4 + 13, 4, 6145, 13, 5, 8098, 14, 4, 9206, 14, 5, 42087, // 14, 5 + 13, 5, 5910, 13, 6, 7699, 14, 5, 9014, 14, 6, 42913, // 14, 6 + 13, 6, 5756, 13, 7, 7418, 14, 6, 8929, 14, 7, 43433, // 14, 7 + 14, 7, 8939, 14, 8, 43461, 15, 7, 5745, 15, 8, 7391, // 14, 8 + 14, 8, 9032, 14, 9, 42936, 15, 8, 5900, 15, 9, 7668, // 14, 9 + 14, 9, 9233, 14, 10, 42105, 15, 9, 6137, 15, 10, 8061, // 14,10 + 14, 10, 9513, 14, 11, 41026, 15, 10, 6440, 15, 11, 8557, // 14,11 + 14, 11, 9841, 14, 12, 39767, 15, 11, 6792, 15, 12, 9136, // 14,12 + 14, 12, 10188, 14, 13, 38394, 15, 12, 7177, 15, 13, 9777, // 14,13 + 14, 13, 10532, 14, 14, 36959, 15, 13, 7579, 15, 14, 10466, // 14,14 + 14, 14, 10855, 14, 15, 35502, 15, 14, 7987, 15, 15, 11192, // 14,15 + 14, -1, 8358, 14, 0, 11526, 15, -1, 11440, 15, 0, 34212, // 15, 0 + 14, 0, 7987, 14, 1, 10855, 15, 0, 11192, 15, 1, 35502, // 15, 1 + 14, 1, 7626, 14, 2, 10224, 15, 1, 10930, 15, 2, 36756, // 15, 2 + 14, 2, 7285, 14, 3, 9642, 15, 2, 10670, 15, 3, 37939, // 15, 3 + 14, 3, 6975, 14, 4, 9122, 15, 3, 10430, 15, 4, 39009, // 15, 4 + 14, 4, 6710, 14, 5, 8676, 15, 4, 10232, 15, 5, 39918, // 15, 5 + 14, 5, 6502, 14, 6, 8316, 15, 5, 10100, 15, 6, 40618, // 15, 6 + 14, 6, 6360, 14, 7, 8052, 15, 6, 10052, 15, 7, 41072, // 15, 7 + 15, 7, 10066, 15, 8, 41106, 16, 7, 6346, 16, 8, 8018, // 15, 8 + 15, 8, 10123, 15, 9, 40646, 16, 8, 6489, 16, 9, 8278, // 15, 9 + 15, 9, 10265, 15, 10, 39940, 16, 9, 6699, 16, 10, 8632, // 15,10 + 15, 10, 10473, 15, 11, 39026, 16, 10, 6965, 16, 11, 9072, // 15,11 + 15, 11, 10723, 15, 12, 37951, 16, 11, 7276, 16, 12, 9586, // 15,12 + 15, 12, 10994, 15, 13, 36764, 16, 12, 7620, 16, 13, 10158, // 15,13 + 15, 13, 11267, 15, 14, 35506, 16, 13, 7983, 16, 14, 10780, // 15,14 + 15, 14, 11526, 15, 15, 34212, 16, 14, 8358, 16, 15, 11440, // 15,15 + // angle of -1.0 degrees + -1, 0, 8769, -1, 1, 6280, 0, 0, 41693, 0, 1, 8794, // 0, 0 + -1, 1, 8265, -1, 2, 5974, 0, 1, 42823, 0, 2, 8474, // 0, 1 + -1, 2, 7791, -1, 3, 5682, 0, 2, 43904, 0, 3, 8159, // 0, 2 + -1, 3, 7356, -1, 4, 5410, 0, 3, 44907, 0, 4, 7863, // 0, 3 + -1, 4, 6970, -1, 5, 5169, 0, 4, 45799, 0, 5, 7598, // 0, 4 + -1, 5, 6644, -1, 6, 4967, 0, 5, 46541, 0, 6, 7384, // 0, 5 + -1, 6, 6391, -1, 7, 4814, 0, 6, 47098, 0, 7, 7233, // 0, 6 + -1, 7, 6217, -1, 8, 4718, 0, 7, 47440, 0, 8, 7161, // 0, 7 + 0, 8, 47426, 0, 9, 7158, 1, 8, 6230, 1, 9, 4722, // 0, 8 + 0, 9, 47086, 0, 10, 7227, 1, 9, 6405, 1, 10, 4818, // 0, 9 + 0, 10, 46532, 0, 11, 7374, 1, 10, 6659, 1, 11, 4971, // 0,10 + 0, 11, 45791, 0, 12, 7587, 1, 11, 6986, 1, 12, 5172, // 0,11 + 0, 12, 44901, 0, 13, 7848, 1, 12, 7374, 1, 13, 5413, // 0,12 + 0, 13, 43900, 0, 14, 8141, 1, 13, 7812, 1, 14, 5683, // 0,13 + 0, 14, 42821, 0, 15, 8452, 1, 14, 8288, 1, 15, 5975, // 0,14 + 0, 15, 41693, 0, 16, 8769, 1, 15, 8795, 1, 16, 6279, // 0,15 + 0, 0, 8452, 0, 1, 5975, 1, 0, 42821, 1, 1, 8288, // 1, 0 + 0, 1, 7901, 0, 2, 5640, 1, 1, 44074, 1, 2, 7921, // 1, 1 + 0, 2, 7378, 0, 3, 5315, 1, 2, 45288, 1, 3, 7555, // 1, 2 + 0, 3, 6892, 0, 4, 5009, 1, 3, 46430, 1, 4, 7205, // 1, 3 + 0, 4, 6458, 0, 5, 4734, 1, 4, 47458, 1, 5, 6886, // 1, 4 + 0, 5, 6092, 0, 6, 4502, 1, 5, 48322, 1, 6, 6620, // 1, 5 + 0, 6, 5809, 0, 7, 4327, 1, 6, 48969, 1, 7, 6431, // 1, 6 + 0, 7, 5623, 0, 8, 4221, 1, 7, 49358, 1, 8, 6334, // 1, 7 + 1, 8, 49347, 1, 9, 6332, 2, 8, 5633, 2, 9, 4224, // 1, 8 + 1, 9, 48960, 1, 10, 6425, 2, 9, 5820, 2, 10, 4331, // 1, 9 + 1, 10, 48314, 1, 11, 6613, 2, 10, 6104, 2, 11, 4505, // 1,10 + 1, 11, 47453, 1, 12, 6875, 2, 11, 6472, 2, 12, 4736, // 1,11 + 1, 12, 46427, 1, 13, 7191, 2, 12, 6908, 2, 13, 5010, // 1,12 + 1, 13, 45286, 1, 14, 7539, 2, 13, 7395, 2, 14, 5316, // 1,13 + 1, 14, 44074, 1, 15, 7901, 2, 14, 7921, 2, 15, 5640, // 1,14 + 1, 15, 42823, 1, 16, 8265, 2, 15, 8474, 2, 16, 5974, // 1,15 + 1, 0, 8141, 1, 1, 5684, 2, 0, 43900, 2, 1, 7811, // 2, 0 + 1, 1, 7539, 1, 2, 5316, 2, 1, 45286, 2, 2, 7395, // 2, 1 + 1, 2, 6959, 1, 3, 4954, 2, 2, 46650, 2, 3, 6973, // 2, 2 + 1, 3, 6414, 1, 4, 4607, 2, 3, 47955, 2, 4, 6560, // 2, 3 + 1, 4, 5920, 1, 5, 4290, 2, 4, 49150, 2, 5, 6176, // 2, 4 + 1, 5, 5499, 1, 6, 4019, 2, 5, 50171, 2, 6, 5847, // 2, 5 + 1, 6, 5175, 1, 7, 3813, 2, 6, 50942, 2, 7, 5606, // 2, 6 + 1, 7, 4970, 1, 8, 3691, 2, 7, 51395, 2, 8, 5480, // 2, 7 + 2, 8, 51387, 2, 9, 5478, 3, 8, 4978, 3, 9, 3693, // 2, 8 + 2, 9, 50935, 2, 10, 5602, 3, 9, 5184, 3, 10, 3815, // 2, 9 + 2, 10, 50165, 2, 11, 5842, 3, 10, 5508, 3, 11, 4021, // 2,10 + 2, 11, 49147, 2, 12, 6168, 3, 11, 5930, 3, 12, 4291, // 2,11 + 2, 12, 47953, 2, 13, 6549, 3, 12, 6426, 3, 13, 4608, // 2,12 + 2, 13, 46650, 2, 14, 6959, 3, 13, 6973, 3, 14, 4954, // 2,13 + 2, 14, 45288, 2, 15, 7378, 3, 14, 7555, 3, 15, 5315, // 2,14 + 2, 15, 43904, 2, 16, 7791, 3, 15, 8159, 3, 16, 5682, // 2,15 + 2, 0, 7848, 2, 1, 5413, 3, 0, 44901, 3, 1, 7374, // 3, 0 + 2, 1, 7191, 2, 2, 5011, 3, 1, 46427, 3, 2, 6907, // 3, 1 + 2, 2, 6549, 2, 3, 4608, 3, 2, 47953, 3, 3, 6426, // 3, 2 + 2, 3, 5934, 2, 4, 4214, 3, 3, 49445, 3, 4, 5943, // 3, 3 + 2, 4, 5365, 2, 5, 3845, 3, 4, 50844, 3, 5, 5482, // 3, 4 + 2, 5, 4872, 2, 6, 3522, 3, 5, 52069, 3, 6, 5073, // 3, 5 + 2, 6, 4489, 2, 7, 3273, 3, 6, 53012, 3, 7, 4762, // 3, 6 + 2, 7, 4254, 2, 8, 3126, 3, 7, 53562, 3, 8, 4594, // 3, 7 + 3, 8, 53557, 3, 9, 4592, 4, 8, 4259, 4, 9, 3128, // 3, 8 + 3, 9, 53008, 3, 10, 4759, 4, 9, 4495, 4, 10, 3274, // 3, 9 + 3, 10, 52066, 3, 11, 5069, 4, 10, 4879, 4, 11, 3522, // 3,10 + 3, 11, 50843, 3, 12, 5474, 4, 11, 5373, 4, 12, 3846, // 3,11 + 3, 12, 49445, 3, 13, 5934, 4, 12, 5943, 4, 13, 4214, // 3,12 + 3, 13, 47955, 3, 14, 6414, 4, 13, 6560, 4, 14, 4607, // 3,13 + 3, 14, 46430, 3, 15, 6892, 4, 14, 7204, 4, 15, 5010, // 3,14 + 3, 15, 44907, 3, 16, 7356, 4, 15, 7863, 4, 16, 5410, // 3,15 + 3, 0, 7587, 3, 1, 5172, 4, 0, 45791, 4, 1, 6986, // 4, 0 + 3, 1, 6875, 3, 2, 4736, 4, 1, 47453, 4, 2, 6472, // 4, 1 + 3, 2, 6168, 3, 3, 4291, 4, 2, 49147, 4, 3, 5930, // 4, 2 + 3, 3, 5474, 3, 4, 3846, 4, 3, 50843, 4, 4, 5373, // 4, 3 + 3, 4, 4816, 3, 5, 3415, 4, 4, 52484, 4, 5, 4821, // 4, 4 + 3, 5, 4226, 3, 6, 3023, 4, 5, 53975, 4, 6, 4312, // 4, 5 + 3, 6, 3755, 3, 7, 2710, 4, 6, 55166, 4, 7, 3905, // 4, 6 + 3, 7, 3469, 3, 8, 2524, 4, 7, 55870, 4, 8, 3673, // 4, 7 + 4, 8, 55867, 4, 9, 3671, 5, 8, 3473, 5, 9, 2525, // 4, 8 + 4, 9, 55164, 4, 10, 3902, 5, 9, 3759, 5, 10, 2711, // 4, 9 + 4, 10, 53973, 4, 11, 4309, 5, 10, 4230, 5, 11, 3024, // 4,10 + 4, 11, 52484, 4, 12, 4816, 5, 11, 4822, 5, 12, 3414, // 4,11 + 4, 12, 50844, 4, 13, 5365, 5, 12, 5481, 5, 13, 3846, // 4,12 + 4, 13, 49150, 4, 14, 5920, 5, 13, 6176, 5, 14, 4290, // 4,13 + 4, 14, 47458, 4, 15, 6458, 5, 14, 6886, 5, 15, 4734, // 4,14 + 4, 15, 45799, 4, 16, 6970, 5, 15, 7599, 5, 16, 5168, // 4,15 + 4, 0, 7374, 4, 1, 4971, 5, 0, 46532, 5, 1, 6659, // 5, 0 + 4, 1, 6613, 4, 2, 4505, 5, 1, 48314, 5, 2, 6104, // 5, 1 + 4, 2, 5842, 4, 3, 4020, 5, 2, 50165, 5, 3, 5509, // 5, 2 + 4, 3, 5069, 4, 4, 3523, 5, 3, 52066, 5, 4, 4878, // 5, 3 + 4, 4, 4309, 4, 5, 3023, 5, 4, 53973, 5, 5, 4231, // 5, 4 + 4, 5, 3595, 4, 6, 2546, 5, 5, 55798, 5, 6, 3597, // 5, 5 + 4, 6, 2993, 4, 7, 2138, 5, 6, 57354, 5, 7, 3051, // 5, 6 + 4, 7, 2615, 4, 8, 1884, 5, 7, 58324, 5, 8, 2713, // 5, 7 + 5, 8, 58322, 5, 9, 2713, 6, 8, 2616, 6, 9, 1885, // 5, 8 + 5, 9, 57353, 5, 10, 3050, 6, 9, 2995, 6, 10, 2138, // 5, 9 + 5, 10, 55798, 5, 11, 3595, 6, 10, 3598, 6, 11, 2545, // 5,10 + 5, 11, 53975, 5, 12, 4226, 6, 11, 4313, 6, 12, 3022, // 5,11 + 5, 12, 52069, 5, 13, 4872, 6, 12, 5073, 6, 13, 3522, // 5,12 + 5, 13, 50171, 5, 14, 5499, 6, 13, 5848, 6, 14, 4018, // 5,13 + 5, 14, 48322, 5, 15, 6092, 6, 14, 6620, 6, 15, 4502, // 5,14 + 5, 15, 46541, 5, 16, 6644, 6, 15, 7383, 6, 16, 4968, // 5,15 + 5, 0, 7227, 5, 1, 4818, 6, 0, 47086, 6, 1, 6405, // 6, 0 + 5, 1, 6425, 5, 2, 4330, 6, 1, 48960, 6, 2, 5821, // 6, 1 + 5, 2, 5602, 5, 3, 3815, 6, 2, 50935, 6, 3, 5184, // 6, 2 + 5, 3, 4759, 5, 4, 3274, 6, 3, 53008, 6, 4, 4495, // 6, 3 + 5, 4, 3902, 5, 5, 2711, 6, 4, 55164, 6, 5, 3759, // 6, 4 + 5, 5, 3050, 5, 6, 2138, 6, 5, 57353, 6, 6, 2995, // 6, 5 + 5, 6, 2258, 5, 7, 1597, 6, 6, 59422, 6, 7, 2259, // 6, 6 + 5, 7, 1695, 5, 8, 1209, 6, 7, 60906, 6, 8, 1726, // 6, 7 + 6, 8, 60905, 6, 9, 1726, 7, 8, 1695, 7, 9, 1210, // 6, 8 + 6, 9, 59422, 6, 10, 2258, 7, 9, 2259, 7, 10, 1597, // 6, 9 + 6, 10, 57354, 6, 11, 2993, 7, 10, 3051, 7, 11, 2138, // 6,10 + 6, 11, 55166, 6, 12, 3755, 7, 11, 3904, 7, 12, 2711, // 6,11 + 6, 12, 53012, 6, 13, 4489, 7, 12, 4762, 7, 13, 3273, // 6,12 + 6, 13, 50942, 6, 14, 5175, 7, 13, 5606, 7, 14, 3813, // 6,13 + 6, 14, 48969, 6, 15, 5809, 7, 14, 6430, 7, 15, 4328, // 6,14 + 6, 15, 47098, 6, 16, 6391, 7, 15, 7233, 7, 16, 4814, // 6,15 + 6, 0, 7158, 6, 1, 4722, 7, 0, 47426, 7, 1, 6230, // 7, 0 + 6, 1, 6332, 6, 2, 4224, 7, 1, 49347, 7, 2, 5633, // 7, 1 + 6, 2, 5478, 6, 3, 3693, 7, 2, 51387, 7, 3, 4978, // 7, 2 + 6, 3, 4592, 6, 4, 3128, 7, 3, 53557, 7, 4, 4259, // 7, 3 + 6, 4, 3671, 6, 5, 2525, 7, 4, 55867, 7, 5, 3473, // 7, 4 + 6, 5, 2713, 6, 6, 1884, 7, 5, 58322, 7, 6, 2617, // 7, 5 + 6, 6, 1726, 6, 7, 1210, 7, 6, 60905, 7, 7, 1695, // 7, 6 + 6, 7, 789, 6, 8, 558, 7, 7, 63399, 7, 8, 790, // 7, 7 + 7, 8, 63399, 7, 9, 789, 8, 8, 789, 8, 9, 559, // 7, 8 + 7, 9, 60906, 7, 10, 1695, 8, 9, 1726, 8, 10, 1209, // 7, 9 + 7, 10, 58324, 7, 11, 2615, 8, 10, 2714, 8, 11, 1883, // 7,10 + 7, 11, 55870, 7, 12, 3469, 8, 11, 3672, 8, 12, 2525, // 7,11 + 7, 12, 53562, 7, 13, 4254, 8, 12, 4594, 8, 13, 3126, // 7,12 + 7, 13, 51395, 7, 14, 4970, 8, 13, 5480, 8, 14, 3691, // 7,13 + 7, 14, 49358, 7, 15, 5623, 8, 14, 6335, 8, 15, 4220, // 7,14 + 7, 15, 47440, 7, 16, 6217, 8, 15, 7161, 8, 16, 4718, // 7,15 + 7, -1, 4718, 7, 0, 7161, 8, -1, 6217, 8, 0, 47440, // 8, 0 + 7, 0, 4221, 7, 1, 6335, 8, 0, 5623, 8, 1, 49357, // 8, 1 + 7, 1, 3691, 7, 2, 5480, 8, 1, 4970, 8, 2, 51395, // 8, 2 + 7, 2, 3126, 7, 3, 4594, 8, 2, 4254, 8, 3, 53562, // 8, 3 + 7, 3, 2524, 7, 4, 3672, 8, 3, 3469, 8, 4, 55871, // 8, 4 + 7, 4, 1884, 7, 5, 2714, 8, 4, 2615, 8, 5, 58323, // 8, 5 + 7, 5, 1209, 7, 6, 1726, 8, 5, 1695, 8, 6, 60906, // 8, 6 + 7, 6, 558, 7, 7, 789, 8, 6, 789, 8, 7, 63400, // 8, 7 + 8, 7, 789, 8, 8, 63399, 9, 7, 558, 9, 8, 790, // 8, 8 + 8, 8, 1695, 8, 9, 60905, 9, 8, 1210, 9, 9, 1726, // 8, 9 + 8, 9, 2616, 8, 10, 58322, 9, 9, 1884, 9, 10, 2714, // 8,10 + 8, 10, 3473, 8, 11, 55867, 9, 10, 2525, 9, 11, 3671, // 8,11 + 8, 11, 4259, 8, 12, 53557, 9, 11, 3128, 9, 12, 4592, // 8,12 + 8, 12, 4978, 8, 13, 51387, 9, 12, 3693, 9, 13, 5478, // 8,13 + 8, 13, 5633, 8, 14, 49347, 9, 13, 4224, 9, 14, 6332, // 8,14 + 8, 14, 6230, 8, 15, 47426, 9, 14, 4722, 9, 15, 7158, // 8,15 + 8, -1, 4814, 8, 0, 7233, 9, -1, 6391, 9, 0, 47098, // 9, 0 + 8, 0, 4327, 8, 1, 6430, 9, 0, 5809, 9, 1, 48970, // 9, 1 + 8, 1, 3813, 8, 2, 5606, 9, 1, 5175, 9, 2, 50942, // 9, 2 + 8, 2, 3273, 8, 3, 4762, 9, 2, 4489, 9, 3, 53012, // 9, 3 + 8, 3, 2710, 8, 4, 3904, 9, 3, 3755, 9, 4, 55167, // 9, 4 + 8, 4, 2138, 8, 5, 3051, 9, 4, 2993, 9, 5, 57354, // 9, 5 + 8, 5, 1597, 8, 6, 2259, 9, 5, 2258, 9, 6, 59422, // 9, 6 + 8, 6, 1210, 8, 7, 1695, 9, 6, 1726, 9, 7, 60905, // 9, 7 + 9, 7, 1726, 9, 8, 60906, 10, 7, 1209, 10, 8, 1695, // 9, 8 + 9, 8, 2259, 9, 9, 59422, 10, 8, 1597, 10, 9, 2258, // 9, 9 + 9, 9, 2995, 9, 10, 57353, 10, 9, 2138, 10, 10, 3050, // 9,10 + 9, 10, 3759, 9, 11, 55164, 10, 10, 2711, 10, 11, 3902, // 9,11 + 9, 11, 4495, 9, 12, 53008, 10, 11, 3274, 10, 12, 4759, // 9,12 + 9, 12, 5184, 9, 13, 50935, 10, 12, 3815, 10, 13, 5602, // 9,13 + 9, 13, 5820, 9, 14, 48960, 10, 13, 4330, 10, 14, 6426, // 9,14 + 9, 14, 6405, 9, 15, 47086, 10, 14, 4818, 10, 15, 7227, // 9,15 + 9, -1, 4967, 9, 0, 7383, 10, -1, 6644, 10, 0, 46542, // 10, 0 + 9, 0, 4502, 9, 1, 6620, 10, 0, 6092, 10, 1, 48322, // 10, 1 + 9, 1, 4019, 9, 2, 5848, 10, 1, 5499, 10, 2, 50170, // 10, 2 + 9, 2, 3522, 9, 3, 5073, 10, 2, 4872, 10, 3, 52069, // 10, 3 + 9, 3, 3023, 9, 4, 4313, 10, 3, 4226, 10, 4, 53974, // 10, 4 + 9, 4, 2546, 9, 5, 3598, 10, 4, 3595, 10, 5, 55797, // 10, 5 + 9, 5, 2138, 9, 6, 2995, 10, 5, 3050, 10, 6, 57353, // 10, 6 + 9, 6, 1884, 9, 7, 2616, 10, 6, 2713, 10, 7, 58323, // 10, 7 + 10, 7, 2714, 10, 8, 58324, 11, 7, 1884, 11, 8, 2614, // 10, 8 + 10, 8, 3051, 10, 9, 57354, 11, 8, 2138, 11, 9, 2993, // 10, 9 + 10, 9, 3598, 10, 10, 55798, 11, 9, 2546, 11, 10, 3594, // 10,10 + 10, 10, 4230, 10, 11, 53973, 11, 10, 3023, 11, 11, 4310, // 10,11 + 10, 11, 4879, 10, 12, 52066, 11, 11, 3523, 11, 12, 5068, // 10,12 + 10, 12, 5508, 10, 13, 50165, 11, 12, 4020, 11, 13, 5843, // 10,13 + 10, 13, 6104, 10, 14, 48314, 11, 13, 4505, 11, 14, 6613, // 10,14 + 10, 14, 6659, 10, 15, 46532, 11, 14, 4971, 11, 15, 7374, // 10,15 + 10, -1, 5169, 10, 0, 7599, 11, -1, 6970, 11, 0, 45798, // 11, 0 + 10, 0, 4734, 10, 1, 6886, 11, 0, 6458, 11, 1, 47458, // 11, 1 + 10, 1, 4290, 10, 2, 6176, 11, 1, 5920, 11, 2, 49150, // 11, 2 + 10, 2, 3845, 10, 3, 5481, 11, 2, 5365, 11, 3, 50845, // 11, 3 + 10, 3, 3415, 10, 4, 4822, 11, 3, 4816, 11, 4, 52483, // 11, 4 + 10, 4, 3023, 10, 5, 4230, 11, 4, 4309, 11, 5, 53974, // 11, 5 + 10, 5, 2711, 10, 6, 3759, 11, 5, 3902, 11, 6, 55164, // 11, 6 + 10, 6, 2525, 10, 7, 3473, 11, 6, 3671, 11, 7, 55867, // 11, 7 + 11, 7, 3672, 11, 8, 55870, 12, 7, 2524, 12, 8, 3470, // 11, 8 + 11, 8, 3904, 11, 9, 55166, 12, 8, 2710, 12, 9, 3756, // 11, 9 + 11, 9, 4313, 11, 10, 53975, 12, 9, 3023, 12, 10, 4225, // 11,10 + 11, 10, 4822, 11, 11, 52484, 12, 10, 3415, 12, 11, 4815, // 11,11 + 11, 11, 5373, 11, 12, 50843, 12, 11, 3846, 12, 12, 5474, // 11,12 + 11, 12, 5930, 11, 13, 49147, 12, 12, 4291, 12, 13, 6168, // 11,13 + 11, 13, 6472, 11, 14, 47453, 12, 13, 4736, 12, 14, 6875, // 11,14 + 11, 14, 6986, 11, 15, 45791, 12, 14, 5172, 12, 15, 7587, // 11,15 + 11, -1, 5410, 11, 0, 7863, 12, -1, 7356, 12, 0, 44907, // 12, 0 + 11, 0, 5009, 11, 1, 7204, 12, 0, 6892, 12, 1, 46431, // 12, 1 + 11, 1, 4607, 11, 2, 6560, 12, 1, 6414, 12, 2, 47955, // 12, 2 + 11, 2, 4214, 11, 3, 5943, 12, 2, 5934, 12, 3, 49445, // 12, 3 + 11, 3, 3846, 11, 4, 5373, 12, 3, 5474, 12, 4, 50843, // 12, 4 + 11, 4, 3523, 11, 5, 4879, 12, 4, 5069, 12, 5, 52065, // 12, 5 + 11, 5, 3274, 11, 6, 4495, 12, 5, 4759, 12, 6, 53008, // 12, 6 + 11, 6, 3128, 11, 7, 4259, 12, 6, 4592, 12, 7, 53557, // 12, 7 + 12, 7, 4594, 12, 8, 53562, 13, 7, 3126, 13, 8, 4254, // 12, 8 + 12, 8, 4762, 12, 9, 53012, 13, 8, 3273, 13, 9, 4489, // 12, 9 + 12, 9, 5073, 12, 10, 52069, 13, 9, 3522, 13, 10, 4872, // 12,10 + 12, 10, 5481, 12, 11, 50844, 13, 10, 3845, 13, 11, 5366, // 12,11 + 12, 11, 5943, 12, 12, 49445, 13, 11, 4214, 13, 12, 5934, // 12,12 + 12, 12, 6426, 12, 13, 47953, 13, 12, 4608, 13, 13, 6549, // 12,13 + 12, 13, 6908, 12, 14, 46427, 13, 13, 5011, 13, 14, 7190, // 12,14 + 12, 14, 7374, 12, 15, 44901, 13, 14, 5413, 13, 15, 7848, // 12,15 + 12, -1, 5682, 12, 0, 8159, 13, -1, 7791, 13, 0, 43904, // 13, 0 + 12, 0, 5315, 12, 1, 7555, 13, 0, 7378, 13, 1, 45288, // 13, 1 + 12, 1, 4954, 12, 2, 6973, 13, 1, 6959, 13, 2, 46650, // 13, 2 + 12, 2, 4608, 12, 3, 6426, 13, 2, 6549, 13, 3, 47953, // 13, 3 + 12, 3, 4291, 12, 4, 5930, 13, 3, 6168, 13, 4, 49147, // 13, 4 + 12, 4, 4020, 12, 5, 5508, 13, 4, 5842, 13, 5, 50166, // 13, 5 + 12, 5, 3815, 12, 6, 5184, 13, 5, 5602, 13, 6, 50935, // 13, 6 + 12, 6, 3693, 12, 7, 4978, 13, 6, 5478, 13, 7, 51387, // 13, 7 + 13, 7, 5480, 13, 8, 51395, 14, 7, 3691, 14, 8, 4970, // 13, 8 + 13, 8, 5606, 13, 9, 50942, 14, 8, 3813, 14, 9, 5175, // 13, 9 + 13, 9, 5848, 13, 10, 50171, 14, 9, 4019, 14, 10, 5498, // 13,10 + 13, 10, 6176, 13, 11, 49150, 14, 10, 4290, 14, 11, 5920, // 13,11 + 13, 11, 6560, 13, 12, 47955, 14, 11, 4607, 14, 12, 6414, // 13,12 + 13, 12, 6973, 13, 13, 46650, 14, 12, 4954, 14, 13, 6959, // 13,13 + 13, 13, 7395, 13, 14, 45286, 14, 13, 5316, 14, 14, 7539, // 13,14 + 13, 14, 7812, 13, 15, 43900, 14, 14, 5684, 14, 15, 8140, // 13,15 + 13, -1, 5974, 13, 0, 8474, 14, -1, 8265, 14, 0, 42823, // 14, 0 + 13, 0, 5640, 13, 1, 7921, 14, 0, 7901, 14, 1, 44074, // 14, 1 + 13, 1, 5316, 13, 2, 7395, 14, 1, 7539, 14, 2, 45286, // 14, 2 + 13, 2, 5011, 13, 3, 6908, 14, 2, 7191, 14, 3, 46426, // 14, 3 + 13, 3, 4736, 13, 4, 6472, 14, 3, 6875, 14, 4, 47453, // 14, 4 + 13, 4, 4505, 13, 5, 6104, 14, 4, 6613, 14, 5, 48314, // 14, 5 + 13, 5, 4330, 13, 6, 5820, 14, 5, 6425, 14, 6, 48961, // 14, 6 + 13, 6, 4224, 13, 7, 5633, 14, 6, 6332, 14, 7, 49347, // 14, 7 + 14, 7, 6335, 14, 8, 49358, 15, 7, 4221, 15, 8, 5622, // 14, 8 + 14, 8, 6430, 14, 9, 48969, 15, 8, 4327, 15, 9, 5810, // 14, 9 + 14, 9, 6620, 14, 10, 48322, 15, 9, 4502, 15, 10, 6092, // 14,10 + 14, 10, 6886, 14, 11, 47458, 15, 10, 4734, 15, 11, 6458, // 14,11 + 14, 11, 7204, 14, 12, 46430, 15, 11, 5009, 15, 12, 6893, // 14,12 + 14, 12, 7555, 14, 13, 45288, 15, 12, 5315, 15, 13, 7378, // 14,13 + 14, 13, 7921, 14, 14, 44074, 15, 13, 5640, 15, 14, 7901, // 14,14 + 14, 14, 8288, 14, 15, 42821, 15, 14, 5975, 15, 15, 8452, // 14,15 + 14, -1, 6280, 14, 0, 8795, 15, -1, 8769, 15, 0, 41692, // 15, 0 + 14, 0, 5975, 14, 1, 8288, 15, 0, 8452, 15, 1, 42821, // 15, 1 + 14, 1, 5684, 14, 2, 7812, 15, 1, 8141, 15, 2, 43899, // 15, 2 + 14, 2, 5413, 14, 3, 7374, 15, 2, 7848, 15, 3, 44901, // 15, 3 + 14, 3, 5172, 14, 4, 6986, 15, 3, 7587, 15, 4, 45791, // 15, 4 + 14, 4, 4971, 14, 5, 6659, 15, 4, 7374, 15, 5, 46532, // 15, 5 + 14, 5, 4818, 14, 6, 6405, 15, 5, 7227, 15, 6, 47086, // 15, 6 + 14, 6, 4722, 14, 7, 6230, 15, 6, 7158, 15, 7, 47426, // 15, 7 + 15, 7, 7161, 15, 8, 47440, 16, 7, 4718, 16, 8, 6217, // 15, 8 + 15, 8, 7233, 15, 9, 47098, 16, 8, 4814, 16, 9, 6391, // 15, 9 + 15, 9, 7383, 15, 10, 46541, 16, 9, 4967, 16, 10, 6645, // 15,10 + 15, 10, 7599, 15, 11, 45799, 16, 10, 5169, 16, 11, 6969, // 15,11 + 15, 11, 7863, 15, 12, 44907, 16, 11, 5410, 16, 12, 7356, // 15,12 + 15, 12, 8159, 15, 13, 43904, 16, 12, 5682, 16, 13, 7791, // 15,13 + 15, 13, 8474, 15, 14, 42823, 16, 13, 5974, 16, 14, 8265, // 15,14 + 15, 14, 8795, 15, 15, 41693, 16, 14, 6280, 16, 15, 8768, // 15,15 + // angle of -0.5 degrees + -1, 0, 5106, -1, 1, 3621, 0, 0, 51699, 0, 1, 5110, // 0, 0 + -1, 1, 4803, -1, 2, 3421, 0, 1, 52457, 0, 2, 4855, // 0, 1 + -1, 2, 4521, -1, 3, 3235, 0, 2, 53168, 0, 3, 4612, // 0, 2 + -1, 3, 4264, -1, 4, 3064, 0, 3, 53815, 0, 4, 4393, // 0, 3 + -1, 4, 4041, -1, 5, 2916, 0, 4, 54378, 0, 5, 4201, // 0, 4 + -1, 5, 3858, -1, 6, 2796, 0, 5, 54835, 0, 6, 4047, // 0, 5 + -1, 6, 3722, -1, 7, 2709, 0, 6, 55166, 0, 7, 3939, // 0, 6 + -1, 7, 3638, -1, 8, 2659, 0, 7, 55354, 0, 8, 3885, // 0, 7 + 0, 8, 55352, 0, 9, 3885, 1, 8, 3640, 1, 9, 2659, // 0, 8 + 0, 9, 55164, 0, 10, 3939, 1, 9, 3724, 1, 10, 2709, // 0, 9 + 0, 10, 54833, 0, 11, 4046, 1, 10, 3860, 1, 11, 2797, // 0,10 + 0, 11, 54376, 0, 12, 4200, 1, 11, 4043, 1, 12, 2917, // 0,11 + 0, 12, 53814, 0, 13, 4390, 1, 12, 4267, 1, 13, 3065, // 0,12 + 0, 13, 53168, 0, 14, 4610, 1, 13, 4523, 1, 14, 3235, // 0,13 + 0, 14, 52457, 0, 15, 4851, 1, 14, 4806, 1, 15, 3422, // 0,14 + 0, 15, 51699, 0, 16, 5106, 1, 15, 5110, 1, 16, 3621, // 0,15 + 0, 0, 4851, 0, 1, 3422, 1, 0, 52457, 1, 1, 4806, // 1, 0 + 0, 1, 4522, 0, 2, 3204, 1, 1, 53285, 1, 2, 4525, // 1, 1 + 0, 2, 4212, 0, 3, 2998, 1, 2, 54072, 1, 3, 4254, // 1, 2 + 0, 3, 3927, 0, 4, 2808, 1, 3, 54796, 1, 4, 4005, // 1, 3 + 0, 4, 3677, 0, 5, 2640, 1, 4, 55435, 1, 5, 3784, // 1, 4 + 0, 5, 3470, 0, 6, 2502, 1, 5, 55959, 1, 6, 3605, // 1, 5 + 0, 6, 3317, 0, 7, 2402, 1, 6, 56340, 1, 7, 3477, // 1, 6 + 0, 7, 3225, 0, 8, 2346, 1, 7, 56554, 1, 8, 3411, // 1, 7 + 1, 8, 56552, 1, 9, 3411, 2, 8, 3227, 2, 9, 2346, // 1, 8 + 1, 9, 56339, 1, 10, 3476, 2, 9, 3319, 2, 10, 2402, // 1, 9 + 1, 10, 55958, 1, 11, 3604, 2, 10, 3472, 2, 11, 2502, // 1,10 + 1, 11, 55434, 1, 12, 3783, 2, 11, 3678, 2, 12, 2641, // 1,11 + 1, 12, 54796, 1, 13, 4003, 2, 12, 3929, 2, 13, 2808, // 1,12 + 1, 13, 54071, 1, 14, 4253, 2, 13, 4214, 2, 14, 2998, // 1,13 + 1, 14, 53285, 1, 15, 4522, 2, 14, 4525, 2, 15, 3204, // 1,14 + 1, 15, 52457, 1, 16, 4803, 2, 15, 4854, 2, 16, 3422, // 1,15 + 1, 0, 4610, 1, 1, 3235, 2, 0, 53168, 2, 1, 4523, // 2, 0 + 1, 1, 4253, 1, 2, 2998, 2, 1, 54071, 2, 2, 4214, // 2, 1 + 1, 2, 3911, 1, 3, 2770, 2, 2, 54941, 2, 3, 3914, // 2, 2 + 1, 3, 3594, 1, 4, 2556, 2, 3, 55756, 2, 4, 3630, // 2, 3 + 1, 4, 3310, 1, 5, 2365, 2, 4, 56487, 2, 5, 3374, // 2, 4 + 1, 5, 3073, 1, 6, 2205, 2, 5, 57096, 2, 6, 3162, // 2, 5 + 1, 6, 2897, 1, 7, 2088, 2, 6, 57545, 2, 7, 3006, // 2, 6 + 1, 7, 2794, 1, 8, 2022, 2, 7, 57795, 2, 8, 2925, // 2, 7 + 2, 8, 57793, 2, 9, 2926, 3, 8, 2795, 3, 9, 2022, // 2, 8 + 2, 9, 57544, 2, 10, 3007, 3, 9, 2898, 3, 10, 2087, // 2, 9 + 2, 10, 57095, 2, 11, 3161, 3, 10, 3074, 3, 11, 2206, // 2,10 + 2, 11, 56486, 2, 12, 3373, 3, 11, 3311, 3, 12, 2366, // 2,11 + 2, 12, 55756, 2, 13, 3628, 3, 12, 3595, 3, 13, 2557, // 2,12 + 2, 13, 54941, 2, 14, 3911, 3, 13, 3913, 3, 14, 2771, // 2,13 + 2, 14, 54072, 2, 15, 4212, 3, 14, 4255, 3, 15, 2997, // 2,14 + 2, 15, 53168, 2, 16, 4521, 3, 15, 4612, 3, 16, 3235, // 2,15 + 2, 0, 4390, 2, 1, 3065, 3, 0, 53814, 3, 1, 4267, // 3, 0 + 2, 1, 4003, 2, 2, 2808, 3, 1, 54796, 3, 2, 3929, // 3, 1 + 2, 2, 3628, 2, 3, 2557, 3, 2, 55756, 3, 3, 3595, // 3, 2 + 2, 3, 3273, 2, 4, 2317, 3, 3, 56673, 3, 4, 3273, // 3, 3 + 2, 4, 2948, 2, 5, 2096, 3, 4, 57514, 3, 5, 2978, // 3, 4 + 2, 5, 2672, 2, 6, 1908, 3, 5, 58234, 3, 6, 2722, // 3, 5 + 2, 6, 2463, 2, 7, 1766, 3, 6, 58775, 3, 7, 2532, // 3, 6 + 2, 7, 2342, 2, 8, 1687, 3, 7, 59077, 3, 8, 2430, // 3, 7 + 3, 8, 59076, 3, 9, 2430, 4, 8, 2343, 4, 9, 1687, // 3, 8 + 3, 9, 58774, 3, 10, 2532, 4, 9, 2464, 4, 10, 1766, // 3, 9 + 3, 10, 58233, 3, 11, 2722, 4, 10, 2673, 4, 11, 1908, // 3,10 + 3, 11, 57514, 3, 12, 2976, 4, 11, 2950, 4, 12, 2096, // 3,11 + 3, 12, 56673, 3, 13, 3273, 4, 12, 3274, 4, 13, 2316, // 3,12 + 3, 13, 55756, 3, 14, 3594, 4, 13, 3630, 4, 14, 2556, // 3,13 + 3, 14, 54796, 3, 15, 3927, 4, 14, 4005, 4, 15, 2808, // 3,14 + 3, 15, 53815, 3, 16, 4264, 4, 15, 4392, 4, 16, 3065, // 3,15 + 3, 0, 4200, 3, 1, 2917, 4, 0, 54376, 4, 1, 4043, // 4, 0 + 3, 1, 3783, 3, 2, 2640, 4, 1, 55434, 4, 2, 3679, // 4, 1 + 3, 2, 3373, 3, 3, 2365, 4, 2, 56486, 4, 3, 3312, // 4, 2 + 3, 3, 2976, 3, 4, 2096, 4, 3, 57514, 4, 4, 2950, // 4, 3 + 3, 4, 2604, 3, 5, 1843, 4, 4, 58484, 4, 5, 2605, // 4, 4 + 3, 5, 2276, 3, 6, 1617, 4, 5, 59346, 4, 6, 2297, // 4, 5 + 3, 6, 2020, 3, 7, 1442, 4, 6, 60018, 4, 7, 2056, // 4, 6 + 3, 7, 1871, 3, 8, 1341, 4, 7, 60402, 4, 8, 1922, // 4, 7 + 4, 8, 60402, 4, 9, 1922, 5, 8, 1871, 5, 9, 1341, // 4, 8 + 4, 9, 60017, 4, 10, 2057, 5, 9, 2020, 5, 10, 1442, // 4, 9 + 4, 10, 59345, 4, 11, 2297, 5, 10, 2276, 5, 11, 1618, // 4,10 + 4, 11, 58484, 4, 12, 2604, 5, 11, 2605, 5, 12, 1843, // 4,11 + 4, 12, 57514, 4, 13, 2948, 5, 12, 2977, 5, 13, 2097, // 4,12 + 4, 13, 56487, 4, 14, 3310, 5, 13, 3374, 5, 14, 2365, // 4,13 + 4, 14, 55435, 4, 15, 3677, 5, 14, 3785, 5, 15, 2639, // 4,14 + 4, 15, 54378, 4, 16, 4041, 5, 15, 4201, 5, 16, 2916, // 4,15 + 4, 0, 4046, 4, 1, 2797, 5, 0, 54833, 5, 1, 3860, // 5, 0 + 4, 1, 3604, 4, 2, 2503, 5, 1, 55958, 5, 2, 3471, // 5, 1 + 4, 2, 3161, 4, 3, 2205, 5, 2, 57095, 5, 3, 3075, // 5, 2 + 4, 3, 2722, 4, 4, 1908, 5, 3, 58233, 5, 4, 2673, // 5, 3 + 4, 4, 2297, 4, 5, 1617, 5, 4, 59345, 5, 5, 2277, // 5, 4 + 4, 5, 1904, 4, 6, 1347, 5, 5, 60381, 5, 6, 1904, // 5, 5 + 4, 6, 1578, 4, 7, 1121, 5, 6, 61243, 5, 7, 1594, // 5, 6 + 4, 7, 1380, 4, 8, 985, 5, 7, 61767, 5, 8, 1404, // 5, 7 + 5, 8, 61767, 5, 9, 1405, 6, 8, 1380, 6, 9, 984, // 5, 8 + 5, 9, 61243, 5, 10, 1593, 6, 9, 1579, 6, 10, 1121, // 5, 9 + 5, 10, 60381, 5, 11, 1904, 6, 10, 1904, 6, 11, 1347, // 5,10 + 5, 11, 59346, 5, 12, 2276, 6, 11, 2297, 6, 12, 1617, // 5,11 + 5, 12, 58234, 5, 13, 2672, 6, 12, 2723, 6, 13, 1907, // 5,12 + 5, 13, 57096, 5, 14, 3073, 6, 13, 3161, 6, 14, 2206, // 5,13 + 5, 14, 55959, 5, 15, 3470, 6, 14, 3605, 6, 15, 2502, // 5,14 + 5, 15, 54835, 5, 16, 3858, 6, 15, 4047, 6, 16, 2796, // 5,15 + 5, 0, 3939, 5, 1, 2709, 6, 0, 55164, 6, 1, 3724, // 6, 0 + 5, 1, 3476, 5, 2, 2403, 6, 1, 56339, 6, 2, 3318, // 6, 1 + 5, 2, 3007, 5, 3, 2088, 6, 2, 57544, 6, 3, 2897, // 6, 2 + 5, 3, 2532, 5, 4, 1767, 6, 3, 58774, 6, 4, 2463, // 6, 3 + 5, 4, 2057, 5, 5, 1442, 6, 4, 60017, 6, 5, 2020, // 6, 4 + 5, 5, 1593, 5, 6, 1121, 6, 5, 61243, 6, 6, 1579, // 6, 5 + 5, 6, 1170, 5, 7, 827, 6, 6, 62369, 6, 7, 1170, // 6, 6 + 5, 7, 875, 5, 8, 622, 6, 7, 63156, 6, 8, 883, // 6, 7 + 6, 8, 63156, 6, 9, 883, 7, 8, 875, 7, 9, 622, // 6, 8 + 6, 9, 62369, 6, 10, 1170, 7, 9, 1170, 7, 10, 827, // 6, 9 + 6, 10, 61243, 6, 11, 1578, 7, 10, 1593, 7, 11, 1122, // 6,10 + 6, 11, 60018, 6, 12, 2020, 7, 11, 2057, 7, 12, 1441, // 6,11 + 6, 12, 58775, 6, 13, 2463, 7, 12, 2532, 7, 13, 1766, // 6,12 + 6, 13, 57545, 6, 14, 2897, 7, 13, 3007, 7, 14, 2087, // 6,13 + 6, 14, 56340, 6, 15, 3317, 7, 14, 3477, 7, 15, 2402, // 6,14 + 6, 15, 55166, 6, 16, 3722, 7, 15, 3940, 7, 16, 2708, // 6,15 + 6, 0, 3885, 6, 1, 2659, 7, 0, 55352, 7, 1, 3640, // 7, 0 + 6, 1, 3411, 6, 2, 2346, 7, 1, 56552, 7, 2, 3227, // 7, 1 + 6, 2, 2926, 6, 3, 2022, 7, 2, 57793, 7, 3, 2795, // 7, 2 + 6, 3, 2430, 6, 4, 1687, 7, 3, 59076, 7, 4, 2343, // 7, 3 + 6, 4, 1922, 6, 5, 1341, 7, 4, 60402, 7, 5, 1871, // 7, 4 + 6, 5, 1405, 6, 6, 985, 7, 5, 61767, 7, 6, 1379, // 7, 5 + 6, 6, 883, 6, 7, 622, 7, 6, 63156, 7, 7, 875, // 7, 6 + 6, 7, 399, 6, 8, 282, 7, 7, 64455, 7, 8, 400, // 7, 7 + 7, 8, 64455, 7, 9, 399, 8, 8, 399, 8, 9, 283, // 7, 8 + 7, 9, 63156, 7, 10, 875, 8, 9, 883, 8, 10, 622, // 7, 9 + 7, 10, 61767, 7, 11, 1380, 8, 10, 1405, 8, 11, 984, // 7,10 + 7, 11, 60402, 7, 12, 1871, 8, 11, 1922, 8, 12, 1341, // 7,11 + 7, 12, 59077, 7, 13, 2342, 8, 12, 2430, 8, 13, 1687, // 7,12 + 7, 13, 57795, 7, 14, 2794, 8, 13, 2926, 8, 14, 2021, // 7,13 + 7, 14, 56554, 7, 15, 3225, 8, 14, 3411, 8, 15, 2346, // 7,14 + 7, 15, 55354, 7, 16, 3638, 8, 15, 3885, 8, 16, 2659, // 7,15 + 7, -1, 2659, 7, 0, 3885, 8, -1, 3638, 8, 0, 55354, // 8, 0 + 7, 0, 2346, 7, 1, 3411, 8, 0, 3225, 8, 1, 56554, // 8, 1 + 7, 1, 2022, 7, 2, 2926, 8, 1, 2794, 8, 2, 57794, // 8, 2 + 7, 2, 1687, 7, 3, 2430, 8, 2, 2342, 8, 3, 59077, // 8, 3 + 7, 3, 1341, 7, 4, 1922, 8, 3, 1871, 8, 4, 60402, // 8, 4 + 7, 4, 985, 7, 5, 1405, 8, 4, 1380, 8, 5, 61766, // 8, 5 + 7, 5, 622, 7, 6, 883, 8, 5, 875, 8, 6, 63156, // 8, 6 + 7, 6, 282, 7, 7, 399, 8, 6, 399, 8, 7, 64456, // 8, 7 + 8, 7, 399, 8, 8, 64455, 9, 7, 282, 9, 8, 400, // 8, 8 + 8, 8, 875, 8, 9, 63156, 9, 8, 622, 9, 9, 883, // 8, 9 + 8, 9, 1380, 8, 10, 61767, 9, 9, 985, 9, 10, 1404, // 8,10 + 8, 10, 1871, 8, 11, 60402, 9, 10, 1341, 9, 11, 1922, // 8,11 + 8, 11, 2343, 8, 12, 59076, 9, 11, 1687, 9, 12, 2430, // 8,12 + 8, 12, 2795, 8, 13, 57793, 9, 12, 2022, 9, 13, 2926, // 8,13 + 8, 13, 3227, 8, 14, 56552, 9, 13, 2346, 9, 14, 3411, // 8,14 + 8, 14, 3640, 8, 15, 55352, 9, 14, 2659, 9, 15, 3885, // 8,15 + 8, -1, 2709, 8, 0, 3940, 9, -1, 3722, 9, 0, 55165, // 9, 0 + 8, 0, 2402, 8, 1, 3477, 9, 0, 3317, 9, 1, 56340, // 9, 1 + 8, 1, 2088, 8, 2, 3007, 9, 1, 2897, 9, 2, 57544, // 9, 2 + 8, 2, 1766, 8, 3, 2532, 9, 2, 2463, 9, 3, 58775, // 9, 3 + 8, 3, 1442, 8, 4, 2057, 9, 3, 2020, 9, 4, 60017, // 9, 4 + 8, 4, 1121, 8, 5, 1593, 9, 4, 1578, 9, 5, 61244, // 9, 5 + 8, 5, 827, 8, 6, 1170, 9, 5, 1170, 9, 6, 62369, // 9, 6 + 8, 6, 622, 8, 7, 875, 9, 6, 883, 9, 7, 63156, // 9, 7 + 9, 7, 883, 9, 8, 63156, 10, 7, 622, 10, 8, 875, // 9, 8 + 9, 8, 1170, 9, 9, 62369, 10, 8, 827, 10, 9, 1170, // 9, 9 + 9, 9, 1579, 9, 10, 61243, 10, 9, 1121, 10, 10, 1593, // 9,10 + 9, 10, 2020, 9, 11, 60017, 10, 10, 1442, 10, 11, 2057, // 9,11 + 9, 11, 2464, 9, 12, 58774, 10, 11, 1767, 10, 12, 2531, // 9,12 + 9, 12, 2898, 9, 13, 57544, 10, 12, 2088, 10, 13, 3006, // 9,13 + 9, 13, 3319, 9, 14, 56339, 10, 13, 2403, 10, 14, 3475, // 9,14 + 9, 14, 3724, 9, 15, 55164, 10, 14, 2709, 10, 15, 3939, // 9,15 + 9, -1, 2796, 9, 0, 4047, 10, -1, 3858, 10, 0, 54835, // 10, 0 + 9, 0, 2502, 9, 1, 3605, 10, 0, 3470, 10, 1, 55959, // 10, 1 + 9, 1, 2205, 9, 2, 3161, 10, 1, 3073, 10, 2, 57097, // 10, 2 + 9, 2, 1908, 9, 3, 2723, 10, 2, 2672, 10, 3, 58233, // 10, 3 + 9, 3, 1617, 9, 4, 2297, 10, 3, 2276, 10, 4, 59346, // 10, 4 + 9, 4, 1347, 9, 5, 1904, 10, 4, 1904, 10, 5, 60381, // 10, 5 + 9, 5, 1121, 9, 6, 1579, 10, 5, 1593, 10, 6, 61243, // 10, 6 + 9, 6, 985, 9, 7, 1380, 10, 6, 1405, 10, 7, 61766, // 10, 7 + 10, 7, 1405, 10, 8, 61767, 11, 7, 985, 11, 8, 1379, // 10, 8 + 10, 8, 1593, 10, 9, 61243, 11, 8, 1121, 11, 9, 1579, // 10, 9 + 10, 9, 1904, 10, 10, 60381, 11, 9, 1347, 11, 10, 1904, // 10,10 + 10, 10, 2276, 10, 11, 59345, 11, 10, 1617, 11, 11, 2298, // 10,11 + 10, 11, 2673, 10, 12, 58233, 11, 11, 1908, 11, 12, 2722, // 10,12 + 10, 12, 3074, 10, 13, 57095, 11, 12, 2205, 11, 13, 3162, // 10,13 + 10, 13, 3472, 10, 14, 55958, 11, 13, 2503, 11, 14, 3603, // 10,14 + 10, 14, 3860, 10, 15, 54833, 11, 14, 2797, 11, 15, 4046, // 10,15 + 10, -1, 2916, 10, 0, 4201, 11, -1, 4041, 11, 0, 54378, // 11, 0 + 10, 0, 2640, 10, 1, 3785, 11, 0, 3677, 11, 1, 55434, // 11, 1 + 10, 1, 2365, 10, 2, 3374, 11, 1, 3310, 11, 2, 56487, // 11, 2 + 10, 2, 2096, 10, 3, 2977, 11, 2, 2948, 11, 3, 57515, // 11, 3 + 10, 3, 1843, 10, 4, 2605, 11, 3, 2604, 11, 4, 58484, // 11, 4 + 10, 4, 1617, 10, 5, 2276, 11, 4, 2297, 11, 5, 59346, // 11, 5 + 10, 5, 1442, 10, 6, 2020, 11, 5, 2057, 11, 6, 60017, // 11, 6 + 10, 6, 1341, 10, 7, 1871, 11, 6, 1922, 11, 7, 60402, // 11, 7 + 11, 7, 1922, 11, 8, 60402, 12, 7, 1341, 12, 8, 1871, // 11, 8 + 11, 8, 2057, 11, 9, 60018, 12, 8, 1442, 12, 9, 2019, // 11, 9 + 11, 9, 2297, 11, 10, 59346, 12, 9, 1617, 12, 10, 2276, // 11,10 + 11, 10, 2605, 11, 11, 58484, 12, 10, 1843, 12, 11, 2604, // 11,11 + 11, 11, 2950, 11, 12, 57514, 12, 11, 2096, 12, 12, 2976, // 11,12 + 11, 12, 3311, 11, 13, 56486, 12, 12, 2365, 12, 13, 3374, // 11,13 + 11, 13, 3678, 11, 14, 55434, 12, 13, 2640, 12, 14, 3784, // 11,14 + 11, 14, 4043, 11, 15, 54376, 12, 14, 2917, 12, 15, 4200, // 11,15 + 11, -1, 3064, 11, 0, 4392, 12, -1, 4264, 12, 0, 53816, // 12, 0 + 11, 0, 2808, 11, 1, 4005, 12, 0, 3927, 12, 1, 54796, // 12, 1 + 11, 1, 2556, 11, 2, 3630, 12, 1, 3594, 12, 2, 55756, // 12, 2 + 11, 2, 2317, 11, 3, 3274, 12, 2, 3273, 12, 3, 56672, // 12, 3 + 11, 3, 2096, 11, 4, 2950, 12, 3, 2976, 12, 4, 57514, // 12, 4 + 11, 4, 1908, 11, 5, 2673, 12, 4, 2722, 12, 5, 58233, // 12, 5 + 11, 5, 1767, 11, 6, 2464, 12, 5, 2532, 12, 6, 58773, // 12, 6 + 11, 6, 1687, 11, 7, 2343, 12, 6, 2430, 12, 7, 59076, // 12, 7 + 12, 7, 2430, 12, 8, 59077, 13, 7, 1687, 13, 8, 2342, // 12, 8 + 12, 8, 2532, 12, 9, 58775, 13, 8, 1766, 13, 9, 2463, // 12, 9 + 12, 9, 2723, 12, 10, 58234, 13, 9, 1908, 13, 10, 2671, // 12,10 + 12, 10, 2977, 12, 11, 57514, 13, 10, 2096, 13, 11, 2949, // 12,11 + 12, 11, 3274, 12, 12, 56673, 13, 11, 2317, 13, 12, 3272, // 12,12 + 12, 12, 3595, 12, 13, 55756, 13, 12, 2557, 13, 13, 3628, // 12,13 + 12, 13, 3929, 12, 14, 54796, 13, 13, 2808, 13, 14, 4003, // 12,14 + 12, 14, 4267, 12, 15, 53814, 13, 14, 3065, 13, 15, 4390, // 12,15 + 12, -1, 3235, 12, 0, 4612, 13, -1, 4521, 13, 0, 53168, // 13, 0 + 12, 0, 2998, 12, 1, 4255, 13, 0, 4212, 13, 1, 54071, // 13, 1 + 12, 1, 2770, 12, 2, 3913, 13, 1, 3911, 13, 2, 54942, // 13, 2 + 12, 2, 2557, 12, 3, 3595, 13, 2, 3628, 13, 3, 55756, // 13, 3 + 12, 3, 2365, 12, 4, 3311, 13, 3, 3373, 13, 4, 56487, // 13, 4 + 12, 4, 2205, 12, 5, 3074, 13, 4, 3161, 13, 5, 57096, // 13, 5 + 12, 5, 2088, 12, 6, 2898, 13, 5, 3007, 13, 6, 57543, // 13, 6 + 12, 6, 2022, 12, 7, 2795, 13, 6, 2926, 13, 7, 57793, // 13, 7 + 13, 7, 2926, 13, 8, 57795, 14, 7, 2022, 14, 8, 2793, // 13, 8 + 13, 8, 3007, 13, 9, 57545, 14, 8, 2088, 14, 9, 2896, // 13, 9 + 13, 9, 3161, 13, 10, 57096, 14, 9, 2205, 14, 10, 3074, // 13,10 + 13, 10, 3374, 13, 11, 56487, 14, 10, 2365, 14, 11, 3310, // 13,11 + 13, 11, 3630, 13, 12, 55756, 14, 11, 2556, 14, 12, 3594, // 13,12 + 13, 12, 3913, 13, 13, 54941, 14, 12, 2770, 14, 13, 3912, // 13,13 + 13, 13, 4214, 13, 14, 54071, 14, 13, 2998, 14, 14, 4253, // 13,14 + 13, 14, 4523, 13, 15, 53168, 14, 14, 3235, 14, 15, 4610, // 13,15 + 13, -1, 3421, 13, 0, 4854, 14, -1, 4803, 14, 0, 52458, // 14, 0 + 13, 0, 3204, 13, 1, 4525, 14, 0, 4522, 14, 1, 53285, // 14, 1 + 13, 1, 2998, 13, 2, 4214, 14, 1, 4253, 14, 2, 54071, // 14, 2 + 13, 2, 2808, 13, 3, 3929, 14, 2, 4003, 14, 3, 54796, // 14, 3 + 13, 3, 2640, 13, 4, 3678, 14, 3, 3783, 14, 4, 55435, // 14, 4 + 13, 4, 2503, 13, 5, 3472, 14, 4, 3604, 14, 5, 55957, // 14, 5 + 13, 5, 2403, 13, 6, 3319, 14, 5, 3476, 14, 6, 56338, // 14, 6 + 13, 6, 2346, 13, 7, 3227, 14, 6, 3411, 14, 7, 56552, // 14, 7 + 14, 7, 3411, 14, 8, 56554, 15, 7, 2346, 15, 8, 3225, // 14, 8 + 14, 8, 3477, 14, 9, 56340, 15, 8, 2402, 15, 9, 3317, // 14, 9 + 14, 9, 3605, 14, 10, 55959, 15, 9, 2502, 15, 10, 3470, // 14,10 + 14, 10, 3785, 14, 11, 55435, 15, 10, 2640, 15, 11, 3676, // 14,11 + 14, 11, 4005, 14, 12, 54796, 15, 11, 2808, 15, 12, 3927, // 14,12 + 14, 12, 4255, 14, 13, 54072, 15, 12, 2998, 15, 13, 4211, // 14,13 + 14, 13, 4525, 14, 14, 53285, 15, 13, 3204, 15, 14, 4522, // 14,14 + 14, 14, 4806, 14, 15, 52457, 15, 14, 3422, 15, 15, 4851, // 14,15 + 14, -1, 3621, 14, 0, 5110, 15, -1, 5106, 15, 0, 51699, // 15, 0 + 14, 0, 3422, 14, 1, 4806, 15, 0, 4851, 15, 1, 52457, // 15, 1 + 14, 1, 3235, 14, 2, 4523, 15, 1, 4610, 15, 2, 53168, // 15, 2 + 14, 2, 3065, 14, 3, 4267, 15, 2, 4390, 15, 3, 53814, // 15, 3 + 14, 3, 2917, 14, 4, 4043, 15, 3, 4200, 15, 4, 54376, // 15, 4 + 14, 4, 2797, 14, 5, 3860, 15, 4, 4046, 15, 5, 54833, // 15, 5 + 14, 5, 2709, 14, 6, 3724, 15, 5, 3939, 15, 6, 55164, // 15, 6 + 14, 6, 2659, 14, 7, 3640, 15, 6, 3885, 15, 7, 55352, // 15, 7 + 15, 7, 3885, 15, 8, 55354, 16, 7, 2659, 16, 8, 3638, // 15, 8 + 15, 8, 3940, 15, 9, 55166, 16, 8, 2709, 16, 9, 3721, // 15, 9 + 15, 9, 4047, 15, 10, 54835, 16, 9, 2796, 16, 10, 3858, // 15,10 + 15, 10, 4201, 15, 11, 54378, 16, 10, 2916, 16, 11, 4041, // 15,11 + 15, 11, 4392, 15, 12, 53815, 16, 11, 3064, 16, 12, 4265, // 15,12 + 15, 12, 4612, 15, 13, 53168, 16, 12, 3235, 16, 13, 4521, // 15,13 + 15, 13, 4854, 15, 14, 52457, 16, 13, 3421, 16, 14, 4804, // 15,14 + 15, 14, 5110, 15, 15, 51699, 16, 14, 3621, 16, 15, 5106, // 15,15 + // angle of 0.0 degrees + 0, 0, 16384, 0, 0, 16384, 0, 0, 16384, 0, 0, 16384, // 0, 0 + 0, 1, 16384, 0, 1, 16384, 0, 1, 16384, 0, 1, 16384, // 0, 1 + 0, 2, 16384, 0, 2, 16384, 0, 2, 16384, 0, 2, 16384, // 0, 2 + 0, 3, 16384, 0, 3, 16384, 0, 3, 16384, 0, 3, 16384, // 0, 3 + 0, 4, 16384, 0, 4, 16384, 0, 4, 16384, 0, 4, 16384, // 0, 4 + 0, 5, 16384, 0, 5, 16384, 0, 5, 16384, 0, 5, 16384, // 0, 5 + 0, 6, 16384, 0, 6, 16384, 0, 6, 16384, 0, 6, 16384, // 0, 6 + 0, 7, 16384, 0, 7, 16384, 0, 7, 16384, 0, 7, 16384, // 0, 7 + 0, 8, 16384, 0, 8, 16384, 0, 8, 16384, 0, 8, 16384, // 0, 8 + 0, 9, 16384, 0, 9, 16384, 0, 9, 16384, 0, 9, 16384, // 0, 9 + 0, 10, 16384, 0, 10, 16384, 0, 10, 16384, 0, 10, 16384, // 0,10 + 0, 11, 16384, 0, 11, 16384, 0, 11, 16384, 0, 11, 16384, // 0,11 + 0, 12, 16384, 0, 12, 16384, 0, 12, 16384, 0, 12, 16384, // 0,12 + 0, 13, 16384, 0, 13, 16384, 0, 13, 16384, 0, 13, 16384, // 0,13 + 0, 14, 16384, 0, 14, 16384, 0, 14, 16384, 0, 14, 16384, // 0,14 + 0, 15, 16384, 0, 15, 16384, 0, 15, 16384, 0, 15, 16384, // 0,15 + 1, 0, 16384, 1, 0, 16384, 1, 0, 16384, 1, 0, 16384, // 1, 0 + 1, 1, 16384, 1, 1, 16384, 1, 1, 16384, 1, 1, 16384, // 1, 1 + 1, 2, 16384, 1, 2, 16384, 1, 2, 16384, 1, 2, 16384, // 1, 2 + 1, 3, 16384, 1, 3, 16384, 1, 3, 16384, 1, 3, 16384, // 1, 3 + 1, 4, 16384, 1, 4, 16384, 1, 4, 16384, 1, 4, 16384, // 1, 4 + 1, 5, 16384, 1, 5, 16384, 1, 5, 16384, 1, 5, 16384, // 1, 5 + 1, 6, 16384, 1, 6, 16384, 1, 6, 16384, 1, 6, 16384, // 1, 6 + 1, 7, 16384, 1, 7, 16384, 1, 7, 16384, 1, 7, 16384, // 1, 7 + 1, 8, 16384, 1, 8, 16384, 1, 8, 16384, 1, 8, 16384, // 1, 8 + 1, 9, 16384, 1, 9, 16384, 1, 9, 16384, 1, 9, 16384, // 1, 9 + 1, 10, 16384, 1, 10, 16384, 1, 10, 16384, 1, 10, 16384, // 1,10 + 1, 11, 16384, 1, 11, 16384, 1, 11, 16384, 1, 11, 16384, // 1,11 + 1, 12, 16384, 1, 12, 16384, 1, 12, 16384, 1, 12, 16384, // 1,12 + 1, 13, 16384, 1, 13, 16384, 1, 13, 16384, 1, 13, 16384, // 1,13 + 1, 14, 16384, 1, 14, 16384, 1, 14, 16384, 1, 14, 16384, // 1,14 + 1, 15, 16384, 1, 15, 16384, 1, 15, 16384, 1, 15, 16384, // 1,15 + 2, 0, 16384, 2, 0, 16384, 2, 0, 16384, 2, 0, 16384, // 2, 0 + 2, 1, 16384, 2, 1, 16384, 2, 1, 16384, 2, 1, 16384, // 2, 1 + 2, 2, 16384, 2, 2, 16384, 2, 2, 16384, 2, 2, 16384, // 2, 2 + 2, 3, 16384, 2, 3, 16384, 2, 3, 16384, 2, 3, 16384, // 2, 3 + 2, 4, 16384, 2, 4, 16384, 2, 4, 16384, 2, 4, 16384, // 2, 4 + 2, 5, 16384, 2, 5, 16384, 2, 5, 16384, 2, 5, 16384, // 2, 5 + 2, 6, 16384, 2, 6, 16384, 2, 6, 16384, 2, 6, 16384, // 2, 6 + 2, 7, 16384, 2, 7, 16384, 2, 7, 16384, 2, 7, 16384, // 2, 7 + 2, 8, 16384, 2, 8, 16384, 2, 8, 16384, 2, 8, 16384, // 2, 8 + 2, 9, 16384, 2, 9, 16384, 2, 9, 16384, 2, 9, 16384, // 2, 9 + 2, 10, 16384, 2, 10, 16384, 2, 10, 16384, 2, 10, 16384, // 2,10 + 2, 11, 16384, 2, 11, 16384, 2, 11, 16384, 2, 11, 16384, // 2,11 + 2, 12, 16384, 2, 12, 16384, 2, 12, 16384, 2, 12, 16384, // 2,12 + 2, 13, 16384, 2, 13, 16384, 2, 13, 16384, 2, 13, 16384, // 2,13 + 2, 14, 16384, 2, 14, 16384, 2, 14, 16384, 2, 14, 16384, // 2,14 + 2, 15, 16384, 2, 15, 16384, 2, 15, 16384, 2, 15, 16384, // 2,15 + 3, 0, 16384, 3, 0, 16384, 3, 0, 16384, 3, 0, 16384, // 3, 0 + 3, 1, 16384, 3, 1, 16384, 3, 1, 16384, 3, 1, 16384, // 3, 1 + 3, 2, 16384, 3, 2, 16384, 3, 2, 16384, 3, 2, 16384, // 3, 2 + 3, 3, 16384, 3, 3, 16384, 3, 3, 16384, 3, 3, 16384, // 3, 3 + 3, 4, 16384, 3, 4, 16384, 3, 4, 16384, 3, 4, 16384, // 3, 4 + 3, 5, 16384, 3, 5, 16384, 3, 5, 16384, 3, 5, 16384, // 3, 5 + 3, 6, 16384, 3, 6, 16384, 3, 6, 16384, 3, 6, 16384, // 3, 6 + 3, 7, 16384, 3, 7, 16384, 3, 7, 16384, 3, 7, 16384, // 3, 7 + 3, 8, 16384, 3, 8, 16384, 3, 8, 16384, 3, 8, 16384, // 3, 8 + 3, 9, 16384, 3, 9, 16384, 3, 9, 16384, 3, 9, 16384, // 3, 9 + 3, 10, 16384, 3, 10, 16384, 3, 10, 16384, 3, 10, 16384, // 3,10 + 3, 11, 16384, 3, 11, 16384, 3, 11, 16384, 3, 11, 16384, // 3,11 + 3, 12, 16384, 3, 12, 16384, 3, 12, 16384, 3, 12, 16384, // 3,12 + 3, 13, 16384, 3, 13, 16384, 3, 13, 16384, 3, 13, 16384, // 3,13 + 3, 14, 16384, 3, 14, 16384, 3, 14, 16384, 3, 14, 16384, // 3,14 + 3, 15, 16384, 3, 15, 16384, 3, 15, 16384, 3, 15, 16384, // 3,15 + 4, 0, 16384, 4, 0, 16384, 4, 0, 16384, 4, 0, 16384, // 4, 0 + 4, 1, 16384, 4, 1, 16384, 4, 1, 16384, 4, 1, 16384, // 4, 1 + 4, 2, 16384, 4, 2, 16384, 4, 2, 16384, 4, 2, 16384, // 4, 2 + 4, 3, 16384, 4, 3, 16384, 4, 3, 16384, 4, 3, 16384, // 4, 3 + 4, 4, 16384, 4, 4, 16384, 4, 4, 16384, 4, 4, 16384, // 4, 4 + 4, 5, 16384, 4, 5, 16384, 4, 5, 16384, 4, 5, 16384, // 4, 5 + 4, 6, 16384, 4, 6, 16384, 4, 6, 16384, 4, 6, 16384, // 4, 6 + 4, 7, 16384, 4, 7, 16384, 4, 7, 16384, 4, 7, 16384, // 4, 7 + 4, 8, 16384, 4, 8, 16384, 4, 8, 16384, 4, 8, 16384, // 4, 8 + 4, 9, 16384, 4, 9, 16384, 4, 9, 16384, 4, 9, 16384, // 4, 9 + 4, 10, 16384, 4, 10, 16384, 4, 10, 16384, 4, 10, 16384, // 4,10 + 4, 11, 16384, 4, 11, 16384, 4, 11, 16384, 4, 11, 16384, // 4,11 + 4, 12, 16384, 4, 12, 16384, 4, 12, 16384, 4, 12, 16384, // 4,12 + 4, 13, 16384, 4, 13, 16384, 4, 13, 16384, 4, 13, 16384, // 4,13 + 4, 14, 16384, 4, 14, 16384, 4, 14, 16384, 4, 14, 16384, // 4,14 + 4, 15, 16384, 4, 15, 16384, 4, 15, 16384, 4, 15, 16384, // 4,15 + 5, 0, 16384, 5, 0, 16384, 5, 0, 16384, 5, 0, 16384, // 5, 0 + 5, 1, 16384, 5, 1, 16384, 5, 1, 16384, 5, 1, 16384, // 5, 1 + 5, 2, 16384, 5, 2, 16384, 5, 2, 16384, 5, 2, 16384, // 5, 2 + 5, 3, 16384, 5, 3, 16384, 5, 3, 16384, 5, 3, 16384, // 5, 3 + 5, 4, 16384, 5, 4, 16384, 5, 4, 16384, 5, 4, 16384, // 5, 4 + 5, 5, 16384, 5, 5, 16384, 5, 5, 16384, 5, 5, 16384, // 5, 5 + 5, 6, 16384, 5, 6, 16384, 5, 6, 16384, 5, 6, 16384, // 5, 6 + 5, 7, 16384, 5, 7, 16384, 5, 7, 16384, 5, 7, 16384, // 5, 7 + 5, 8, 16384, 5, 8, 16384, 5, 8, 16384, 5, 8, 16384, // 5, 8 + 5, 9, 16384, 5, 9, 16384, 5, 9, 16384, 5, 9, 16384, // 5, 9 + 5, 10, 16384, 5, 10, 16384, 5, 10, 16384, 5, 10, 16384, // 5,10 + 5, 11, 16384, 5, 11, 16384, 5, 11, 16384, 5, 11, 16384, // 5,11 + 5, 12, 16384, 5, 12, 16384, 5, 12, 16384, 5, 12, 16384, // 5,12 + 5, 13, 16384, 5, 13, 16384, 5, 13, 16384, 5, 13, 16384, // 5,13 + 5, 14, 16384, 5, 14, 16384, 5, 14, 16384, 5, 14, 16384, // 5,14 + 5, 15, 16384, 5, 15, 16384, 5, 15, 16384, 5, 15, 16384, // 5,15 + 6, 0, 16384, 6, 0, 16384, 6, 0, 16384, 6, 0, 16384, // 6, 0 + 6, 1, 16384, 6, 1, 16384, 6, 1, 16384, 6, 1, 16384, // 6, 1 + 6, 2, 16384, 6, 2, 16384, 6, 2, 16384, 6, 2, 16384, // 6, 2 + 6, 3, 16384, 6, 3, 16384, 6, 3, 16384, 6, 3, 16384, // 6, 3 + 6, 4, 16384, 6, 4, 16384, 6, 4, 16384, 6, 4, 16384, // 6, 4 + 6, 5, 16384, 6, 5, 16384, 6, 5, 16384, 6, 5, 16384, // 6, 5 + 6, 6, 16384, 6, 6, 16384, 6, 6, 16384, 6, 6, 16384, // 6, 6 + 6, 7, 16384, 6, 7, 16384, 6, 7, 16384, 6, 7, 16384, // 6, 7 + 6, 8, 16384, 6, 8, 16384, 6, 8, 16384, 6, 8, 16384, // 6, 8 + 6, 9, 16384, 6, 9, 16384, 6, 9, 16384, 6, 9, 16384, // 6, 9 + 6, 10, 16384, 6, 10, 16384, 6, 10, 16384, 6, 10, 16384, // 6,10 + 6, 11, 16384, 6, 11, 16384, 6, 11, 16384, 6, 11, 16384, // 6,11 + 6, 12, 16384, 6, 12, 16384, 6, 12, 16384, 6, 12, 16384, // 6,12 + 6, 13, 16384, 6, 13, 16384, 6, 13, 16384, 6, 13, 16384, // 6,13 + 6, 14, 16384, 6, 14, 16384, 6, 14, 16384, 6, 14, 16384, // 6,14 + 6, 15, 16384, 6, 15, 16384, 6, 15, 16384, 6, 15, 16384, // 6,15 + 7, 0, 16384, 7, 0, 16384, 7, 0, 16384, 7, 0, 16384, // 7, 0 + 7, 1, 16384, 7, 1, 16384, 7, 1, 16384, 7, 1, 16384, // 7, 1 + 7, 2, 16384, 7, 2, 16384, 7, 2, 16384, 7, 2, 16384, // 7, 2 + 7, 3, 16384, 7, 3, 16384, 7, 3, 16384, 7, 3, 16384, // 7, 3 + 7, 4, 16384, 7, 4, 16384, 7, 4, 16384, 7, 4, 16384, // 7, 4 + 7, 5, 16384, 7, 5, 16384, 7, 5, 16384, 7, 5, 16384, // 7, 5 + 7, 6, 16384, 7, 6, 16384, 7, 6, 16384, 7, 6, 16384, // 7, 6 + 7, 7, 16384, 7, 7, 16384, 7, 7, 16384, 7, 7, 16384, // 7, 7 + 7, 8, 16384, 7, 8, 16384, 7, 8, 16384, 7, 8, 16384, // 7, 8 + 7, 9, 16384, 7, 9, 16384, 7, 9, 16384, 7, 9, 16384, // 7, 9 + 7, 10, 16384, 7, 10, 16384, 7, 10, 16384, 7, 10, 16384, // 7,10 + 7, 11, 16384, 7, 11, 16384, 7, 11, 16384, 7, 11, 16384, // 7,11 + 7, 12, 16384, 7, 12, 16384, 7, 12, 16384, 7, 12, 16384, // 7,12 + 7, 13, 16384, 7, 13, 16384, 7, 13, 16384, 7, 13, 16384, // 7,13 + 7, 14, 16384, 7, 14, 16384, 7, 14, 16384, 7, 14, 16384, // 7,14 + 7, 15, 16384, 7, 15, 16384, 7, 15, 16384, 7, 15, 16384, // 7,15 + 8, 0, 16384, 8, 0, 16384, 8, 0, 16384, 8, 0, 16384, // 8, 0 + 8, 1, 16384, 8, 1, 16384, 8, 1, 16384, 8, 1, 16384, // 8, 1 + 8, 2, 16384, 8, 2, 16384, 8, 2, 16384, 8, 2, 16384, // 8, 2 + 8, 3, 16384, 8, 3, 16384, 8, 3, 16384, 8, 3, 16384, // 8, 3 + 8, 4, 16384, 8, 4, 16384, 8, 4, 16384, 8, 4, 16384, // 8, 4 + 8, 5, 16384, 8, 5, 16384, 8, 5, 16384, 8, 5, 16384, // 8, 5 + 8, 6, 16384, 8, 6, 16384, 8, 6, 16384, 8, 6, 16384, // 8, 6 + 8, 7, 16384, 8, 7, 16384, 8, 7, 16384, 8, 7, 16384, // 8, 7 + 8, 8, 16384, 8, 8, 16384, 8, 8, 16384, 8, 8, 16384, // 8, 8 + 8, 9, 16384, 8, 9, 16384, 8, 9, 16384, 8, 9, 16384, // 8, 9 + 8, 10, 16384, 8, 10, 16384, 8, 10, 16384, 8, 10, 16384, // 8,10 + 8, 11, 16384, 8, 11, 16384, 8, 11, 16384, 8, 11, 16384, // 8,11 + 8, 12, 16384, 8, 12, 16384, 8, 12, 16384, 8, 12, 16384, // 8,12 + 8, 13, 16384, 8, 13, 16384, 8, 13, 16384, 8, 13, 16384, // 8,13 + 8, 14, 16384, 8, 14, 16384, 8, 14, 16384, 8, 14, 16384, // 8,14 + 8, 15, 16384, 8, 15, 16384, 8, 15, 16384, 8, 15, 16384, // 8,15 + 9, 0, 16384, 9, 0, 16384, 9, 0, 16384, 9, 0, 16384, // 9, 0 + 9, 1, 16384, 9, 1, 16384, 9, 1, 16384, 9, 1, 16384, // 9, 1 + 9, 2, 16384, 9, 2, 16384, 9, 2, 16384, 9, 2, 16384, // 9, 2 + 9, 3, 16384, 9, 3, 16384, 9, 3, 16384, 9, 3, 16384, // 9, 3 + 9, 4, 16384, 9, 4, 16384, 9, 4, 16384, 9, 4, 16384, // 9, 4 + 9, 5, 16384, 9, 5, 16384, 9, 5, 16384, 9, 5, 16384, // 9, 5 + 9, 6, 16384, 9, 6, 16384, 9, 6, 16384, 9, 6, 16384, // 9, 6 + 9, 7, 16384, 9, 7, 16384, 9, 7, 16384, 9, 7, 16384, // 9, 7 + 9, 8, 16384, 9, 8, 16384, 9, 8, 16384, 9, 8, 16384, // 9, 8 + 9, 9, 16384, 9, 9, 16384, 9, 9, 16384, 9, 9, 16384, // 9, 9 + 9, 10, 16384, 9, 10, 16384, 9, 10, 16384, 9, 10, 16384, // 9,10 + 9, 11, 16384, 9, 11, 16384, 9, 11, 16384, 9, 11, 16384, // 9,11 + 9, 12, 16384, 9, 12, 16384, 9, 12, 16384, 9, 12, 16384, // 9,12 + 9, 13, 16384, 9, 13, 16384, 9, 13, 16384, 9, 13, 16384, // 9,13 + 9, 14, 16384, 9, 14, 16384, 9, 14, 16384, 9, 14, 16384, // 9,14 + 9, 15, 16384, 9, 15, 16384, 9, 15, 16384, 9, 15, 16384, // 9,15 + 10, 0, 16384, 10, 0, 16384, 10, 0, 16384, 10, 0, 16384, // 10, 0 + 10, 1, 16384, 10, 1, 16384, 10, 1, 16384, 10, 1, 16384, // 10, 1 + 10, 2, 16384, 10, 2, 16384, 10, 2, 16384, 10, 2, 16384, // 10, 2 + 10, 3, 16384, 10, 3, 16384, 10, 3, 16384, 10, 3, 16384, // 10, 3 + 10, 4, 16384, 10, 4, 16384, 10, 4, 16384, 10, 4, 16384, // 10, 4 + 10, 5, 16384, 10, 5, 16384, 10, 5, 16384, 10, 5, 16384, // 10, 5 + 10, 6, 16384, 10, 6, 16384, 10, 6, 16384, 10, 6, 16384, // 10, 6 + 10, 7, 16384, 10, 7, 16384, 10, 7, 16384, 10, 7, 16384, // 10, 7 + 10, 8, 16384, 10, 8, 16384, 10, 8, 16384, 10, 8, 16384, // 10, 8 + 10, 9, 16384, 10, 9, 16384, 10, 9, 16384, 10, 9, 16384, // 10, 9 + 10, 10, 16384, 10, 10, 16384, 10, 10, 16384, 10, 10, 16384, // 10,10 + 10, 11, 16384, 10, 11, 16384, 10, 11, 16384, 10, 11, 16384, // 10,11 + 10, 12, 16384, 10, 12, 16384, 10, 12, 16384, 10, 12, 16384, // 10,12 + 10, 13, 16384, 10, 13, 16384, 10, 13, 16384, 10, 13, 16384, // 10,13 + 10, 14, 16384, 10, 14, 16384, 10, 14, 16384, 10, 14, 16384, // 10,14 + 10, 15, 16384, 10, 15, 16384, 10, 15, 16384, 10, 15, 16384, // 10,15 + 11, 0, 16384, 11, 0, 16384, 11, 0, 16384, 11, 0, 16384, // 11, 0 + 11, 1, 16384, 11, 1, 16384, 11, 1, 16384, 11, 1, 16384, // 11, 1 + 11, 2, 16384, 11, 2, 16384, 11, 2, 16384, 11, 2, 16384, // 11, 2 + 11, 3, 16384, 11, 3, 16384, 11, 3, 16384, 11, 3, 16384, // 11, 3 + 11, 4, 16384, 11, 4, 16384, 11, 4, 16384, 11, 4, 16384, // 11, 4 + 11, 5, 16384, 11, 5, 16384, 11, 5, 16384, 11, 5, 16384, // 11, 5 + 11, 6, 16384, 11, 6, 16384, 11, 6, 16384, 11, 6, 16384, // 11, 6 + 11, 7, 16384, 11, 7, 16384, 11, 7, 16384, 11, 7, 16384, // 11, 7 + 11, 8, 16384, 11, 8, 16384, 11, 8, 16384, 11, 8, 16384, // 11, 8 + 11, 9, 16384, 11, 9, 16384, 11, 9, 16384, 11, 9, 16384, // 11, 9 + 11, 10, 16384, 11, 10, 16384, 11, 10, 16384, 11, 10, 16384, // 11,10 + 11, 11, 16384, 11, 11, 16384, 11, 11, 16384, 11, 11, 16384, // 11,11 + 11, 12, 16384, 11, 12, 16384, 11, 12, 16384, 11, 12, 16384, // 11,12 + 11, 13, 16384, 11, 13, 16384, 11, 13, 16384, 11, 13, 16384, // 11,13 + 11, 14, 16384, 11, 14, 16384, 11, 14, 16384, 11, 14, 16384, // 11,14 + 11, 15, 16384, 11, 15, 16384, 11, 15, 16384, 11, 15, 16384, // 11,15 + 12, 0, 16384, 12, 0, 16384, 12, 0, 16384, 12, 0, 16384, // 12, 0 + 12, 1, 16384, 12, 1, 16384, 12, 1, 16384, 12, 1, 16384, // 12, 1 + 12, 2, 16384, 12, 2, 16384, 12, 2, 16384, 12, 2, 16384, // 12, 2 + 12, 3, 16384, 12, 3, 16384, 12, 3, 16384, 12, 3, 16384, // 12, 3 + 12, 4, 16384, 12, 4, 16384, 12, 4, 16384, 12, 4, 16384, // 12, 4 + 12, 5, 16384, 12, 5, 16384, 12, 5, 16384, 12, 5, 16384, // 12, 5 + 12, 6, 16384, 12, 6, 16384, 12, 6, 16384, 12, 6, 16384, // 12, 6 + 12, 7, 16384, 12, 7, 16384, 12, 7, 16384, 12, 7, 16384, // 12, 7 + 12, 8, 16384, 12, 8, 16384, 12, 8, 16384, 12, 8, 16384, // 12, 8 + 12, 9, 16384, 12, 9, 16384, 12, 9, 16384, 12, 9, 16384, // 12, 9 + 12, 10, 16384, 12, 10, 16384, 12, 10, 16384, 12, 10, 16384, // 12,10 + 12, 11, 16384, 12, 11, 16384, 12, 11, 16384, 12, 11, 16384, // 12,11 + 12, 12, 16384, 12, 12, 16384, 12, 12, 16384, 12, 12, 16384, // 12,12 + 12, 13, 16384, 12, 13, 16384, 12, 13, 16384, 12, 13, 16384, // 12,13 + 12, 14, 16384, 12, 14, 16384, 12, 14, 16384, 12, 14, 16384, // 12,14 + 12, 15, 16384, 12, 15, 16384, 12, 15, 16384, 12, 15, 16384, // 12,15 + 13, 0, 16384, 13, 0, 16384, 13, 0, 16384, 13, 0, 16384, // 13, 0 + 13, 1, 16384, 13, 1, 16384, 13, 1, 16384, 13, 1, 16384, // 13, 1 + 13, 2, 16384, 13, 2, 16384, 13, 2, 16384, 13, 2, 16384, // 13, 2 + 13, 3, 16384, 13, 3, 16384, 13, 3, 16384, 13, 3, 16384, // 13, 3 + 13, 4, 16384, 13, 4, 16384, 13, 4, 16384, 13, 4, 16384, // 13, 4 + 13, 5, 16384, 13, 5, 16384, 13, 5, 16384, 13, 5, 16384, // 13, 5 + 13, 6, 16384, 13, 6, 16384, 13, 6, 16384, 13, 6, 16384, // 13, 6 + 13, 7, 16384, 13, 7, 16384, 13, 7, 16384, 13, 7, 16384, // 13, 7 + 13, 8, 16384, 13, 8, 16384, 13, 8, 16384, 13, 8, 16384, // 13, 8 + 13, 9, 16384, 13, 9, 16384, 13, 9, 16384, 13, 9, 16384, // 13, 9 + 13, 10, 16384, 13, 10, 16384, 13, 10, 16384, 13, 10, 16384, // 13,10 + 13, 11, 16384, 13, 11, 16384, 13, 11, 16384, 13, 11, 16384, // 13,11 + 13, 12, 16384, 13, 12, 16384, 13, 12, 16384, 13, 12, 16384, // 13,12 + 13, 13, 16384, 13, 13, 16384, 13, 13, 16384, 13, 13, 16384, // 13,13 + 13, 14, 16384, 13, 14, 16384, 13, 14, 16384, 13, 14, 16384, // 13,14 + 13, 15, 16384, 13, 15, 16384, 13, 15, 16384, 13, 15, 16384, // 13,15 + 14, 0, 16384, 14, 0, 16384, 14, 0, 16384, 14, 0, 16384, // 14, 0 + 14, 1, 16384, 14, 1, 16384, 14, 1, 16384, 14, 1, 16384, // 14, 1 + 14, 2, 16384, 14, 2, 16384, 14, 2, 16384, 14, 2, 16384, // 14, 2 + 14, 3, 16384, 14, 3, 16384, 14, 3, 16384, 14, 3, 16384, // 14, 3 + 14, 4, 16384, 14, 4, 16384, 14, 4, 16384, 14, 4, 16384, // 14, 4 + 14, 5, 16384, 14, 5, 16384, 14, 5, 16384, 14, 5, 16384, // 14, 5 + 14, 6, 16384, 14, 6, 16384, 14, 6, 16384, 14, 6, 16384, // 14, 6 + 14, 7, 16384, 14, 7, 16384, 14, 7, 16384, 14, 7, 16384, // 14, 7 + 14, 8, 16384, 14, 8, 16384, 14, 8, 16384, 14, 8, 16384, // 14, 8 + 14, 9, 16384, 14, 9, 16384, 14, 9, 16384, 14, 9, 16384, // 14, 9 + 14, 10, 16384, 14, 10, 16384, 14, 10, 16384, 14, 10, 16384, // 14,10 + 14, 11, 16384, 14, 11, 16384, 14, 11, 16384, 14, 11, 16384, // 14,11 + 14, 12, 16384, 14, 12, 16384, 14, 12, 16384, 14, 12, 16384, // 14,12 + 14, 13, 16384, 14, 13, 16384, 14, 13, 16384, 14, 13, 16384, // 14,13 + 14, 14, 16384, 14, 14, 16384, 14, 14, 16384, 14, 14, 16384, // 14,14 + 14, 15, 16384, 14, 15, 16384, 14, 15, 16384, 14, 15, 16384, // 14,15 + 15, 0, 16384, 15, 0, 16384, 15, 0, 16384, 15, 0, 16384, // 15, 0 + 15, 1, 16384, 15, 1, 16384, 15, 1, 16384, 15, 1, 16384, // 15, 1 + 15, 2, 16384, 15, 2, 16384, 15, 2, 16384, 15, 2, 16384, // 15, 2 + 15, 3, 16384, 15, 3, 16384, 15, 3, 16384, 15, 3, 16384, // 15, 3 + 15, 4, 16384, 15, 4, 16384, 15, 4, 16384, 15, 4, 16384, // 15, 4 + 15, 5, 16384, 15, 5, 16384, 15, 5, 16384, 15, 5, 16384, // 15, 5 + 15, 6, 16384, 15, 6, 16384, 15, 6, 16384, 15, 6, 16384, // 15, 6 + 15, 7, 16384, 15, 7, 16384, 15, 7, 16384, 15, 7, 16384, // 15, 7 + 15, 8, 16384, 15, 8, 16384, 15, 8, 16384, 15, 8, 16384, // 15, 8 + 15, 9, 16384, 15, 9, 16384, 15, 9, 16384, 15, 9, 16384, // 15, 9 + 15, 10, 16384, 15, 10, 16384, 15, 10, 16384, 15, 10, 16384, // 15,10 + 15, 11, 16384, 15, 11, 16384, 15, 11, 16384, 15, 11, 16384, // 15,11 + 15, 12, 16384, 15, 12, 16384, 15, 12, 16384, 15, 12, 16384, // 15,12 + 15, 13, 16384, 15, 13, 16384, 15, 13, 16384, 15, 13, 16384, // 15,13 + 15, 14, 16384, 15, 14, 16384, 15, 14, 16384, 15, 14, 16384, // 15,14 + 15, 15, 16384, 15, 15, 16384, 15, 15, 16384, 15, 15, 16384, // 15,15 + // angle of 0.5 degrees + 0, -1, 5106, 0, 0, 51699, 1, -1, 3621, 1, 0, 5110, // 0, 0 + 0, 0, 4851, 0, 1, 52457, 1, 0, 3422, 1, 1, 4806, // 0, 1 + 0, 1, 4610, 0, 2, 53168, 1, 1, 3235, 1, 2, 4523, // 0, 2 + 0, 2, 4390, 0, 3, 53814, 1, 2, 3065, 1, 3, 4267, // 0, 3 + 0, 3, 4200, 0, 4, 54376, 1, 3, 2917, 1, 4, 4043, // 0, 4 + 0, 4, 4046, 0, 5, 54833, 1, 4, 2797, 1, 5, 3860, // 0, 5 + 0, 5, 3939, 0, 6, 55164, 1, 5, 2709, 1, 6, 3724, // 0, 6 + 0, 6, 3885, 0, 7, 55352, 1, 6, 2659, 1, 7, 3640, // 0, 7 + -1, 7, 2659, -1, 8, 3638, 0, 7, 3885, 0, 8, 55354, // 0, 8 + -1, 8, 2709, -1, 9, 3722, 0, 8, 3940, 0, 9, 55165, // 0, 9 + -1, 9, 2796, -1, 10, 3858, 0, 9, 4047, 0, 10, 54835, // 0,10 + -1, 10, 2916, -1, 11, 4041, 0, 10, 4201, 0, 11, 54378, // 0,11 + -1, 11, 3064, -1, 12, 4264, 0, 11, 4392, 0, 12, 53816, // 0,12 + -1, 12, 3235, -1, 13, 4521, 0, 12, 4612, 0, 13, 53168, // 0,13 + -1, 13, 3421, -1, 14, 4803, 0, 13, 4854, 0, 14, 52458, // 0,14 + -1, 14, 3621, -1, 15, 5106, 0, 14, 5110, 0, 15, 51699, // 0,15 + 1, -1, 4803, 1, 0, 52457, 2, -1, 3421, 2, 0, 4855, // 1, 0 + 1, 0, 4522, 1, 1, 53285, 2, 0, 3204, 2, 1, 4525, // 1, 1 + 1, 1, 4253, 1, 2, 54071, 2, 1, 2998, 2, 2, 4214, // 1, 2 + 1, 2, 4003, 1, 3, 54796, 2, 2, 2808, 2, 3, 3929, // 1, 3 + 1, 3, 3783, 1, 4, 55434, 2, 3, 2640, 2, 4, 3679, // 1, 4 + 1, 4, 3604, 1, 5, 55958, 2, 4, 2503, 2, 5, 3471, // 1, 5 + 1, 5, 3476, 1, 6, 56339, 2, 5, 2403, 2, 6, 3318, // 1, 6 + 1, 6, 3411, 1, 7, 56552, 2, 6, 2346, 2, 7, 3227, // 1, 7 + 0, 7, 2346, 0, 8, 3225, 1, 7, 3411, 1, 8, 56554, // 1, 8 + 0, 8, 2402, 0, 9, 3317, 1, 8, 3477, 1, 9, 56340, // 1, 9 + 0, 9, 2502, 0, 10, 3470, 1, 9, 3605, 1, 10, 55959, // 1,10 + 0, 10, 2640, 0, 11, 3677, 1, 10, 3785, 1, 11, 55434, // 1,11 + 0, 11, 2808, 0, 12, 3927, 1, 11, 4005, 1, 12, 54796, // 1,12 + 0, 12, 2998, 0, 13, 4212, 1, 12, 4255, 1, 13, 54071, // 1,13 + 0, 13, 3204, 0, 14, 4522, 1, 13, 4525, 1, 14, 53285, // 1,14 + 0, 14, 3422, 0, 15, 4851, 1, 14, 4806, 1, 15, 52457, // 1,15 + 2, -1, 4521, 2, 0, 53168, 3, -1, 3235, 3, 0, 4612, // 2, 0 + 2, 0, 4212, 2, 1, 54072, 3, 0, 2998, 3, 1, 4254, // 2, 1 + 2, 1, 3911, 2, 2, 54941, 3, 1, 2770, 3, 2, 3914, // 2, 2 + 2, 2, 3628, 2, 3, 55756, 3, 2, 2557, 3, 3, 3595, // 2, 3 + 2, 3, 3373, 2, 4, 56486, 3, 3, 2365, 3, 4, 3312, // 2, 4 + 2, 4, 3161, 2, 5, 57095, 3, 4, 2205, 3, 5, 3075, // 2, 5 + 2, 5, 3007, 2, 6, 57544, 3, 5, 2088, 3, 6, 2897, // 2, 6 + 2, 6, 2926, 2, 7, 57793, 3, 6, 2022, 3, 7, 2795, // 2, 7 + 1, 7, 2022, 1, 8, 2794, 2, 7, 2926, 2, 8, 57794, // 2, 8 + 1, 8, 2088, 1, 9, 2897, 2, 8, 3007, 2, 9, 57544, // 2, 9 + 1, 9, 2205, 1, 10, 3073, 2, 9, 3161, 2, 10, 57097, // 2,10 + 1, 10, 2365, 1, 11, 3310, 2, 10, 3374, 2, 11, 56487, // 2,11 + 1, 11, 2556, 1, 12, 3594, 2, 11, 3630, 2, 12, 55756, // 2,12 + 1, 12, 2770, 1, 13, 3911, 2, 12, 3913, 2, 13, 54942, // 2,13 + 1, 13, 2998, 1, 14, 4253, 2, 13, 4214, 2, 14, 54071, // 2,14 + 1, 14, 3235, 1, 15, 4610, 2, 14, 4523, 2, 15, 53168, // 2,15 + 3, -1, 4264, 3, 0, 53815, 4, -1, 3064, 4, 0, 4393, // 3, 0 + 3, 0, 3927, 3, 1, 54796, 4, 0, 2808, 4, 1, 4005, // 3, 1 + 3, 1, 3594, 3, 2, 55756, 4, 1, 2556, 4, 2, 3630, // 3, 2 + 3, 2, 3273, 3, 3, 56673, 4, 2, 2317, 4, 3, 3273, // 3, 3 + 3, 3, 2976, 3, 4, 57514, 4, 3, 2096, 4, 4, 2950, // 3, 4 + 3, 4, 2722, 3, 5, 58233, 4, 4, 1908, 4, 5, 2673, // 3, 5 + 3, 5, 2532, 3, 6, 58774, 4, 5, 1767, 4, 6, 2463, // 3, 6 + 3, 6, 2430, 3, 7, 59076, 4, 6, 1687, 4, 7, 2343, // 3, 7 + 2, 7, 1687, 2, 8, 2342, 3, 7, 2430, 3, 8, 59077, // 3, 8 + 2, 8, 1766, 2, 9, 2463, 3, 8, 2532, 3, 9, 58775, // 3, 9 + 2, 9, 1908, 2, 10, 2672, 3, 9, 2723, 3, 10, 58233, // 3,10 + 2, 10, 2096, 2, 11, 2948, 3, 10, 2977, 3, 11, 57515, // 3,11 + 2, 11, 2317, 2, 12, 3273, 3, 11, 3274, 3, 12, 56672, // 3,12 + 2, 12, 2557, 2, 13, 3628, 3, 12, 3595, 3, 13, 55756, // 3,13 + 2, 13, 2808, 2, 14, 4003, 3, 13, 3929, 3, 14, 54796, // 3,14 + 2, 14, 3065, 2, 15, 4390, 3, 14, 4267, 3, 15, 53814, // 3,15 + 4, -1, 4041, 4, 0, 54378, 5, -1, 2916, 5, 0, 4201, // 4, 0 + 4, 0, 3677, 4, 1, 55435, 5, 0, 2640, 5, 1, 3784, // 4, 1 + 4, 1, 3310, 4, 2, 56487, 5, 1, 2365, 5, 2, 3374, // 4, 2 + 4, 2, 2948, 4, 3, 57514, 5, 2, 2096, 5, 3, 2978, // 4, 3 + 4, 3, 2604, 4, 4, 58484, 5, 3, 1843, 5, 4, 2605, // 4, 4 + 4, 4, 2297, 4, 5, 59345, 5, 4, 1617, 5, 5, 2277, // 4, 5 + 4, 5, 2057, 4, 6, 60017, 5, 5, 1442, 5, 6, 2020, // 4, 6 + 4, 6, 1922, 4, 7, 60402, 5, 6, 1341, 5, 7, 1871, // 4, 7 + 3, 7, 1341, 3, 8, 1871, 4, 7, 1922, 4, 8, 60402, // 4, 8 + 3, 8, 1442, 3, 9, 2020, 4, 8, 2057, 4, 9, 60017, // 4, 9 + 3, 9, 1617, 3, 10, 2276, 4, 9, 2297, 4, 10, 59346, // 4,10 + 3, 10, 1843, 3, 11, 2604, 4, 10, 2605, 4, 11, 58484, // 4,11 + 3, 11, 2096, 3, 12, 2976, 4, 11, 2950, 4, 12, 57514, // 4,12 + 3, 12, 2365, 3, 13, 3373, 4, 12, 3311, 4, 13, 56487, // 4,13 + 3, 13, 2640, 3, 14, 3783, 4, 13, 3678, 4, 14, 55435, // 4,14 + 3, 14, 2917, 3, 15, 4200, 4, 14, 4043, 4, 15, 54376, // 4,15 + 5, -1, 3858, 5, 0, 54835, 6, -1, 2796, 6, 0, 4047, // 5, 0 + 5, 0, 3470, 5, 1, 55959, 6, 0, 2502, 6, 1, 3605, // 5, 1 + 5, 1, 3073, 5, 2, 57096, 6, 1, 2205, 6, 2, 3162, // 5, 2 + 5, 2, 2672, 5, 3, 58234, 6, 2, 1908, 6, 3, 2722, // 5, 3 + 5, 3, 2276, 5, 4, 59346, 6, 3, 1617, 6, 4, 2297, // 5, 4 + 5, 4, 1904, 5, 5, 60381, 6, 4, 1347, 6, 5, 1904, // 5, 5 + 5, 5, 1593, 5, 6, 61243, 6, 5, 1121, 6, 6, 1579, // 5, 6 + 5, 6, 1405, 5, 7, 61767, 6, 6, 985, 6, 7, 1379, // 5, 7 + 4, 7, 985, 4, 8, 1380, 5, 7, 1405, 5, 8, 61766, // 5, 8 + 4, 8, 1121, 4, 9, 1578, 5, 8, 1593, 5, 9, 61244, // 5, 9 + 4, 9, 1347, 4, 10, 1904, 5, 9, 1904, 5, 10, 60381, // 5,10 + 4, 10, 1617, 4, 11, 2297, 5, 10, 2276, 5, 11, 59346, // 5,11 + 4, 11, 1908, 4, 12, 2722, 5, 11, 2673, 5, 12, 58233, // 5,12 + 4, 12, 2205, 4, 13, 3161, 5, 12, 3074, 5, 13, 57096, // 5,13 + 4, 13, 2503, 4, 14, 3604, 5, 13, 3472, 5, 14, 55957, // 5,14 + 4, 14, 2797, 4, 15, 4046, 5, 14, 3860, 5, 15, 54833, // 5,15 + 6, -1, 3722, 6, 0, 55166, 7, -1, 2709, 7, 0, 3939, // 6, 0 + 6, 0, 3317, 6, 1, 56340, 7, 0, 2402, 7, 1, 3477, // 6, 1 + 6, 1, 2897, 6, 2, 57545, 7, 1, 2088, 7, 2, 3006, // 6, 2 + 6, 2, 2463, 6, 3, 58775, 7, 2, 1766, 7, 3, 2532, // 6, 3 + 6, 3, 2020, 6, 4, 60018, 7, 3, 1442, 7, 4, 2056, // 6, 4 + 6, 4, 1578, 6, 5, 61243, 7, 4, 1121, 7, 5, 1594, // 6, 5 + 6, 5, 1170, 6, 6, 62369, 7, 5, 827, 7, 6, 1170, // 6, 6 + 6, 6, 883, 6, 7, 63156, 7, 6, 622, 7, 7, 875, // 6, 7 + 5, 7, 622, 5, 8, 875, 6, 7, 883, 6, 8, 63156, // 6, 8 + 5, 8, 827, 5, 9, 1170, 6, 8, 1170, 6, 9, 62369, // 6, 9 + 5, 9, 1121, 5, 10, 1593, 6, 9, 1579, 6, 10, 61243, // 6,10 + 5, 10, 1442, 5, 11, 2057, 6, 10, 2020, 6, 11, 60017, // 6,11 + 5, 11, 1767, 5, 12, 2532, 6, 11, 2464, 6, 12, 58773, // 6,12 + 5, 12, 2088, 5, 13, 3007, 6, 12, 2898, 6, 13, 57543, // 6,13 + 5, 13, 2403, 5, 14, 3476, 6, 13, 3319, 6, 14, 56338, // 6,14 + 5, 14, 2709, 5, 15, 3939, 6, 14, 3724, 6, 15, 55164, // 6,15 + 7, -1, 3638, 7, 0, 55354, 8, -1, 2659, 8, 0, 3885, // 7, 0 + 7, 0, 3225, 7, 1, 56554, 8, 0, 2346, 8, 1, 3411, // 7, 1 + 7, 1, 2794, 7, 2, 57795, 8, 1, 2022, 8, 2, 2925, // 7, 2 + 7, 2, 2342, 7, 3, 59077, 8, 2, 1687, 8, 3, 2430, // 7, 3 + 7, 3, 1871, 7, 4, 60402, 8, 3, 1341, 8, 4, 1922, // 7, 4 + 7, 4, 1380, 7, 5, 61767, 8, 4, 985, 8, 5, 1404, // 7, 5 + 7, 5, 875, 7, 6, 63156, 8, 5, 622, 8, 6, 883, // 7, 6 + 7, 6, 399, 7, 7, 64455, 8, 6, 282, 8, 7, 400, // 7, 7 + 6, 7, 282, 6, 8, 399, 7, 7, 399, 7, 8, 64456, // 7, 8 + 6, 8, 622, 6, 9, 883, 7, 8, 875, 7, 9, 63156, // 7, 9 + 6, 9, 985, 6, 10, 1405, 7, 9, 1380, 7, 10, 61766, // 7,10 + 6, 10, 1341, 6, 11, 1922, 7, 10, 1871, 7, 11, 60402, // 7,11 + 6, 11, 1687, 6, 12, 2430, 7, 11, 2343, 7, 12, 59076, // 7,12 + 6, 12, 2022, 6, 13, 2926, 7, 12, 2795, 7, 13, 57793, // 7,13 + 6, 13, 2346, 6, 14, 3411, 7, 13, 3227, 7, 14, 56552, // 7,14 + 6, 14, 2659, 6, 15, 3885, 7, 14, 3640, 7, 15, 55352, // 7,15 + 8, 0, 55352, 8, 1, 3640, 9, 0, 3885, 9, 1, 2659, // 8, 0 + 8, 1, 56552, 8, 2, 3227, 9, 1, 3411, 9, 2, 2346, // 8, 1 + 8, 2, 57793, 8, 3, 2795, 9, 2, 2926, 9, 3, 2022, // 8, 2 + 8, 3, 59076, 8, 4, 2343, 9, 3, 2430, 9, 4, 1687, // 8, 3 + 8, 4, 60402, 8, 5, 1871, 9, 4, 1922, 9, 5, 1341, // 8, 4 + 8, 5, 61767, 8, 6, 1380, 9, 5, 1405, 9, 6, 984, // 8, 5 + 8, 6, 63156, 8, 7, 875, 9, 6, 883, 9, 7, 622, // 8, 6 + 8, 7, 64455, 8, 8, 399, 9, 7, 399, 9, 8, 283, // 8, 7 + 7, 8, 399, 7, 9, 282, 8, 8, 64455, 8, 9, 400, // 8, 8 + 7, 9, 883, 7, 10, 622, 8, 9, 63156, 8, 10, 875, // 8, 9 + 7, 10, 1405, 7, 11, 985, 8, 10, 61767, 8, 11, 1379, // 8,10 + 7, 11, 1922, 7, 12, 1341, 8, 11, 60402, 8, 12, 1871, // 8,11 + 7, 12, 2430, 7, 13, 1687, 8, 12, 59077, 8, 13, 2342, // 8,12 + 7, 13, 2926, 7, 14, 2022, 8, 13, 57795, 8, 14, 2793, // 8,13 + 7, 14, 3411, 7, 15, 2346, 8, 14, 56554, 8, 15, 3225, // 8,14 + 7, 15, 3885, 7, 16, 2659, 8, 15, 55354, 8, 16, 3638, // 8,15 + 9, 0, 55164, 9, 1, 3724, 10, 0, 3939, 10, 1, 2709, // 9, 0 + 9, 1, 56339, 9, 2, 3319, 10, 1, 3476, 10, 2, 2402, // 9, 1 + 9, 2, 57544, 9, 3, 2898, 10, 2, 3007, 10, 3, 2087, // 9, 2 + 9, 3, 58774, 9, 4, 2464, 10, 3, 2532, 10, 4, 1766, // 9, 3 + 9, 4, 60017, 9, 5, 2020, 10, 4, 2057, 10, 5, 1442, // 9, 4 + 9, 5, 61243, 9, 6, 1579, 10, 5, 1593, 10, 6, 1121, // 9, 5 + 9, 6, 62369, 9, 7, 1170, 10, 6, 1170, 10, 7, 827, // 9, 6 + 9, 7, 63156, 9, 8, 883, 10, 7, 875, 10, 8, 622, // 9, 7 + 8, 8, 875, 8, 9, 622, 9, 8, 63156, 9, 9, 883, // 9, 8 + 8, 9, 1170, 8, 10, 827, 9, 9, 62369, 9, 10, 1170, // 9, 9 + 8, 10, 1593, 8, 11, 1121, 9, 10, 61243, 9, 11, 1579, // 9,10 + 8, 11, 2057, 8, 12, 1442, 9, 11, 60018, 9, 12, 2019, // 9,11 + 8, 12, 2532, 8, 13, 1766, 9, 12, 58775, 9, 13, 2463, // 9,12 + 8, 13, 3007, 8, 14, 2088, 9, 13, 57545, 9, 14, 2896, // 9,13 + 8, 14, 3477, 8, 15, 2402, 9, 14, 56340, 9, 15, 3317, // 9,14 + 8, 15, 3940, 8, 16, 2709, 9, 15, 55166, 9, 16, 3721, // 9,15 + 10, 0, 54833, 10, 1, 3860, 11, 0, 4046, 11, 1, 2797, // 10, 0 + 10, 1, 55958, 10, 2, 3472, 11, 1, 3604, 11, 2, 2502, // 10, 1 + 10, 2, 57095, 10, 3, 3074, 11, 2, 3161, 11, 3, 2206, // 10, 2 + 10, 3, 58233, 10, 4, 2673, 11, 3, 2722, 11, 4, 1908, // 10, 3 + 10, 4, 59345, 10, 5, 2276, 11, 4, 2297, 11, 5, 1618, // 10, 4 + 10, 5, 60381, 10, 6, 1904, 11, 5, 1904, 11, 6, 1347, // 10, 5 + 10, 6, 61243, 10, 7, 1593, 11, 6, 1578, 11, 7, 1122, // 10, 6 + 10, 7, 61767, 10, 8, 1405, 11, 7, 1380, 11, 8, 984, // 10, 7 + 9, 8, 1380, 9, 9, 985, 10, 8, 61767, 10, 9, 1404, // 10, 8 + 9, 9, 1579, 9, 10, 1121, 10, 9, 61243, 10, 10, 1593, // 10, 9 + 9, 10, 1904, 9, 11, 1347, 10, 10, 60381, 10, 11, 1904, // 10,10 + 9, 11, 2297, 9, 12, 1617, 10, 11, 59346, 10, 12, 2276, // 10,11 + 9, 12, 2723, 9, 13, 1908, 10, 12, 58234, 10, 13, 2671, // 10,12 + 9, 13, 3161, 9, 14, 2205, 10, 13, 57096, 10, 14, 3074, // 10,13 + 9, 14, 3605, 9, 15, 2502, 10, 14, 55959, 10, 15, 3470, // 10,14 + 9, 15, 4047, 9, 16, 2796, 10, 15, 54835, 10, 16, 3858, // 10,15 + 11, 0, 54376, 11, 1, 4043, 12, 0, 4200, 12, 1, 2917, // 11, 0 + 11, 1, 55434, 11, 2, 3678, 12, 1, 3783, 12, 2, 2641, // 11, 1 + 11, 2, 56486, 11, 3, 3311, 12, 2, 3373, 12, 3, 2366, // 11, 2 + 11, 3, 57514, 11, 4, 2950, 12, 3, 2976, 12, 4, 2096, // 11, 3 + 11, 4, 58484, 11, 5, 2605, 12, 4, 2604, 12, 5, 1843, // 11, 4 + 11, 5, 59346, 11, 6, 2297, 12, 5, 2276, 12, 6, 1617, // 11, 5 + 11, 6, 60018, 11, 7, 2057, 12, 6, 2020, 12, 7, 1441, // 11, 6 + 11, 7, 60402, 11, 8, 1922, 12, 7, 1871, 12, 8, 1341, // 11, 7 + 10, 8, 1871, 10, 9, 1341, 11, 8, 60402, 11, 9, 1922, // 11, 8 + 10, 9, 2020, 10, 10, 1442, 11, 9, 60017, 11, 10, 2057, // 11, 9 + 10, 10, 2276, 10, 11, 1617, 11, 10, 59345, 11, 11, 2298, // 11,10 + 10, 11, 2605, 10, 12, 1843, 11, 11, 58484, 11, 12, 2604, // 11,11 + 10, 12, 2977, 10, 13, 2096, 11, 12, 57514, 11, 13, 2949, // 11,12 + 10, 13, 3374, 10, 14, 2365, 11, 13, 56487, 11, 14, 3310, // 11,13 + 10, 14, 3785, 10, 15, 2640, 11, 14, 55435, 11, 15, 3676, // 11,14 + 10, 15, 4201, 10, 16, 2916, 11, 15, 54378, 11, 16, 4041, // 11,15 + 12, 0, 53814, 12, 1, 4267, 13, 0, 4390, 13, 1, 3065, // 12, 0 + 12, 1, 54796, 12, 2, 3929, 13, 1, 4003, 13, 2, 2808, // 12, 1 + 12, 2, 55756, 12, 3, 3595, 13, 2, 3628, 13, 3, 2557, // 12, 2 + 12, 3, 56673, 12, 4, 3274, 13, 3, 3273, 13, 4, 2316, // 12, 3 + 12, 4, 57514, 12, 5, 2977, 13, 4, 2948, 13, 5, 2097, // 12, 4 + 12, 5, 58234, 12, 6, 2723, 13, 5, 2672, 13, 6, 1907, // 12, 5 + 12, 6, 58775, 12, 7, 2532, 13, 6, 2463, 13, 7, 1766, // 12, 6 + 12, 7, 59077, 12, 8, 2430, 13, 7, 2342, 13, 8, 1687, // 12, 7 + 11, 8, 2343, 11, 9, 1687, 12, 8, 59076, 12, 9, 2430, // 12, 8 + 11, 9, 2464, 11, 10, 1767, 12, 9, 58774, 12, 10, 2531, // 12, 9 + 11, 10, 2673, 11, 11, 1908, 12, 10, 58233, 12, 11, 2722, // 12,10 + 11, 11, 2950, 11, 12, 2096, 12, 11, 57514, 12, 12, 2976, // 12,11 + 11, 12, 3274, 11, 13, 2317, 12, 12, 56673, 12, 13, 3272, // 12,12 + 11, 13, 3630, 11, 14, 2556, 12, 13, 55756, 12, 14, 3594, // 12,13 + 11, 14, 4005, 11, 15, 2808, 12, 14, 54796, 12, 15, 3927, // 12,14 + 11, 15, 4392, 11, 16, 3064, 12, 15, 53815, 12, 16, 4265, // 12,15 + 13, 0, 53168, 13, 1, 4523, 14, 0, 4610, 14, 1, 3235, // 13, 0 + 13, 1, 54071, 13, 2, 4214, 14, 1, 4253, 14, 2, 2998, // 13, 1 + 13, 2, 54941, 13, 3, 3913, 14, 2, 3911, 14, 3, 2771, // 13, 2 + 13, 3, 55756, 13, 4, 3630, 14, 3, 3594, 14, 4, 2556, // 13, 3 + 13, 4, 56487, 13, 5, 3374, 14, 4, 3310, 14, 5, 2365, // 13, 4 + 13, 5, 57096, 13, 6, 3161, 14, 5, 3073, 14, 6, 2206, // 13, 5 + 13, 6, 57545, 13, 7, 3007, 14, 6, 2897, 14, 7, 2087, // 13, 6 + 13, 7, 57795, 13, 8, 2926, 14, 7, 2794, 14, 8, 2021, // 13, 7 + 12, 8, 2795, 12, 9, 2022, 13, 8, 57793, 13, 9, 2926, // 13, 8 + 12, 9, 2898, 12, 10, 2088, 13, 9, 57544, 13, 10, 3006, // 13, 9 + 12, 10, 3074, 12, 11, 2205, 13, 10, 57095, 13, 11, 3162, // 13,10 + 12, 11, 3311, 12, 12, 2365, 13, 11, 56486, 13, 12, 3374, // 13,11 + 12, 12, 3595, 12, 13, 2557, 13, 12, 55756, 13, 13, 3628, // 13,12 + 12, 13, 3913, 12, 14, 2770, 13, 13, 54941, 13, 14, 3912, // 13,13 + 12, 14, 4255, 12, 15, 2998, 13, 14, 54072, 13, 15, 4211, // 13,14 + 12, 15, 4612, 12, 16, 3235, 13, 15, 53168, 13, 16, 4521, // 13,15 + 14, 0, 52457, 14, 1, 4806, 15, 0, 4851, 15, 1, 3422, // 14, 0 + 14, 1, 53285, 14, 2, 4525, 15, 1, 4522, 15, 2, 3204, // 14, 1 + 14, 2, 54072, 14, 3, 4255, 15, 2, 4212, 15, 3, 2997, // 14, 2 + 14, 3, 54796, 14, 4, 4005, 15, 3, 3927, 15, 4, 2808, // 14, 3 + 14, 4, 55435, 14, 5, 3785, 15, 4, 3677, 15, 5, 2639, // 14, 4 + 14, 5, 55959, 14, 6, 3605, 15, 5, 3470, 15, 6, 2502, // 14, 5 + 14, 6, 56340, 14, 7, 3477, 15, 6, 3317, 15, 7, 2402, // 14, 6 + 14, 7, 56554, 14, 8, 3411, 15, 7, 3225, 15, 8, 2346, // 14, 7 + 13, 8, 3227, 13, 9, 2346, 14, 8, 56552, 14, 9, 3411, // 14, 8 + 13, 9, 3319, 13, 10, 2403, 14, 9, 56339, 14, 10, 3475, // 14, 9 + 13, 10, 3472, 13, 11, 2503, 14, 10, 55958, 14, 11, 3603, // 14,10 + 13, 11, 3678, 13, 12, 2640, 14, 11, 55434, 14, 12, 3784, // 14,11 + 13, 12, 3929, 13, 13, 2808, 14, 12, 54796, 14, 13, 4003, // 14,12 + 13, 13, 4214, 13, 14, 2998, 14, 13, 54071, 14, 14, 4253, // 14,13 + 13, 14, 4525, 13, 15, 3204, 14, 14, 53285, 14, 15, 4522, // 14,14 + 13, 15, 4854, 13, 16, 3421, 14, 15, 52457, 14, 16, 4804, // 14,15 + 15, 0, 51699, 15, 1, 5110, 16, 0, 5106, 16, 1, 3621, // 15, 0 + 15, 1, 52457, 15, 2, 4854, 16, 1, 4803, 16, 2, 3422, // 15, 1 + 15, 2, 53168, 15, 3, 4612, 16, 2, 4521, 16, 3, 3235, // 15, 2 + 15, 3, 53815, 15, 4, 4392, 16, 3, 4264, 16, 4, 3065, // 15, 3 + 15, 4, 54378, 15, 5, 4201, 16, 4, 4041, 16, 5, 2916, // 15, 4 + 15, 5, 54835, 15, 6, 4047, 16, 5, 3858, 16, 6, 2796, // 15, 5 + 15, 6, 55166, 15, 7, 3940, 16, 6, 3722, 16, 7, 2708, // 15, 6 + 15, 7, 55354, 15, 8, 3885, 16, 7, 3638, 16, 8, 2659, // 15, 7 + 14, 8, 3640, 14, 9, 2659, 15, 8, 55352, 15, 9, 3885, // 15, 8 + 14, 9, 3724, 14, 10, 2709, 15, 9, 55164, 15, 10, 3939, // 15, 9 + 14, 10, 3860, 14, 11, 2797, 15, 10, 54833, 15, 11, 4046, // 15,10 + 14, 11, 4043, 14, 12, 2917, 15, 11, 54376, 15, 12, 4200, // 15,11 + 14, 12, 4267, 14, 13, 3065, 15, 12, 53814, 15, 13, 4390, // 15,12 + 14, 13, 4523, 14, 14, 3235, 15, 13, 53168, 15, 14, 4610, // 15,13 + 14, 14, 4806, 14, 15, 3422, 15, 14, 52457, 15, 15, 4851, // 15,14 + 14, 15, 5110, 14, 16, 3621, 15, 15, 51699, 15, 16, 5106, // 15,15 + // angle of 1.0 degrees + 0, -1, 8769, 0, 0, 41693, 1, -1, 6280, 1, 0, 8794, // 0, 0 + 0, 0, 8452, 0, 1, 42821, 1, 0, 5975, 1, 1, 8288, // 0, 1 + 0, 1, 8141, 0, 2, 43900, 1, 1, 5684, 1, 2, 7811, // 0, 2 + 0, 2, 7848, 0, 3, 44901, 1, 2, 5413, 1, 3, 7374, // 0, 3 + 0, 3, 7587, 0, 4, 45791, 1, 3, 5172, 1, 4, 6986, // 0, 4 + 0, 4, 7374, 0, 5, 46532, 1, 4, 4971, 1, 5, 6659, // 0, 5 + 0, 5, 7227, 0, 6, 47086, 1, 5, 4818, 1, 6, 6405, // 0, 6 + 0, 6, 7158, 0, 7, 47426, 1, 6, 4722, 1, 7, 6230, // 0, 7 + -1, 7, 4718, -1, 8, 6217, 0, 7, 7161, 0, 8, 47440, // 0, 8 + -1, 8, 4814, -1, 9, 6391, 0, 8, 7233, 0, 9, 47098, // 0, 9 + -1, 9, 4967, -1, 10, 6644, 0, 9, 7383, 0, 10, 46542, // 0,10 + -1, 10, 5169, -1, 11, 6970, 0, 10, 7599, 0, 11, 45798, // 0,11 + -1, 11, 5410, -1, 12, 7356, 0, 11, 7863, 0, 12, 44907, // 0,12 + -1, 12, 5682, -1, 13, 7791, 0, 12, 8159, 0, 13, 43904, // 0,13 + -1, 13, 5974, -1, 14, 8265, 0, 13, 8474, 0, 14, 42823, // 0,14 + -1, 14, 6280, -1, 15, 8769, 0, 14, 8795, 0, 15, 41692, // 0,15 + 1, -1, 8265, 1, 0, 42823, 2, -1, 5974, 2, 0, 8474, // 1, 0 + 1, 0, 7901, 1, 1, 44074, 2, 0, 5640, 2, 1, 7921, // 1, 1 + 1, 1, 7539, 1, 2, 45286, 2, 1, 5316, 2, 2, 7395, // 1, 2 + 1, 2, 7191, 1, 3, 46427, 2, 2, 5011, 2, 3, 6907, // 1, 3 + 1, 3, 6875, 1, 4, 47453, 2, 3, 4736, 2, 4, 6472, // 1, 4 + 1, 4, 6613, 1, 5, 48314, 2, 4, 4505, 2, 5, 6104, // 1, 5 + 1, 5, 6425, 1, 6, 48960, 2, 5, 4330, 2, 6, 5821, // 1, 6 + 1, 6, 6332, 1, 7, 49347, 2, 6, 4224, 2, 7, 5633, // 1, 7 + 0, 7, 4221, 0, 8, 5623, 1, 7, 6335, 1, 8, 49357, // 1, 8 + 0, 8, 4327, 0, 9, 5809, 1, 8, 6430, 1, 9, 48970, // 1, 9 + 0, 9, 4502, 0, 10, 6092, 1, 9, 6620, 1, 10, 48322, // 1,10 + 0, 10, 4734, 0, 11, 6458, 1, 10, 6886, 1, 11, 47458, // 1,11 + 0, 11, 5009, 0, 12, 6892, 1, 11, 7204, 1, 12, 46431, // 1,12 + 0, 12, 5315, 0, 13, 7378, 1, 12, 7555, 1, 13, 45288, // 1,13 + 0, 13, 5640, 0, 14, 7901, 1, 13, 7921, 1, 14, 44074, // 1,14 + 0, 14, 5975, 0, 15, 8452, 1, 14, 8288, 1, 15, 42821, // 1,15 + 2, -1, 7791, 2, 0, 43904, 3, -1, 5682, 3, 0, 8159, // 2, 0 + 2, 0, 7378, 2, 1, 45288, 3, 0, 5315, 3, 1, 7555, // 2, 1 + 2, 1, 6959, 2, 2, 46650, 3, 1, 4954, 3, 2, 6973, // 2, 2 + 2, 2, 6549, 2, 3, 47953, 3, 2, 4608, 3, 3, 6426, // 2, 3 + 2, 3, 6168, 2, 4, 49147, 3, 3, 4291, 3, 4, 5930, // 2, 4 + 2, 4, 5842, 2, 5, 50165, 3, 4, 4020, 3, 5, 5509, // 2, 5 + 2, 5, 5602, 2, 6, 50935, 3, 5, 3815, 3, 6, 5184, // 2, 6 + 2, 6, 5478, 2, 7, 51387, 3, 6, 3693, 3, 7, 4978, // 2, 7 + 1, 7, 3691, 1, 8, 4970, 2, 7, 5480, 2, 8, 51395, // 2, 8 + 1, 8, 3813, 1, 9, 5175, 2, 8, 5606, 2, 9, 50942, // 2, 9 + 1, 9, 4019, 1, 10, 5499, 2, 9, 5848, 2, 10, 50170, // 2,10 + 1, 10, 4290, 1, 11, 5920, 2, 10, 6176, 2, 11, 49150, // 2,11 + 1, 11, 4607, 1, 12, 6414, 2, 11, 6560, 2, 12, 47955, // 2,12 + 1, 12, 4954, 1, 13, 6959, 2, 12, 6973, 2, 13, 46650, // 2,13 + 1, 13, 5316, 1, 14, 7539, 2, 13, 7395, 2, 14, 45286, // 2,14 + 1, 14, 5684, 1, 15, 8141, 2, 14, 7812, 2, 15, 43899, // 2,15 + 3, -1, 7356, 3, 0, 44907, 4, -1, 5410, 4, 0, 7863, // 3, 0 + 3, 0, 6892, 3, 1, 46430, 4, 0, 5009, 4, 1, 7205, // 3, 1 + 3, 1, 6414, 3, 2, 47955, 4, 1, 4607, 4, 2, 6560, // 3, 2 + 3, 2, 5934, 3, 3, 49445, 4, 2, 4214, 4, 3, 5943, // 3, 3 + 3, 3, 5474, 3, 4, 50843, 4, 3, 3846, 4, 4, 5373, // 3, 4 + 3, 4, 5069, 3, 5, 52066, 4, 4, 3523, 4, 5, 4878, // 3, 5 + 3, 5, 4759, 3, 6, 53008, 4, 5, 3274, 4, 6, 4495, // 3, 6 + 3, 6, 4592, 3, 7, 53557, 4, 6, 3128, 4, 7, 4259, // 3, 7 + 2, 7, 3126, 2, 8, 4254, 3, 7, 4594, 3, 8, 53562, // 3, 8 + 2, 8, 3273, 2, 9, 4489, 3, 8, 4762, 3, 9, 53012, // 3, 9 + 2, 9, 3522, 2, 10, 4872, 3, 9, 5073, 3, 10, 52069, // 3,10 + 2, 10, 3845, 2, 11, 5365, 3, 10, 5481, 3, 11, 50845, // 3,11 + 2, 11, 4214, 2, 12, 5934, 3, 11, 5943, 3, 12, 49445, // 3,12 + 2, 12, 4608, 2, 13, 6549, 3, 12, 6426, 3, 13, 47953, // 3,13 + 2, 13, 5011, 2, 14, 7191, 3, 13, 6908, 3, 14, 46426, // 3,14 + 2, 14, 5413, 2, 15, 7848, 3, 14, 7374, 3, 15, 44901, // 3,15 + 4, -1, 6970, 4, 0, 45799, 5, -1, 5169, 5, 0, 7598, // 4, 0 + 4, 0, 6458, 4, 1, 47458, 5, 0, 4734, 5, 1, 6886, // 4, 1 + 4, 1, 5920, 4, 2, 49150, 5, 1, 4290, 5, 2, 6176, // 4, 2 + 4, 2, 5365, 4, 3, 50844, 5, 2, 3845, 5, 3, 5482, // 4, 3 + 4, 3, 4816, 4, 4, 52484, 5, 3, 3415, 5, 4, 4821, // 4, 4 + 4, 4, 4309, 4, 5, 53973, 5, 4, 3023, 5, 5, 4231, // 4, 5 + 4, 5, 3902, 4, 6, 55164, 5, 5, 2711, 5, 6, 3759, // 4, 6 + 4, 6, 3671, 4, 7, 55867, 5, 6, 2525, 5, 7, 3473, // 4, 7 + 3, 7, 2524, 3, 8, 3469, 4, 7, 3672, 4, 8, 55871, // 4, 8 + 3, 8, 2710, 3, 9, 3755, 4, 8, 3904, 4, 9, 55167, // 4, 9 + 3, 9, 3023, 3, 10, 4226, 4, 9, 4313, 4, 10, 53974, // 4,10 + 3, 10, 3415, 3, 11, 4816, 4, 10, 4822, 4, 11, 52483, // 4,11 + 3, 11, 3846, 3, 12, 5474, 4, 11, 5373, 4, 12, 50843, // 4,12 + 3, 12, 4291, 3, 13, 6168, 4, 12, 5930, 4, 13, 49147, // 4,13 + 3, 13, 4736, 3, 14, 6875, 4, 13, 6472, 4, 14, 47453, // 4,14 + 3, 14, 5172, 3, 15, 7587, 4, 14, 6986, 4, 15, 45791, // 4,15 + 5, -1, 6644, 5, 0, 46541, 6, -1, 4967, 6, 0, 7384, // 5, 0 + 5, 0, 6092, 5, 1, 48322, 6, 0, 4502, 6, 1, 6620, // 5, 1 + 5, 1, 5499, 5, 2, 50171, 6, 1, 4019, 6, 2, 5847, // 5, 2 + 5, 2, 4872, 5, 3, 52069, 6, 2, 3522, 6, 3, 5073, // 5, 3 + 5, 3, 4226, 5, 4, 53975, 6, 3, 3023, 6, 4, 4312, // 5, 4 + 5, 4, 3595, 5, 5, 55798, 6, 4, 2546, 6, 5, 3597, // 5, 5 + 5, 5, 3050, 5, 6, 57353, 6, 5, 2138, 6, 6, 2995, // 5, 6 + 5, 6, 2713, 5, 7, 58322, 6, 6, 1884, 6, 7, 2617, // 5, 7 + 4, 7, 1884, 4, 8, 2615, 5, 7, 2714, 5, 8, 58323, // 5, 8 + 4, 8, 2138, 4, 9, 2993, 5, 8, 3051, 5, 9, 57354, // 5, 9 + 4, 9, 2546, 4, 10, 3595, 5, 9, 3598, 5, 10, 55797, // 5,10 + 4, 10, 3023, 4, 11, 4309, 5, 10, 4230, 5, 11, 53974, // 5,11 + 4, 11, 3523, 4, 12, 5069, 5, 11, 4879, 5, 12, 52065, // 5,12 + 4, 12, 4020, 4, 13, 5842, 5, 12, 5508, 5, 13, 50166, // 5,13 + 4, 13, 4505, 4, 14, 6613, 5, 13, 6104, 5, 14, 48314, // 5,14 + 4, 14, 4971, 4, 15, 7374, 5, 14, 6659, 5, 15, 46532, // 5,15 + 6, -1, 6391, 6, 0, 47098, 7, -1, 4814, 7, 0, 7233, // 6, 0 + 6, 0, 5809, 6, 1, 48969, 7, 0, 4327, 7, 1, 6431, // 6, 1 + 6, 1, 5175, 6, 2, 50942, 7, 1, 3813, 7, 2, 5606, // 6, 2 + 6, 2, 4489, 6, 3, 53012, 7, 2, 3273, 7, 3, 4762, // 6, 3 + 6, 3, 3755, 6, 4, 55166, 7, 3, 2710, 7, 4, 3905, // 6, 4 + 6, 4, 2993, 6, 5, 57354, 7, 4, 2138, 7, 5, 3051, // 6, 5 + 6, 5, 2258, 6, 6, 59422, 7, 5, 1597, 7, 6, 2259, // 6, 6 + 6, 6, 1726, 6, 7, 60905, 7, 6, 1210, 7, 7, 1695, // 6, 7 + 5, 7, 1209, 5, 8, 1695, 6, 7, 1726, 6, 8, 60906, // 6, 8 + 5, 8, 1597, 5, 9, 2258, 6, 8, 2259, 6, 9, 59422, // 6, 9 + 5, 9, 2138, 5, 10, 3050, 6, 9, 2995, 6, 10, 57353, // 6,10 + 5, 10, 2711, 5, 11, 3902, 6, 10, 3759, 6, 11, 55164, // 6,11 + 5, 11, 3274, 5, 12, 4759, 6, 11, 4495, 6, 12, 53008, // 6,12 + 5, 12, 3815, 5, 13, 5602, 6, 12, 5184, 6, 13, 50935, // 6,13 + 5, 13, 4330, 5, 14, 6425, 6, 13, 5820, 6, 14, 48961, // 6,14 + 5, 14, 4818, 5, 15, 7227, 6, 14, 6405, 6, 15, 47086, // 6,15 + 7, -1, 6217, 7, 0, 47440, 8, -1, 4718, 8, 0, 7161, // 7, 0 + 7, 0, 5623, 7, 1, 49358, 8, 0, 4221, 8, 1, 6334, // 7, 1 + 7, 1, 4970, 7, 2, 51395, 8, 1, 3691, 8, 2, 5480, // 7, 2 + 7, 2, 4254, 7, 3, 53562, 8, 2, 3126, 8, 3, 4594, // 7, 3 + 7, 3, 3469, 7, 4, 55870, 8, 3, 2524, 8, 4, 3673, // 7, 4 + 7, 4, 2615, 7, 5, 58324, 8, 4, 1884, 8, 5, 2713, // 7, 5 + 7, 5, 1695, 7, 6, 60906, 8, 5, 1209, 8, 6, 1726, // 7, 6 + 7, 6, 789, 7, 7, 63399, 8, 6, 558, 8, 7, 790, // 7, 7 + 6, 7, 558, 6, 8, 789, 7, 7, 789, 7, 8, 63400, // 7, 8 + 6, 8, 1210, 6, 9, 1726, 7, 8, 1695, 7, 9, 60905, // 7, 9 + 6, 9, 1884, 6, 10, 2713, 7, 9, 2616, 7, 10, 58323, // 7,10 + 6, 10, 2525, 6, 11, 3671, 7, 10, 3473, 7, 11, 55867, // 7,11 + 6, 11, 3128, 6, 12, 4592, 7, 11, 4259, 7, 12, 53557, // 7,12 + 6, 12, 3693, 6, 13, 5478, 7, 12, 4978, 7, 13, 51387, // 7,13 + 6, 13, 4224, 6, 14, 6332, 7, 13, 5633, 7, 14, 49347, // 7,14 + 6, 14, 4722, 6, 15, 7158, 7, 14, 6230, 7, 15, 47426, // 7,15 + 8, 0, 47426, 8, 1, 6230, 9, 0, 7158, 9, 1, 4722, // 8, 0 + 8, 1, 49347, 8, 2, 5633, 9, 1, 6332, 9, 2, 4224, // 8, 1 + 8, 2, 51387, 8, 3, 4978, 9, 2, 5478, 9, 3, 3693, // 8, 2 + 8, 3, 53557, 8, 4, 4259, 9, 3, 4592, 9, 4, 3128, // 8, 3 + 8, 4, 55867, 8, 5, 3473, 9, 4, 3671, 9, 5, 2525, // 8, 4 + 8, 5, 58322, 8, 6, 2616, 9, 5, 2713, 9, 6, 1885, // 8, 5 + 8, 6, 60905, 8, 7, 1695, 9, 6, 1726, 9, 7, 1210, // 8, 6 + 8, 7, 63399, 8, 8, 789, 9, 7, 789, 9, 8, 559, // 8, 7 + 7, 8, 789, 7, 9, 558, 8, 8, 63399, 8, 9, 790, // 8, 8 + 7, 9, 1726, 7, 10, 1209, 8, 9, 60906, 8, 10, 1695, // 8, 9 + 7, 10, 2714, 7, 11, 1884, 8, 10, 58324, 8, 11, 2614, // 8,10 + 7, 11, 3672, 7, 12, 2524, 8, 11, 55870, 8, 12, 3470, // 8,11 + 7, 12, 4594, 7, 13, 3126, 8, 12, 53562, 8, 13, 4254, // 8,12 + 7, 13, 5480, 7, 14, 3691, 8, 13, 51395, 8, 14, 4970, // 8,13 + 7, 14, 6335, 7, 15, 4221, 8, 14, 49358, 8, 15, 5622, // 8,14 + 7, 15, 7161, 7, 16, 4718, 8, 15, 47440, 8, 16, 6217, // 8,15 + 9, 0, 47086, 9, 1, 6405, 10, 0, 7227, 10, 1, 4818, // 9, 0 + 9, 1, 48960, 9, 2, 5820, 10, 1, 6425, 10, 2, 4331, // 9, 1 + 9, 2, 50935, 9, 3, 5184, 10, 2, 5602, 10, 3, 3815, // 9, 2 + 9, 3, 53008, 9, 4, 4495, 10, 3, 4759, 10, 4, 3274, // 9, 3 + 9, 4, 55164, 9, 5, 3759, 10, 4, 3902, 10, 5, 2711, // 9, 4 + 9, 5, 57353, 9, 6, 2995, 10, 5, 3050, 10, 6, 2138, // 9, 5 + 9, 6, 59422, 9, 7, 2259, 10, 6, 2258, 10, 7, 1597, // 9, 6 + 9, 7, 60906, 9, 8, 1726, 10, 7, 1695, 10, 8, 1209, // 9, 7 + 8, 8, 1695, 8, 9, 1210, 9, 8, 60905, 9, 9, 1726, // 9, 8 + 8, 9, 2259, 8, 10, 1597, 9, 9, 59422, 9, 10, 2258, // 9, 9 + 8, 10, 3051, 8, 11, 2138, 9, 10, 57354, 9, 11, 2993, // 9,10 + 8, 11, 3904, 8, 12, 2710, 9, 11, 55166, 9, 12, 3756, // 9,11 + 8, 12, 4762, 8, 13, 3273, 9, 12, 53012, 9, 13, 4489, // 9,12 + 8, 13, 5606, 8, 14, 3813, 9, 13, 50942, 9, 14, 5175, // 9,13 + 8, 14, 6430, 8, 15, 4327, 9, 14, 48969, 9, 15, 5810, // 9,14 + 8, 15, 7233, 8, 16, 4814, 9, 15, 47098, 9, 16, 6391, // 9,15 + 10, 0, 46532, 10, 1, 6659, 11, 0, 7374, 11, 1, 4971, // 10, 0 + 10, 1, 48314, 10, 2, 6104, 11, 1, 6613, 11, 2, 4505, // 10, 1 + 10, 2, 50165, 10, 3, 5508, 11, 2, 5842, 11, 3, 4021, // 10, 2 + 10, 3, 52066, 10, 4, 4879, 11, 3, 5069, 11, 4, 3522, // 10, 3 + 10, 4, 53973, 10, 5, 4230, 11, 4, 4309, 11, 5, 3024, // 10, 4 + 10, 5, 55798, 10, 6, 3598, 11, 5, 3595, 11, 6, 2545, // 10, 5 + 10, 6, 57354, 10, 7, 3051, 11, 6, 2993, 11, 7, 2138, // 10, 6 + 10, 7, 58324, 10, 8, 2714, 11, 7, 2615, 11, 8, 1883, // 10, 7 + 9, 8, 2616, 9, 9, 1884, 10, 8, 58322, 10, 9, 2714, // 10, 8 + 9, 9, 2995, 9, 10, 2138, 10, 9, 57353, 10, 10, 3050, // 10, 9 + 9, 10, 3598, 9, 11, 2546, 10, 10, 55798, 10, 11, 3594, // 10,10 + 9, 11, 4313, 9, 12, 3023, 10, 11, 53975, 10, 12, 4225, // 10,11 + 9, 12, 5073, 9, 13, 3522, 10, 12, 52069, 10, 13, 4872, // 10,12 + 9, 13, 5848, 9, 14, 4019, 10, 13, 50171, 10, 14, 5498, // 10,13 + 9, 14, 6620, 9, 15, 4502, 10, 14, 48322, 10, 15, 6092, // 10,14 + 9, 15, 7383, 9, 16, 4967, 10, 15, 46541, 10, 16, 6645, // 10,15 + 11, 0, 45791, 11, 1, 6986, 12, 0, 7587, 12, 1, 5172, // 11, 0 + 11, 1, 47453, 11, 2, 6472, 12, 1, 6875, 12, 2, 4736, // 11, 1 + 11, 2, 49147, 11, 3, 5930, 12, 2, 6168, 12, 3, 4291, // 11, 2 + 11, 3, 50843, 11, 4, 5373, 12, 3, 5474, 12, 4, 3846, // 11, 3 + 11, 4, 52484, 11, 5, 4822, 12, 4, 4816, 12, 5, 3414, // 11, 4 + 11, 5, 53975, 11, 6, 4313, 12, 5, 4226, 12, 6, 3022, // 11, 5 + 11, 6, 55166, 11, 7, 3904, 12, 6, 3755, 12, 7, 2711, // 11, 6 + 11, 7, 55870, 11, 8, 3672, 12, 7, 3469, 12, 8, 2525, // 11, 7 + 10, 8, 3473, 10, 9, 2525, 11, 8, 55867, 11, 9, 3671, // 11, 8 + 10, 9, 3759, 10, 10, 2711, 11, 9, 55164, 11, 10, 3902, // 11, 9 + 10, 10, 4230, 10, 11, 3023, 11, 10, 53973, 11, 11, 4310, // 11,10 + 10, 11, 4822, 10, 12, 3415, 11, 11, 52484, 11, 12, 4815, // 11,11 + 10, 12, 5481, 10, 13, 3845, 11, 12, 50844, 11, 13, 5366, // 11,12 + 10, 13, 6176, 10, 14, 4290, 11, 13, 49150, 11, 14, 5920, // 11,13 + 10, 14, 6886, 10, 15, 4734, 11, 14, 47458, 11, 15, 6458, // 11,14 + 10, 15, 7599, 10, 16, 5169, 11, 15, 45799, 11, 16, 6969, // 11,15 + 12, 0, 44901, 12, 1, 7374, 13, 0, 7848, 13, 1, 5413, // 12, 0 + 12, 1, 46427, 12, 2, 6908, 13, 1, 7191, 13, 2, 5010, // 12, 1 + 12, 2, 47953, 12, 3, 6426, 13, 2, 6549, 13, 3, 4608, // 12, 2 + 12, 3, 49445, 12, 4, 5943, 13, 3, 5934, 13, 4, 4214, // 12, 3 + 12, 4, 50844, 12, 5, 5481, 13, 4, 5365, 13, 5, 3846, // 12, 4 + 12, 5, 52069, 12, 6, 5073, 13, 5, 4872, 13, 6, 3522, // 12, 5 + 12, 6, 53012, 12, 7, 4762, 13, 6, 4489, 13, 7, 3273, // 12, 6 + 12, 7, 53562, 12, 8, 4594, 13, 7, 4254, 13, 8, 3126, // 12, 7 + 11, 8, 4259, 11, 9, 3128, 12, 8, 53557, 12, 9, 4592, // 12, 8 + 11, 9, 4495, 11, 10, 3274, 12, 9, 53008, 12, 10, 4759, // 12, 9 + 11, 10, 4879, 11, 11, 3523, 12, 10, 52066, 12, 11, 5068, // 12,10 + 11, 11, 5373, 11, 12, 3846, 12, 11, 50843, 12, 12, 5474, // 12,11 + 11, 12, 5943, 11, 13, 4214, 12, 12, 49445, 12, 13, 5934, // 12,12 + 11, 13, 6560, 11, 14, 4607, 12, 13, 47955, 12, 14, 6414, // 12,13 + 11, 14, 7204, 11, 15, 5009, 12, 14, 46430, 12, 15, 6893, // 12,14 + 11, 15, 7863, 11, 16, 5410, 12, 15, 44907, 12, 16, 7356, // 12,15 + 13, 0, 43900, 13, 1, 7812, 14, 0, 8141, 14, 1, 5683, // 13, 0 + 13, 1, 45286, 13, 2, 7395, 14, 1, 7539, 14, 2, 5316, // 13, 1 + 13, 2, 46650, 13, 3, 6973, 14, 2, 6959, 14, 3, 4954, // 13, 2 + 13, 3, 47955, 13, 4, 6560, 14, 3, 6414, 14, 4, 4607, // 13, 3 + 13, 4, 49150, 13, 5, 6176, 14, 4, 5920, 14, 5, 4290, // 13, 4 + 13, 5, 50171, 13, 6, 5848, 14, 5, 5499, 14, 6, 4018, // 13, 5 + 13, 6, 50942, 13, 7, 5606, 14, 6, 5175, 14, 7, 3813, // 13, 6 + 13, 7, 51395, 13, 8, 5480, 14, 7, 4970, 14, 8, 3691, // 13, 7 + 12, 8, 4978, 12, 9, 3693, 13, 8, 51387, 13, 9, 5478, // 13, 8 + 12, 9, 5184, 12, 10, 3815, 13, 9, 50935, 13, 10, 5602, // 13, 9 + 12, 10, 5508, 12, 11, 4020, 13, 10, 50165, 13, 11, 5843, // 13,10 + 12, 11, 5930, 12, 12, 4291, 13, 11, 49147, 13, 12, 6168, // 13,11 + 12, 12, 6426, 12, 13, 4608, 13, 12, 47953, 13, 13, 6549, // 13,12 + 12, 13, 6973, 12, 14, 4954, 13, 13, 46650, 13, 14, 6959, // 13,13 + 12, 14, 7555, 12, 15, 5315, 13, 14, 45288, 13, 15, 7378, // 13,14 + 12, 15, 8159, 12, 16, 5682, 13, 15, 43904, 13, 16, 7791, // 13,15 + 14, 0, 42821, 14, 1, 8288, 15, 0, 8452, 15, 1, 5975, // 14, 0 + 14, 1, 44074, 14, 2, 7921, 15, 1, 7901, 15, 2, 5640, // 14, 1 + 14, 2, 45288, 14, 3, 7555, 15, 2, 7378, 15, 3, 5315, // 14, 2 + 14, 3, 46430, 14, 4, 7204, 15, 3, 6892, 15, 4, 5010, // 14, 3 + 14, 4, 47458, 14, 5, 6886, 15, 4, 6458, 15, 5, 4734, // 14, 4 + 14, 5, 48322, 14, 6, 6620, 15, 5, 6092, 15, 6, 4502, // 14, 5 + 14, 6, 48969, 14, 7, 6430, 15, 6, 5809, 15, 7, 4328, // 14, 6 + 14, 7, 49358, 14, 8, 6335, 15, 7, 5623, 15, 8, 4220, // 14, 7 + 13, 8, 5633, 13, 9, 4224, 14, 8, 49347, 14, 9, 6332, // 14, 8 + 13, 9, 5820, 13, 10, 4330, 14, 9, 48960, 14, 10, 6426, // 14, 9 + 13, 10, 6104, 13, 11, 4505, 14, 10, 48314, 14, 11, 6613, // 14,10 + 13, 11, 6472, 13, 12, 4736, 14, 11, 47453, 14, 12, 6875, // 14,11 + 13, 12, 6908, 13, 13, 5011, 14, 12, 46427, 14, 13, 7190, // 14,12 + 13, 13, 7395, 13, 14, 5316, 14, 13, 45286, 14, 14, 7539, // 14,13 + 13, 14, 7921, 13, 15, 5640, 14, 14, 44074, 14, 15, 7901, // 14,14 + 13, 15, 8474, 13, 16, 5974, 14, 15, 42823, 14, 16, 8265, // 14,15 + 15, 0, 41693, 15, 1, 8795, 16, 0, 8769, 16, 1, 6279, // 15, 0 + 15, 1, 42823, 15, 2, 8474, 16, 1, 8265, 16, 2, 5974, // 15, 1 + 15, 2, 43904, 15, 3, 8159, 16, 2, 7791, 16, 3, 5682, // 15, 2 + 15, 3, 44907, 15, 4, 7863, 16, 3, 7356, 16, 4, 5410, // 15, 3 + 15, 4, 45799, 15, 5, 7599, 16, 4, 6970, 16, 5, 5168, // 15, 4 + 15, 5, 46541, 15, 6, 7383, 16, 5, 6644, 16, 6, 4968, // 15, 5 + 15, 6, 47098, 15, 7, 7233, 16, 6, 6391, 16, 7, 4814, // 15, 6 + 15, 7, 47440, 15, 8, 7161, 16, 7, 6217, 16, 8, 4718, // 15, 7 + 14, 8, 6230, 14, 9, 4722, 15, 8, 47426, 15, 9, 7158, // 15, 8 + 14, 9, 6405, 14, 10, 4818, 15, 9, 47086, 15, 10, 7227, // 15, 9 + 14, 10, 6659, 14, 11, 4971, 15, 10, 46532, 15, 11, 7374, // 15,10 + 14, 11, 6986, 14, 12, 5172, 15, 11, 45791, 15, 12, 7587, // 15,11 + 14, 12, 7374, 14, 13, 5413, 15, 12, 44901, 15, 13, 7848, // 15,12 + 14, 13, 7812, 14, 14, 5684, 15, 13, 43900, 15, 14, 8140, // 15,13 + 14, 14, 8288, 14, 15, 5975, 15, 14, 42821, 15, 15, 8452, // 15,14 + 14, 15, 8795, 14, 16, 6280, 15, 15, 41693, 15, 16, 8768, // 15,15 + // angle of 1.5 degrees + 0, -1, 11440, 0, 0, 34212, 1, -1, 8358, 1, 0, 11526, // 0, 0 + 0, 0, 11192, 0, 1, 35502, 1, 0, 7987, 1, 1, 10855, // 0, 1 + 0, 1, 10930, 0, 2, 36756, 1, 1, 7626, 1, 2, 10224, // 0, 2 + 0, 2, 10670, 0, 3, 37939, 1, 2, 7285, 1, 3, 9642, // 0, 3 + 0, 3, 10430, 0, 4, 39009, 1, 3, 6975, 1, 4, 9122, // 0, 4 + 0, 4, 10232, 0, 5, 39918, 1, 4, 6710, 1, 5, 8676, // 0, 5 + 0, 5, 10100, 0, 6, 40618, 1, 5, 6502, 1, 6, 8316, // 0, 6 + 0, 6, 10052, 0, 7, 41072, 1, 6, 6360, 1, 7, 8052, // 0, 7 + -1, 7, 6346, -1, 8, 8018, 0, 7, 10066, 0, 8, 41106, // 0, 8 + -1, 8, 6489, -1, 9, 8278, 0, 8, 10123, 0, 9, 40646, // 0, 9 + -1, 9, 6699, -1, 10, 8632, 0, 9, 10265, 0, 10, 39940, // 0,10 + -1, 10, 6965, -1, 11, 9072, 0, 10, 10473, 0, 11, 39026, // 0,11 + -1, 11, 7276, -1, 12, 9585, 0, 11, 10723, 0, 12, 37952, // 0,12 + -1, 12, 7620, -1, 13, 10158, 0, 12, 10994, 0, 13, 36764, // 0,13 + -1, 13, 7983, -1, 14, 10780, 0, 13, 11267, 0, 14, 35506, // 0,14 + -1, 14, 8358, -1, 15, 11440, 0, 14, 11526, 0, 15, 34212, // 0,15 + 1, -1, 10780, 1, 0, 35506, 2, -1, 7983, 2, 0, 11267, // 1, 0 + 1, 0, 10467, 1, 1, 36959, 2, 0, 7579, 2, 1, 10531, // 1, 1 + 1, 1, 10133, 1, 2, 38390, 2, 1, 7179, 2, 2, 9834, // 1, 2 + 1, 2, 9796, 1, 3, 39759, 2, 2, 6797, 2, 3, 9184, // 1, 3 + 1, 3, 9478, 1, 4, 41013, 2, 3, 6447, 2, 4, 8598, // 1, 4 + 1, 4, 9206, 1, 5, 42087, 2, 4, 6145, 2, 5, 8098, // 1, 5 + 1, 5, 9014, 1, 6, 42913, 2, 5, 5910, 2, 6, 7699, // 1, 6 + 1, 6, 8929, 1, 7, 43433, 2, 6, 5756, 2, 7, 7418, // 1, 7 + 0, 7, 5745, 0, 8, 7390, 1, 7, 8939, 1, 8, 43462, // 1, 8 + 0, 8, 5900, 0, 9, 7667, 1, 8, 9032, 1, 9, 42937, // 1, 9 + 0, 9, 6137, 0, 10, 8061, 1, 9, 9233, 1, 10, 42105, // 1,10 + 0, 10, 6440, 0, 11, 8557, 1, 10, 9513, 1, 11, 41026, // 1,11 + 0, 11, 6792, 0, 12, 9135, 1, 11, 9841, 1, 12, 39768, // 1,12 + 0, 12, 7177, 0, 13, 9777, 1, 12, 10188, 1, 13, 38394, // 1,13 + 0, 13, 7579, 0, 14, 10467, 1, 13, 10532, 1, 14, 36958, // 1,14 + 0, 14, 7987, 0, 15, 11192, 1, 14, 10855, 1, 15, 35502, // 1,15 + 2, -1, 10158, 2, 0, 36764, 3, -1, 7620, 3, 0, 10994, // 2, 0 + 2, 0, 9777, 2, 1, 38394, 3, 0, 7177, 3, 1, 10188, // 2, 1 + 2, 1, 9366, 2, 2, 40025, 3, 1, 6732, 3, 2, 9413, // 2, 2 + 2, 2, 8941, 2, 3, 41614, 3, 2, 6299, 3, 3, 8682, // 2, 3 + 2, 3, 8530, 2, 4, 43096, 3, 3, 5895, 3, 4, 8015, // 2, 4 + 2, 4, 8167, 2, 5, 44386, 3, 4, 5543, 3, 5, 7440, // 2, 5 + 2, 5, 7899, 2, 6, 45383, 3, 5, 5268, 3, 6, 6986, // 2, 6 + 2, 6, 7766, 2, 7, 45995, 3, 6, 5095, 3, 7, 6680, // 2, 7 + 1, 7, 5087, 1, 8, 6658, 2, 7, 7773, 2, 8, 46018, // 2, 8 + 1, 8, 5261, 1, 9, 6961, 2, 8, 7913, 2, 9, 45401, // 2, 9 + 1, 9, 5537, 1, 10, 7411, 2, 9, 8189, 2, 10, 44399, // 2,10 + 1, 10, 5891, 1, 11, 7981, 2, 10, 8559, 2, 11, 43105, // 2,11 + 1, 11, 6297, 1, 12, 8641, 2, 11, 8979, 2, 12, 41619, // 2,12 + 1, 12, 6732, 1, 13, 9366, 2, 12, 9413, 2, 13, 40025, // 2,13 + 1, 13, 7179, 1, 14, 10133, 2, 13, 9834, 2, 14, 38390, // 2,14 + 1, 14, 7626, 1, 15, 10930, 2, 14, 10224, 2, 15, 36756, // 2,15 + 3, -1, 9585, 3, 0, 37951, 4, -1, 7276, 4, 0, 10724, // 3, 0 + 3, 0, 9135, 3, 1, 39767, 4, 0, 6792, 4, 1, 9842, // 3, 1 + 3, 1, 8641, 3, 2, 41618, 4, 1, 6297, 4, 2, 8980, // 3, 2 + 3, 2, 8120, 3, 3, 43461, 4, 2, 5804, 4, 3, 8151, // 3, 3 + 3, 3, 7598, 3, 4, 45224, 4, 3, 5331, 4, 4, 7383, // 3, 4 + 3, 4, 7121, 3, 5, 46798, 4, 4, 4909, 4, 5, 6708, // 3, 5 + 3, 5, 6750, 3, 6, 48037, 4, 5, 4576, 4, 6, 6173, // 3, 6 + 3, 6, 6552, 3, 7, 48785, 4, 6, 4372, 4, 7, 5827, // 3, 7 + 2, 7, 4366, 2, 8, 5811, 3, 7, 6558, 3, 8, 48801, // 3, 8 + 2, 8, 4572, 2, 9, 6154, 3, 8, 6761, 3, 9, 48049, // 3, 9 + 2, 9, 4906, 2, 10, 6685, 3, 9, 7138, 3, 10, 46807, // 3,10 + 2, 10, 5330, 2, 11, 7356, 3, 10, 7622, 3, 11, 45228, // 3,11 + 2, 11, 5804, 2, 12, 8120, 3, 11, 8151, 3, 12, 43461, // 3,12 + 2, 12, 6299, 2, 13, 8941, 3, 12, 8681, 3, 13, 41615, // 3,13 + 2, 13, 6797, 2, 14, 9796, 3, 13, 9184, 3, 14, 39759, // 3,14 + 2, 14, 7285, 2, 15, 10670, 3, 14, 9642, 3, 15, 37939, // 3,15 + 4, -1, 9072, 4, 0, 39026, 5, -1, 6965, 5, 0, 10473, // 4, 0 + 4, 0, 8557, 4, 1, 41026, 5, 0, 6440, 5, 1, 9513, // 4, 1 + 4, 1, 7981, 4, 2, 43105, 5, 1, 5891, 5, 2, 8559, // 4, 2 + 4, 2, 7356, 4, 3, 45229, 5, 2, 5330, 5, 3, 7621, // 4, 3 + 4, 3, 6708, 4, 4, 47328, 5, 3, 4774, 5, 4, 6726, // 4, 4 + 4, 4, 6086, 4, 5, 49275, 5, 4, 4258, 5, 5, 5917, // 4, 5 + 4, 5, 5573, 4, 6, 50865, 5, 5, 3837, 5, 6, 5261, // 4, 6 + 4, 6, 5280, 4, 7, 51832, 5, 6, 3579, 5, 7, 4845, // 4, 7 + 3, 7, 3575, 3, 8, 4835, 4, 7, 5283, 4, 8, 51843, // 4, 8 + 3, 8, 3834, 3, 9, 5248, 4, 8, 5581, 4, 9, 50873, // 4, 9 + 3, 9, 4257, 3, 10, 5901, 4, 9, 6099, 4, 10, 49279, // 4,10 + 3, 10, 4774, 3, 11, 6708, 4, 10, 6727, 4, 11, 47327, // 4,11 + 3, 11, 5331, 3, 12, 7598, 4, 11, 7382, 4, 12, 45225, // 4,12 + 3, 12, 5895, 3, 13, 8530, 4, 12, 8015, 4, 13, 43096, // 4,13 + 3, 13, 6447, 3, 14, 9478, 4, 13, 8599, 4, 14, 41012, // 4,14 + 3, 14, 6975, 3, 15, 10430, 4, 14, 9122, 4, 15, 39009, // 4,15 + 5, -1, 8632, 5, 0, 39940, 6, -1, 6699, 6, 0, 10265, // 5, 0 + 5, 0, 8061, 5, 1, 42105, 6, 0, 6137, 6, 1, 9233, // 5, 1 + 5, 1, 7411, 5, 2, 44399, 6, 1, 5537, 6, 2, 8189, // 5, 2 + 5, 2, 6685, 5, 3, 46806, 6, 2, 4906, 6, 3, 7139, // 5, 3 + 5, 3, 5901, 5, 4, 49279, 6, 3, 4257, 6, 4, 6099, // 5, 4 + 5, 4, 5103, 5, 5, 51700, 6, 4, 3621, 6, 5, 5112, // 5, 5 + 5, 5, 4388, 5, 6, 53813, 6, 5, 3065, 6, 6, 4270, // 5, 6 + 5, 6, 3938, 5, 7, 55162, 6, 6, 2710, 6, 7, 3726, // 5, 7 + 4, 7, 2708, 4, 8, 3720, 5, 7, 3940, 5, 8, 55168, // 5, 8 + 4, 8, 3064, 4, 9, 4262, 5, 8, 4394, 5, 9, 53816, // 5, 9 + 4, 9, 3621, 4, 10, 5103, 5, 9, 5113, 5, 10, 51699, // 5,10 + 4, 10, 4258, 4, 11, 6086, 5, 10, 5917, 5, 11, 49275, // 5,11 + 4, 11, 4909, 4, 12, 7121, 5, 11, 6707, 5, 12, 46799, // 5,12 + 4, 12, 5543, 4, 13, 8167, 5, 12, 7440, 5, 13, 44386, // 5,13 + 4, 13, 6145, 4, 14, 9206, 5, 13, 8098, 5, 14, 42087, // 5,14 + 4, 14, 6710, 4, 15, 10232, 5, 14, 8676, 5, 15, 39918, // 5,15 + 6, -1, 8278, 6, 0, 40646, 7, -1, 6489, 7, 0, 10123, // 6, 0 + 6, 0, 7667, 6, 1, 42936, 7, 0, 5900, 7, 1, 9033, // 6, 1 + 6, 1, 6961, 6, 2, 45401, 7, 1, 5261, 7, 2, 7913, // 6, 2 + 6, 2, 6154, 6, 3, 48049, 7, 2, 4572, 7, 3, 6761, // 6, 3 + 6, 3, 5248, 6, 4, 50873, 7, 3, 3834, 7, 4, 5581, // 6, 4 + 6, 4, 4262, 6, 5, 53816, 7, 4, 3064, 7, 5, 4394, // 6, 5 + 6, 5, 3271, 6, 6, 56673, 7, 5, 2316, 7, 6, 3276, // 6, 6 + 6, 6, 2532, 6, 7, 58773, 7, 6, 1767, 7, 7, 2464, // 6, 7 + 5, 7, 1766, 5, 8, 2462, 6, 7, 2533, 6, 8, 58775, // 6, 8 + 5, 8, 2316, 5, 9, 3271, 6, 8, 3275, 6, 9, 56674, // 6, 9 + 5, 9, 3065, 5, 10, 4388, 6, 9, 4269, 6, 10, 53814, // 6,10 + 5, 10, 3837, 5, 11, 5573, 6, 10, 5261, 6, 11, 50865, // 6,11 + 5, 11, 4576, 5, 12, 6750, 6, 11, 6173, 6, 12, 48037, // 6,12 + 5, 12, 5268, 5, 13, 7899, 6, 12, 6986, 6, 13, 45383, // 6,13 + 5, 13, 5910, 5, 14, 9014, 6, 13, 7699, 6, 14, 42913, // 6,14 + 5, 14, 6502, 5, 15, 10100, 6, 14, 8316, 6, 15, 40618, // 6,15 + 7, -1, 8018, 7, 0, 41106, 8, -1, 6346, 8, 0, 10066, // 7, 0 + 7, 0, 7390, 7, 1, 43461, 8, 0, 5745, 8, 1, 8940, // 7, 1 + 7, 1, 6658, 7, 2, 46017, 8, 1, 5087, 8, 2, 7774, // 7, 2 + 7, 2, 5811, 7, 3, 48801, 8, 2, 4366, 8, 3, 6558, // 7, 3 + 7, 3, 4835, 7, 4, 51842, 8, 3, 3575, 8, 4, 5284, // 7, 4 + 7, 4, 3720, 7, 5, 55168, 8, 4, 2708, 8, 5, 3940, // 7, 5 + 7, 5, 2462, 7, 6, 58775, 8, 5, 1766, 8, 6, 2533, // 7, 6 + 7, 6, 1170, 7, 7, 62369, 8, 6, 827, 8, 7, 1170, // 7, 7 + 6, 7, 827, 6, 8, 1170, 7, 7, 1170, 7, 8, 62369, // 7, 8 + 6, 8, 1767, 6, 9, 2532, 7, 8, 2464, 7, 9, 58773, // 7, 9 + 6, 9, 2710, 6, 10, 3938, 7, 9, 3726, 7, 10, 55162, // 7,10 + 6, 10, 3579, 6, 11, 5280, 7, 10, 4846, 7, 11, 51831, // 7,11 + 6, 11, 4372, 6, 12, 6552, 7, 11, 5827, 7, 12, 48785, // 7,12 + 6, 12, 5095, 6, 13, 7766, 7, 12, 6680, 7, 13, 45995, // 7,13 + 6, 13, 5756, 6, 14, 8929, 7, 13, 7418, 7, 14, 43433, // 7,14 + 6, 14, 6360, 6, 15, 10052, 7, 14, 8052, 7, 15, 41072, // 7,15 + 8, 0, 41072, 8, 1, 8052, 9, 0, 10052, 9, 1, 6360, // 8, 0 + 8, 1, 43433, 8, 2, 7418, 9, 1, 8929, 9, 2, 5756, // 8, 1 + 8, 2, 45995, 8, 3, 6680, 9, 2, 7766, 9, 3, 5095, // 8, 2 + 8, 3, 48785, 8, 4, 5827, 9, 3, 6552, 9, 4, 4372, // 8, 3 + 8, 4, 51832, 8, 5, 4846, 9, 4, 5280, 9, 5, 3578, // 8, 4 + 8, 5, 55162, 8, 6, 3726, 9, 5, 3938, 9, 6, 2710, // 8, 5 + 8, 6, 58773, 8, 7, 2464, 9, 6, 2532, 9, 7, 1767, // 8, 6 + 8, 7, 62369, 8, 8, 1170, 9, 7, 1170, 9, 8, 827, // 8, 7 + 7, 8, 1170, 7, 9, 827, 8, 8, 62369, 8, 9, 1170, // 8, 8 + 7, 9, 2533, 7, 10, 1766, 8, 9, 58775, 8, 10, 2462, // 8, 9 + 7, 10, 3940, 7, 11, 2708, 8, 10, 55168, 8, 11, 3720, // 8,10 + 7, 11, 5283, 7, 12, 3575, 8, 11, 51842, 8, 12, 4836, // 8,11 + 7, 12, 6558, 7, 13, 4366, 8, 12, 48801, 8, 13, 5811, // 8,12 + 7, 13, 7773, 7, 14, 5087, 8, 13, 46017, 8, 14, 6659, // 8,13 + 7, 14, 8939, 7, 15, 5745, 8, 14, 43461, 8, 15, 7391, // 8,14 + 7, 15, 10066, 7, 16, 6346, 8, 15, 41106, 8, 16, 8018, // 8,15 + 9, 0, 40618, 9, 1, 8316, 10, 0, 10100, 10, 1, 6502, // 9, 0 + 9, 1, 42913, 9, 2, 7699, 10, 1, 9014, 10, 2, 5910, // 9, 1 + 9, 2, 45383, 9, 3, 6986, 10, 2, 7899, 10, 3, 5268, // 9, 2 + 9, 3, 48037, 9, 4, 6173, 10, 3, 6750, 10, 4, 4576, // 9, 3 + 9, 4, 50865, 9, 5, 5261, 10, 4, 5573, 10, 5, 3837, // 9, 4 + 9, 5, 53813, 9, 6, 4269, 10, 5, 4388, 10, 6, 3066, // 9, 5 + 9, 6, 56673, 9, 7, 3275, 10, 6, 3271, 10, 7, 2317, // 9, 6 + 9, 7, 58775, 9, 8, 2533, 10, 7, 2462, 10, 8, 1766, // 9, 7 + 8, 8, 2464, 8, 9, 1767, 9, 8, 58773, 9, 9, 2532, // 9, 8 + 8, 9, 3275, 8, 10, 2316, 9, 9, 56673, 9, 10, 3272, // 9, 9 + 8, 10, 4394, 8, 11, 3064, 9, 10, 53816, 9, 11, 4262, // 9,10 + 8, 11, 5581, 8, 12, 3834, 9, 11, 50873, 9, 12, 5248, // 9,11 + 8, 12, 6761, 8, 13, 4572, 9, 12, 48049, 9, 13, 6154, // 9,12 + 8, 13, 7913, 8, 14, 5261, 9, 13, 45401, 9, 14, 6961, // 9,13 + 8, 14, 9032, 8, 15, 5900, 9, 14, 42936, 9, 15, 7668, // 9,14 + 8, 15, 10123, 8, 16, 6489, 9, 15, 40646, 9, 16, 8278, // 9,15 + 10, 0, 39918, 10, 1, 8676, 11, 0, 10232, 11, 1, 6710, // 10, 0 + 10, 1, 42087, 10, 2, 8098, 11, 1, 9206, 11, 2, 6145, // 10, 1 + 10, 2, 44386, 10, 3, 7440, 11, 2, 8167, 11, 3, 5543, // 10, 2 + 10, 3, 46798, 10, 4, 6707, 11, 3, 7121, 11, 4, 4910, // 10, 3 + 10, 4, 49275, 10, 5, 5917, 11, 4, 6086, 11, 5, 4258, // 10, 4 + 10, 5, 51700, 10, 6, 5113, 11, 5, 5103, 11, 6, 3620, // 10, 5 + 10, 6, 53816, 10, 7, 4394, 11, 6, 4262, 11, 7, 3064, // 10, 6 + 10, 7, 55168, 10, 8, 3940, 11, 7, 3720, 11, 8, 2708, // 10, 7 + 9, 8, 3726, 9, 9, 2710, 10, 8, 55162, 10, 9, 3938, // 10, 8 + 9, 9, 4269, 9, 10, 3065, 10, 9, 53813, 10, 10, 4389, // 10, 9 + 9, 10, 5113, 9, 11, 3621, 10, 10, 51700, 10, 11, 5102, // 10,10 + 9, 11, 6099, 9, 12, 4257, 10, 11, 49279, 10, 12, 5901, // 10,11 + 9, 12, 7138, 9, 13, 4906, 10, 12, 46806, 10, 13, 6686, // 10,12 + 9, 13, 8189, 9, 14, 5537, 10, 13, 44399, 10, 14, 7411, // 10,13 + 9, 14, 9233, 9, 15, 6137, 10, 14, 42105, 10, 15, 8061, // 10,14 + 9, 15, 10265, 9, 16, 6699, 10, 15, 39940, 10, 16, 8632, // 10,15 + 11, 0, 39009, 11, 1, 9122, 12, 0, 10430, 12, 1, 6975, // 11, 0 + 11, 1, 41013, 11, 2, 8599, 12, 1, 9478, 12, 2, 6446, // 11, 1 + 11, 2, 43096, 11, 3, 8015, 12, 2, 8530, 12, 3, 5895, // 11, 2 + 11, 3, 45224, 11, 4, 7382, 12, 3, 7598, 12, 4, 5332, // 11, 3 + 11, 4, 47328, 11, 5, 6727, 12, 4, 6708, 12, 5, 4773, // 11, 4 + 11, 5, 49279, 11, 6, 6099, 12, 5, 5901, 12, 6, 4257, // 11, 5 + 11, 6, 50873, 11, 7, 5581, 12, 6, 5248, 12, 7, 3834, // 11, 6 + 11, 7, 51842, 11, 8, 5283, 12, 7, 4835, 12, 8, 3576, // 11, 7 + 10, 8, 4846, 10, 9, 3579, 11, 8, 51832, 11, 9, 5279, // 11, 8 + 10, 9, 5261, 10, 10, 3837, 11, 9, 50865, 11, 10, 5573, // 11, 9 + 10, 10, 5917, 10, 11, 4258, 11, 10, 49275, 11, 11, 6086, // 11,10 + 10, 11, 6727, 10, 12, 4774, 11, 11, 47328, 11, 12, 6707, // 11,11 + 10, 12, 7622, 10, 13, 5330, 11, 12, 45229, 11, 13, 7355, // 11,12 + 10, 13, 8559, 10, 14, 5891, 11, 13, 43105, 11, 14, 7981, // 11,13 + 10, 14, 9513, 10, 15, 6440, 11, 14, 41026, 11, 15, 8557, // 11,14 + 10, 15, 10473, 10, 16, 6965, 11, 15, 39026, 11, 16, 9072, // 11,15 + 12, 0, 37939, 12, 1, 9642, 13, 0, 10670, 13, 1, 7285, // 12, 0 + 12, 1, 39759, 12, 2, 9184, 13, 1, 9796, 13, 2, 6797, // 12, 1 + 12, 2, 41614, 12, 3, 8681, 13, 2, 8941, 13, 3, 6300, // 12, 2 + 12, 3, 43461, 12, 4, 8151, 13, 3, 8120, 13, 4, 5804, // 12, 3 + 12, 4, 45229, 12, 5, 7622, 13, 4, 7356, 13, 5, 5329, // 12, 4 + 12, 5, 46806, 12, 6, 7138, 13, 5, 6685, 13, 6, 4907, // 12, 5 + 12, 6, 48049, 12, 7, 6761, 13, 6, 6154, 13, 7, 4572, // 12, 6 + 12, 7, 48801, 12, 8, 6558, 13, 7, 5811, 13, 8, 4366, // 12, 7 + 11, 8, 5827, 11, 9, 4372, 12, 8, 48785, 12, 9, 6552, // 12, 8 + 11, 9, 6173, 11, 10, 4576, 12, 9, 48037, 12, 10, 6750, // 12, 9 + 11, 10, 6707, 11, 11, 4909, 12, 10, 46798, 12, 11, 7122, // 12,10 + 11, 11, 7382, 11, 12, 5331, 12, 11, 45224, 12, 12, 7599, // 12,11 + 11, 12, 8151, 11, 13, 5804, 12, 12, 43461, 12, 13, 8120, // 12,12 + 11, 13, 8979, 11, 14, 6297, 12, 13, 41618, 12, 14, 8642, // 12,13 + 11, 14, 9841, 11, 15, 6792, 12, 14, 39767, 12, 15, 9136, // 12,14 + 11, 15, 10723, 11, 16, 7276, 12, 15, 37951, 12, 16, 9586, // 12,15 + 13, 0, 36756, 13, 1, 10224, 14, 0, 10930, 14, 1, 7626, // 13, 0 + 13, 1, 38390, 13, 2, 9834, 14, 1, 10133, 14, 2, 7179, // 13, 1 + 13, 2, 40025, 13, 3, 9413, 14, 2, 9366, 14, 3, 6732, // 13, 2 + 13, 3, 41618, 13, 4, 8979, 14, 3, 8641, 14, 4, 6298, // 13, 3 + 13, 4, 43105, 13, 5, 8559, 14, 4, 7981, 14, 5, 5891, // 13, 4 + 13, 5, 44399, 13, 6, 8189, 14, 5, 7411, 14, 6, 5537, // 13, 5 + 13, 6, 45401, 13, 7, 7913, 14, 6, 6961, 14, 7, 5261, // 13, 6 + 13, 7, 46017, 13, 8, 7773, 14, 7, 6658, 14, 8, 5088, // 13, 7 + 12, 8, 6680, 12, 9, 5095, 13, 8, 45995, 13, 9, 7766, // 13, 8 + 12, 9, 6986, 12, 10, 5268, 13, 9, 45383, 13, 10, 7899, // 13, 9 + 12, 10, 7440, 12, 11, 5543, 13, 10, 44386, 13, 11, 8167, // 13,10 + 12, 11, 8015, 12, 12, 5895, 13, 11, 43096, 13, 12, 8530, // 13,11 + 12, 12, 8681, 12, 13, 6299, 13, 12, 41614, 13, 13, 8942, // 13,12 + 12, 13, 9413, 12, 14, 6732, 13, 13, 40025, 13, 14, 9366, // 13,13 + 12, 14, 10188, 12, 15, 7177, 13, 14, 38394, 13, 15, 9777, // 13,14 + 12, 15, 10994, 12, 16, 7620, 13, 15, 36764, 13, 16, 10158, // 13,15 + 14, 0, 35502, 14, 1, 10855, 15, 0, 11192, 15, 1, 7987, // 14, 0 + 14, 1, 36959, 14, 2, 10532, 15, 1, 10467, 15, 2, 7578, // 14, 1 + 14, 2, 38394, 14, 3, 10188, 15, 2, 9777, 15, 3, 7177, // 14, 2 + 14, 3, 39767, 14, 4, 9841, 15, 3, 9135, 15, 4, 6793, // 14, 3 + 14, 4, 41026, 14, 5, 9513, 15, 4, 8557, 15, 5, 6440, // 14, 4 + 14, 5, 42105, 14, 6, 9233, 15, 5, 8061, 15, 6, 6137, // 14, 5 + 14, 6, 42936, 14, 7, 9032, 15, 6, 7667, 15, 7, 5901, // 14, 6 + 14, 7, 43461, 14, 8, 8939, 15, 7, 7390, 15, 8, 5746, // 14, 7 + 13, 8, 7418, 13, 9, 5756, 14, 8, 43433, 14, 9, 8929, // 14, 8 + 13, 9, 7699, 13, 10, 5910, 14, 9, 42913, 14, 10, 9014, // 14, 9 + 13, 10, 8098, 13, 11, 6145, 14, 10, 42087, 14, 11, 9206, // 14,10 + 13, 11, 8599, 13, 12, 6447, 14, 11, 41013, 14, 12, 9477, // 14,11 + 13, 12, 9184, 13, 13, 6797, 14, 12, 39759, 14, 13, 9796, // 14,12 + 13, 13, 9834, 13, 14, 7179, 14, 13, 38390, 14, 14, 10133, // 14,13 + 13, 14, 10532, 13, 15, 7579, 14, 14, 36959, 14, 15, 10466, // 14,14 + 13, 15, 11267, 13, 16, 7983, 14, 15, 35506, 14, 16, 10780, // 14,15 + 15, 0, 34212, 15, 1, 11526, 16, 0, 11440, 16, 1, 8358, // 15, 0 + 15, 1, 35506, 15, 2, 11267, 16, 1, 10780, 16, 2, 7983, // 15, 1 + 15, 2, 36764, 15, 3, 10994, 16, 2, 10158, 16, 3, 7620, // 15, 2 + 15, 3, 37951, 15, 4, 10723, 16, 3, 9585, 16, 4, 7277, // 15, 3 + 15, 4, 39026, 15, 5, 10473, 16, 4, 9072, 16, 5, 6965, // 15, 4 + 15, 5, 39940, 15, 6, 10265, 16, 5, 8632, 16, 6, 6699, // 15, 5 + 15, 6, 40646, 15, 7, 10123, 16, 6, 8278, 16, 7, 6489, // 15, 6 + 15, 7, 41106, 15, 8, 10066, 16, 7, 8018, 16, 8, 6346, // 15, 7 + 14, 8, 8052, 14, 9, 6360, 15, 8, 41072, 15, 9, 10052, // 15, 8 + 14, 9, 8316, 14, 10, 6502, 15, 9, 40618, 15, 10, 10100, // 15, 9 + 14, 10, 8676, 14, 11, 6710, 15, 10, 39918, 15, 11, 10232, // 15,10 + 14, 11, 9122, 14, 12, 6975, 15, 11, 39009, 15, 12, 10430, // 15,11 + 14, 12, 9642, 14, 13, 7285, 15, 12, 37939, 15, 13, 10670, // 15,12 + 14, 13, 10224, 14, 14, 7626, 15, 13, 36756, 15, 14, 10930, // 15,13 + 14, 14, 10855, 14, 15, 7987, 15, 14, 35502, 15, 15, 11192, // 15,14 + 14, 15, 11526, 14, 16, 8358, 15, 15, 34212, 15, 16, 11440, // 15,15 + // angle of 2.0 degrees + 0, -1, 13368, 0, 0, 28495, 1, -1, 10104, 1, 0, 13569, // 0, 0 + 0, 0, 13291, 0, 1, 29828, 1, 0, 9671, 1, 1, 12746, // 0, 1 + 0, 1, 13176, 0, 2, 31138, 1, 1, 9245, 1, 2, 11977, // 0, 2 + 0, 2, 13038, 0, 3, 32391, 1, 2, 8838, 1, 3, 11269, // 0, 3 + 0, 3, 12899, 0, 4, 33539, 1, 3, 8463, 1, 4, 10635, // 0, 4 + 0, 4, 12783, 0, 5, 34532, 1, 4, 8135, 1, 5, 10086, // 0, 5 + 0, 5, 12717, 0, 6, 35315, 1, 5, 7868, 1, 6, 9636, // 0, 6 + 0, 6, 12728, 0, 7, 35844, 1, 6, 7674, 1, 7, 9290, // 0, 7 + -1, 7, 7643, -1, 8, 9224, 0, 7, 12764, 0, 8, 35905, // 0, 8 + -1, 8, 7839, -1, 9, 9558, 0, 8, 12777, 0, 9, 35362, // 0, 9 + -1, 9, 8107, -1, 10, 9995, 0, 9, 12867, 0, 10, 34567, // 0,10 + -1, 10, 8438, -1, 11, 10528, 0, 10, 13007, 0, 11, 33563, // 0,11 + -1, 11, 8816, -1, 12, 11143, 0, 11, 13171, 0, 12, 32406, // 0,12 + -1, 12, 9229, -1, 13, 11829, 0, 12, 13332, 0, 13, 31146, // 0,13 + -1, 13, 9662, -1, 14, 12574, 0, 13, 13470, 0, 14, 29830, // 0,14 + -1, 14, 10104, -1, 15, 13368, 0, 14, 13569, 0, 15, 28495, // 0,15 + 1, -1, 12574, 1, 0, 29831, 2, -1, 9662, 2, 0, 13469, // 1, 0 + 1, 0, 12412, 1, 1, 31358, 2, 0, 9202, 2, 1, 12564, // 1, 1 + 1, 1, 12203, 1, 2, 32881, 2, 1, 8742, 2, 2, 11710, // 1, 2 + 1, 2, 11964, 1, 3, 34358, 2, 2, 8296, 2, 3, 10918, // 1, 3 + 1, 3, 11721, 1, 4, 35730, 2, 3, 7881, 2, 4, 10204, // 1, 4 + 1, 4, 11507, 1, 5, 36926, 2, 4, 7517, 2, 5, 9586, // 1, 5 + 1, 5, 11360, 1, 6, 37866, 2, 5, 7224, 2, 6, 9086, // 1, 6 + 1, 6, 11317, 1, 7, 38481, 2, 6, 7020, 2, 7, 8718, // 1, 7 + 0, 7, 6997, 0, 8, 8662, 1, 7, 11344, 1, 8, 38533, // 1, 8 + 0, 8, 7202, 0, 9, 9020, 1, 8, 11407, 1, 9, 37907, // 1, 9 + 0, 9, 7497, 0, 10, 9509, 1, 9, 11575, 1, 10, 36955, // 1,10 + 0, 10, 7865, 0, 11, 10111, 1, 10, 11810, 1, 11, 35750, // 1,11 + 0, 11, 8284, 0, 12, 10808, 1, 11, 12074, 1, 12, 34370, // 1,12 + 0, 12, 8735, 0, 13, 11580, 1, 12, 12334, 1, 13, 32887, // 1,13 + 0, 13, 9202, 0, 14, 12412, 1, 13, 12564, 1, 14, 31358, // 1,14 + 0, 14, 9671, 0, 15, 13291, 1, 14, 12746, 1, 15, 29828, // 1,15 + 2, -1, 11829, 2, 0, 31146, 3, -1, 9229, 3, 0, 13332, // 2, 0 + 2, 0, 11580, 2, 1, 32886, 3, 0, 8735, 3, 1, 12335, // 2, 1 + 2, 1, 11272, 2, 2, 34650, 3, 1, 8232, 3, 2, 11382, // 2, 2 + 2, 2, 10922, 2, 3, 36392, 3, 2, 7734, 3, 3, 10488, // 2, 3 + 2, 3, 10559, 2, 4, 38042, 3, 3, 7261, 3, 4, 9674, // 2, 4 + 2, 4, 10226, 2, 5, 39503, 3, 4, 6842, 3, 5, 8965, // 2, 5 + 2, 5, 9977, 2, 6, 40656, 3, 5, 6506, 3, 6, 8397, // 2, 6 + 2, 6, 9867, 2, 7, 41389, 3, 6, 6284, 3, 7, 7996, // 2, 7 + 1, 7, 6266, 1, 8, 7951, 2, 7, 9886, 2, 8, 41433, // 2, 8 + 1, 8, 6491, 1, 9, 8344, 2, 8, 10013, 2, 9, 40688, // 2, 9 + 1, 9, 6829, 1, 10, 8902, 2, 9, 10279, 2, 10, 39526, // 2,10 + 1, 10, 7252, 1, 11, 9597, 2, 10, 10630, 2, 11, 38057, // 2,11 + 1, 11, 7728, 1, 12, 10397, 2, 11, 11012, 2, 12, 36399, // 2,12 + 1, 12, 8232, 1, 13, 11272, 2, 12, 11382, 2, 13, 34650, // 2,13 + 1, 13, 8742, 1, 14, 12203, 2, 13, 11709, 2, 14, 32882, // 2,14 + 1, 14, 9245, 1, 15, 13176, 2, 14, 11977, 2, 15, 31138, // 2,15 + 3, -1, 11143, 3, 0, 32406, 4, -1, 8816, 4, 0, 13171, // 3, 0 + 3, 0, 10808, 3, 1, 34369, 4, 0, 8284, 4, 1, 12075, // 3, 1 + 3, 1, 10397, 3, 2, 36399, 4, 1, 7728, 4, 2, 11012, // 3, 2 + 3, 2, 9924, 3, 3, 38450, 4, 2, 7164, 4, 3, 9998, // 3, 3 + 3, 3, 9421, 3, 4, 40444, 4, 3, 6615, 4, 4, 9056, // 3, 4 + 3, 4, 8940, 3, 5, 42256, 4, 4, 6116, 4, 5, 8224, // 3, 5 + 3, 5, 8558, 3, 6, 43710, 4, 5, 5712, 4, 6, 7556, // 3, 6 + 3, 6, 8359, 3, 7, 44616, 4, 6, 5454, 4, 7, 7107, // 3, 7 + 2, 7, 5443, 2, 8, 7072, 3, 7, 8373, 3, 8, 44648, // 3, 8 + 2, 8, 5703, 2, 9, 7516, 3, 8, 8584, 3, 9, 43733, // 3, 9 + 2, 9, 6108, 2, 10, 8175, 3, 9, 8982, 3, 10, 42271, // 3,10 + 2, 10, 6611, 2, 11, 8995, 3, 10, 9478, 3, 11, 40452, // 3,11 + 2, 11, 7164, 2, 12, 9924, 3, 11, 9998, 3, 12, 38450, // 3,12 + 2, 12, 7734, 2, 13, 10922, 3, 12, 10488, 3, 13, 36392, // 3,13 + 2, 13, 8296, 2, 14, 11964, 3, 13, 10918, 3, 14, 34358, // 3,14 + 2, 14, 8838, 2, 15, 13038, 3, 14, 11269, 3, 15, 32391, // 3,15 + 4, -1, 10528, 4, 0, 33564, 5, -1, 8438, 5, 0, 13006, // 4, 0 + 4, 0, 10111, 4, 1, 35750, 5, 0, 7865, 5, 1, 11810, // 4, 1 + 4, 1, 9597, 4, 2, 38057, 5, 1, 7252, 5, 2, 10630, // 4, 2 + 4, 2, 8995, 4, 3, 40452, 5, 2, 6611, 5, 3, 9478, // 4, 3 + 4, 3, 8332, 4, 4, 42861, 5, 3, 5965, 5, 4, 8378, // 4, 4 + 4, 4, 7667, 4, 5, 45139, 5, 4, 5353, 5, 5, 7377, // 4, 5 + 4, 5, 7100, 4, 6, 47035, 5, 5, 4843, 5, 6, 6558, // 4, 6 + 4, 6, 6774, 4, 7, 48218, 5, 6, 4521, 5, 7, 6023, // 4, 7 + 3, 7, 4513, 3, 8, 6000, 4, 7, 6783, 4, 8, 48240, // 4, 8 + 3, 8, 4838, 3, 9, 6530, 4, 8, 7119, 4, 9, 47049, // 4, 9 + 3, 9, 5350, 3, 10, 7342, 4, 9, 7698, 4, 10, 45146, // 4,10 + 3, 10, 5965, 3, 11, 8332, 4, 10, 8378, 4, 11, 42861, // 4,11 + 3, 11, 6615, 3, 12, 9421, 4, 11, 9056, 4, 12, 40444, // 4,12 + 3, 12, 7261, 3, 13, 10559, 4, 12, 9674, 4, 13, 38042, // 4,13 + 3, 13, 7881, 3, 14, 11721, 4, 13, 10204, 4, 14, 35730, // 4,14 + 3, 14, 8463, 3, 15, 12899, 4, 14, 10635, 4, 15, 33539, // 4,15 + 5, -1, 9995, 5, 0, 34567, 6, -1, 8107, 6, 0, 12867, // 5, 0 + 5, 0, 9509, 5, 1, 36955, 6, 0, 7497, 6, 1, 11575, // 5, 1 + 5, 1, 8902, 5, 2, 39526, 6, 1, 6829, 6, 2, 10279, // 5, 2 + 5, 2, 8175, 5, 3, 42271, 6, 2, 6108, 6, 3, 8982, // 5, 3 + 5, 3, 7342, 5, 4, 45146, 6, 3, 5350, 6, 4, 7698, // 5, 4 + 5, 4, 6451, 5, 5, 48019, 6, 4, 4591, 6, 5, 6475, // 5, 5 + 5, 5, 5624, 5, 6, 50581, 6, 5, 3913, 6, 6, 5418, // 5, 6 + 5, 6, 5092, 5, 7, 52253, 6, 6, 3470, 6, 7, 4721, // 5, 7 + 4, 7, 3466, 4, 8, 4708, 5, 7, 5097, 5, 8, 52265, // 5, 8 + 4, 8, 3911, 4, 9, 5400, 5, 8, 5637, 5, 9, 50588, // 5, 9 + 4, 9, 4591, 4, 10, 6451, 5, 9, 6475, 5, 10, 48019, // 5,10 + 4, 10, 5353, 4, 11, 7667, 5, 10, 7377, 5, 11, 45139, // 5,11 + 4, 11, 6116, 4, 12, 8940, 5, 11, 8224, 5, 12, 42256, // 5,12 + 4, 12, 6842, 4, 13, 10226, 5, 12, 8966, 5, 13, 39502, // 5,13 + 4, 13, 7517, 4, 14, 11507, 5, 13, 9587, 5, 14, 36925, // 5,14 + 4, 14, 8135, 4, 15, 12783, 5, 14, 10086, 5, 15, 34532, // 5,15 + 6, -1, 9558, 6, 0, 35362, 7, -1, 7839, 7, 0, 12777, // 6, 0 + 6, 0, 9020, 6, 1, 37906, 7, 0, 7202, 7, 1, 11408, // 6, 1 + 6, 1, 8344, 6, 2, 40688, 7, 1, 6491, 7, 2, 10013, // 6, 2 + 6, 2, 7516, 6, 3, 43733, 7, 2, 5703, 7, 3, 8584, // 6, 3 + 6, 3, 6530, 6, 4, 47049, 7, 3, 4838, 7, 4, 7119, // 6, 4 + 6, 4, 5400, 6, 5, 50587, 7, 4, 3911, 7, 5, 5638, // 6, 5 + 6, 5, 4217, 6, 6, 54105, 7, 5, 2989, 7, 6, 4225, // 6, 6 + 6, 6, 3303, 6, 7, 56751, 7, 6, 2295, 7, 7, 3187, // 6, 7 + 5, 7, 2294, 5, 8, 3180, 6, 7, 3306, 6, 8, 56756, // 6, 8 + 5, 8, 2989, 5, 9, 4217, 6, 8, 4225, 6, 9, 54105, // 6, 9 + 5, 9, 3913, 5, 10, 5624, 6, 9, 5418, 6, 10, 50581, // 6,10 + 5, 10, 4843, 5, 11, 7100, 6, 10, 6558, 6, 11, 47035, // 6,11 + 5, 11, 5712, 5, 12, 8558, 6, 11, 7556, 6, 12, 43710, // 6,12 + 5, 12, 6506, 5, 13, 9977, 6, 12, 8397, 6, 13, 40656, // 6,13 + 5, 13, 7224, 5, 14, 11360, 6, 13, 9086, 6, 14, 37866, // 6,14 + 5, 14, 7868, 5, 15, 12717, 6, 14, 9635, 6, 15, 35316, // 6,15 + 7, -1, 9224, 7, 0, 35905, 8, -1, 7643, 8, 0, 12764, // 7, 0 + 7, 0, 8662, 7, 1, 38534, 8, 0, 6997, 8, 1, 11343, // 7, 1 + 7, 1, 7951, 7, 2, 41432, 8, 1, 6266, 8, 2, 9887, // 7, 2 + 7, 2, 7072, 7, 3, 44649, 8, 2, 5443, 8, 3, 8372, // 7, 3 + 7, 3, 6000, 7, 4, 48240, 8, 3, 4513, 8, 4, 6783, // 7, 4 + 7, 4, 4708, 7, 5, 52266, 8, 4, 3466, 8, 5, 5096, // 7, 5 + 7, 5, 3180, 7, 6, 56756, 8, 5, 2294, 8, 6, 3306, // 7, 6 + 7, 6, 1541, 7, 7, 61364, 8, 6, 1090, 8, 7, 1541, // 7, 7 + 6, 7, 1090, 6, 8, 1541, 7, 7, 1542, 7, 8, 61363, // 7, 8 + 6, 8, 2295, 6, 9, 3303, 7, 8, 3186, 7, 9, 56752, // 7, 9 + 6, 9, 3470, 6, 10, 5092, 7, 9, 4721, 7, 10, 52253, // 7,10 + 6, 10, 4521, 6, 11, 6774, 7, 10, 6023, 7, 11, 48218, // 7,11 + 6, 11, 5454, 6, 12, 8359, 7, 11, 7106, 7, 12, 44617, // 7,12 + 6, 12, 6284, 6, 13, 9867, 7, 12, 7996, 7, 13, 41389, // 7,13 + 6, 13, 7020, 6, 14, 11317, 7, 13, 8718, 7, 14, 38481, // 7,14 + 6, 14, 7674, 6, 15, 12728, 7, 14, 9290, 7, 15, 35844, // 7,15 + 8, 0, 35844, 8, 1, 9290, 9, 0, 12728, 9, 1, 7674, // 8, 0 + 8, 1, 38481, 8, 2, 8718, 9, 1, 11317, 9, 2, 7020, // 8, 1 + 8, 2, 41389, 8, 3, 7996, 9, 2, 9867, 9, 3, 6284, // 8, 2 + 8, 3, 44616, 8, 4, 7106, 9, 3, 8359, 9, 4, 5455, // 8, 3 + 8, 4, 48218, 8, 5, 6023, 9, 4, 6774, 9, 5, 4521, // 8, 4 + 8, 5, 52253, 8, 6, 4721, 9, 5, 5092, 9, 6, 3470, // 8, 5 + 8, 6, 56751, 8, 7, 3186, 9, 6, 3303, 9, 7, 2296, // 8, 6 + 8, 7, 61364, 8, 8, 1542, 9, 7, 1541, 9, 8, 1089, // 8, 7 + 7, 8, 1542, 7, 9, 1090, 8, 8, 61364, 8, 9, 1540, // 8, 8 + 7, 9, 3306, 7, 10, 2294, 8, 9, 56756, 8, 10, 3180, // 8, 9 + 7, 10, 5097, 7, 11, 3466, 8, 10, 52266, 8, 11, 4707, // 8,10 + 7, 11, 6783, 7, 12, 4513, 8, 11, 48240, 8, 12, 6000, // 8,11 + 7, 12, 8373, 7, 13, 5443, 8, 12, 44649, 8, 13, 7071, // 8,12 + 7, 13, 9886, 7, 14, 6266, 8, 13, 41432, 8, 14, 7952, // 8,13 + 7, 14, 11344, 7, 15, 6997, 8, 14, 38534, 8, 15, 8661, // 8,14 + 7, 15, 12764, 7, 16, 7643, 8, 15, 35905, 8, 16, 9224, // 8,15 + 9, 0, 35315, 9, 1, 9635, 10, 0, 12717, 10, 1, 7869, // 9, 0 + 9, 1, 37866, 9, 2, 9086, 10, 1, 11360, 10, 2, 7224, // 9, 1 + 9, 2, 40656, 9, 3, 8397, 10, 2, 9977, 10, 3, 6506, // 9, 2 + 9, 3, 43710, 9, 4, 7556, 10, 3, 8558, 10, 4, 5712, // 9, 3 + 9, 4, 47035, 9, 5, 6558, 10, 4, 7100, 10, 5, 4843, // 9, 4 + 9, 5, 50581, 9, 6, 5418, 10, 5, 5624, 10, 6, 3913, // 9, 5 + 9, 6, 54105, 9, 7, 4225, 10, 6, 4217, 10, 7, 2989, // 9, 6 + 9, 7, 56756, 9, 8, 3306, 10, 7, 3180, 10, 8, 2294, // 9, 7 + 8, 8, 3186, 8, 9, 2295, 9, 8, 56751, 9, 9, 3304, // 9, 8 + 8, 9, 4225, 8, 10, 2989, 9, 9, 54105, 9, 10, 4217, // 9, 9 + 8, 10, 5637, 8, 11, 3911, 9, 10, 50587, 9, 11, 5401, // 9,10 + 8, 11, 7119, 8, 12, 4838, 9, 11, 47049, 9, 12, 6530, // 9,11 + 8, 12, 8584, 8, 13, 5703, 9, 12, 43733, 9, 13, 7516, // 9,12 + 8, 13, 10013, 8, 14, 6491, 9, 13, 40688, 9, 14, 8344, // 9,13 + 8, 14, 11407, 8, 15, 7202, 9, 14, 37906, 9, 15, 9021, // 9,14 + 8, 15, 12777, 8, 16, 7839, 9, 15, 35362, 9, 16, 9558, // 9,15 + 10, 0, 34532, 10, 1, 10086, 11, 0, 12783, 11, 1, 8135, // 10, 0 + 10, 1, 36926, 10, 2, 9587, 11, 1, 11507, 11, 2, 7516, // 10, 1 + 10, 2, 39503, 10, 3, 8966, 11, 2, 10226, 11, 3, 6841, // 10, 2 + 10, 3, 42256, 10, 4, 8224, 11, 3, 8940, 11, 4, 6116, // 10, 3 + 10, 4, 45139, 10, 5, 7377, 11, 4, 7667, 11, 5, 5353, // 10, 4 + 10, 5, 48019, 10, 6, 6475, 11, 5, 6451, 11, 6, 4591, // 10, 5 + 10, 6, 50587, 10, 7, 5637, 11, 6, 5400, 11, 7, 3912, // 10, 6 + 10, 7, 52266, 10, 8, 5097, 11, 7, 4708, 11, 8, 3465, // 10, 7 + 9, 8, 4721, 9, 9, 3470, 10, 8, 52253, 10, 9, 5092, // 10, 8 + 9, 9, 5418, 9, 10, 3913, 10, 9, 50581, 10, 10, 5624, // 10, 9 + 9, 10, 6475, 9, 11, 4591, 10, 10, 48019, 10, 11, 6451, // 10,10 + 9, 11, 7698, 9, 12, 5350, 10, 11, 45146, 10, 12, 7342, // 10,11 + 9, 12, 8982, 9, 13, 6108, 10, 12, 42271, 10, 13, 8175, // 10,12 + 9, 13, 10279, 9, 14, 6829, 10, 13, 39526, 10, 14, 8902, // 10,13 + 9, 14, 11575, 9, 15, 7497, 10, 14, 36955, 10, 15, 9509, // 10,14 + 9, 15, 12867, 9, 16, 8107, 10, 15, 34567, 10, 16, 9995, // 10,15 + 11, 0, 33539, 11, 1, 10635, 12, 0, 12899, 12, 1, 8463, // 11, 0 + 11, 1, 35730, 11, 2, 10204, 12, 1, 11721, 12, 2, 7881, // 11, 1 + 11, 2, 38042, 11, 3, 9674, 12, 2, 10559, 12, 3, 7261, // 11, 2 + 11, 3, 40444, 11, 4, 9056, 12, 3, 9421, 12, 4, 6615, // 11, 3 + 11, 4, 42861, 11, 5, 8378, 12, 4, 8332, 12, 5, 5965, // 11, 4 + 11, 5, 45146, 11, 6, 7698, 12, 5, 7342, 12, 6, 5350, // 11, 5 + 11, 6, 47049, 11, 7, 7119, 12, 6, 6530, 12, 7, 4838, // 11, 6 + 11, 7, 48240, 11, 8, 6783, 12, 7, 6000, 12, 8, 4513, // 11, 7 + 10, 8, 6023, 10, 9, 4521, 11, 8, 48218, 11, 9, 6774, // 11, 8 + 10, 9, 6558, 10, 10, 4843, 11, 9, 47035, 11, 10, 7100, // 11, 9 + 10, 10, 7377, 10, 11, 5353, 11, 10, 45139, 11, 11, 7667, // 11,10 + 10, 11, 8378, 10, 12, 5965, 11, 11, 42861, 11, 12, 8332, // 11,11 + 10, 12, 9478, 10, 13, 6611, 11, 12, 40452, 11, 13, 8995, // 11,12 + 10, 13, 10630, 10, 14, 7252, 11, 13, 38057, 11, 14, 9597, // 11,13 + 10, 14, 11810, 10, 15, 7865, 11, 14, 35750, 11, 15, 10111, // 11,14 + 10, 15, 13007, 10, 16, 8438, 11, 15, 33564, 11, 16, 10527, // 11,15 + 12, 0, 32391, 12, 1, 11269, 13, 0, 13038, 13, 1, 8838, // 12, 0 + 12, 1, 34358, 12, 2, 10918, 13, 1, 11964, 13, 2, 8296, // 12, 1 + 12, 2, 36392, 12, 3, 10488, 13, 2, 10922, 13, 3, 7734, // 12, 2 + 12, 3, 38450, 12, 4, 9998, 13, 3, 9924, 13, 4, 7164, // 12, 3 + 12, 4, 40452, 12, 5, 9478, 13, 4, 8995, 13, 5, 6611, // 12, 4 + 12, 5, 42271, 12, 6, 8982, 13, 5, 8175, 13, 6, 6108, // 12, 5 + 12, 6, 43733, 12, 7, 8584, 13, 6, 7516, 13, 7, 5703, // 12, 6 + 12, 7, 44649, 12, 8, 8373, 13, 7, 7072, 13, 8, 5442, // 12, 7 + 11, 8, 7106, 11, 9, 5454, 12, 8, 44616, 12, 9, 8360, // 12, 8 + 11, 9, 7556, 11, 10, 5712, 12, 9, 43710, 12, 10, 8558, // 12, 9 + 11, 10, 8224, 11, 11, 6116, 12, 10, 42256, 12, 11, 8940, // 12,10 + 11, 11, 9056, 11, 12, 6615, 12, 11, 40444, 12, 12, 9421, // 12,11 + 11, 12, 9998, 11, 13, 7164, 12, 12, 38450, 12, 13, 9924, // 12,12 + 11, 13, 11012, 11, 14, 7728, 12, 13, 36399, 12, 14, 10397, // 12,13 + 11, 14, 12074, 11, 15, 8284, 12, 14, 34369, 12, 15, 10809, // 12,14 + 11, 15, 13171, 11, 16, 8816, 12, 15, 32406, 12, 16, 11143, // 12,15 + 13, 0, 31138, 13, 1, 11977, 14, 0, 13176, 14, 1, 9245, // 13, 0 + 13, 1, 32881, 13, 2, 11709, 14, 1, 12203, 14, 2, 8743, // 13, 1 + 13, 2, 34650, 13, 3, 11382, 14, 2, 11272, 14, 3, 8232, // 13, 2 + 13, 3, 36399, 13, 4, 11012, 14, 3, 10397, 14, 4, 7728, // 13, 3 + 13, 4, 38057, 13, 5, 10630, 14, 4, 9597, 14, 5, 7252, // 13, 4 + 13, 5, 39526, 13, 6, 10279, 14, 5, 8902, 14, 6, 6829, // 13, 5 + 13, 6, 40688, 13, 7, 10013, 14, 6, 8344, 14, 7, 6491, // 13, 6 + 13, 7, 41432, 13, 8, 9886, 14, 7, 7951, 14, 8, 6267, // 13, 7 + 12, 8, 7996, 12, 9, 6284, 13, 8, 41389, 13, 9, 9867, // 13, 8 + 12, 9, 8397, 12, 10, 6506, 13, 9, 40656, 13, 10, 9977, // 13, 9 + 12, 10, 8966, 12, 11, 6842, 13, 10, 39503, 13, 11, 10225, // 13,10 + 12, 11, 9674, 12, 12, 7261, 13, 11, 38042, 13, 12, 10559, // 13,11 + 12, 12, 10488, 12, 13, 7734, 13, 12, 36392, 13, 13, 10922, // 13,12 + 12, 13, 11382, 12, 14, 8232, 13, 13, 34650, 13, 14, 11272, // 13,13 + 12, 14, 12334, 12, 15, 8735, 13, 14, 32886, 13, 15, 11581, // 13,14 + 12, 15, 13332, 12, 16, 9229, 13, 15, 31146, 13, 16, 11829, // 13,15 + 14, 0, 29828, 14, 1, 12746, 15, 0, 13291, 15, 1, 9671, // 14, 0 + 14, 1, 31358, 14, 2, 12564, 15, 1, 12412, 15, 2, 9202, // 14, 1 + 14, 2, 32886, 14, 3, 12334, 15, 2, 11580, 15, 3, 8736, // 14, 2 + 14, 3, 34369, 14, 4, 12074, 15, 3, 10808, 15, 4, 8285, // 14, 3 + 14, 4, 35750, 14, 5, 11810, 15, 4, 10111, 15, 5, 7865, // 14, 4 + 14, 5, 36955, 14, 6, 11575, 15, 5, 9509, 15, 6, 7497, // 14, 5 + 14, 6, 37906, 14, 7, 11407, 15, 6, 9020, 15, 7, 7203, // 14, 6 + 14, 7, 38534, 14, 8, 11344, 15, 7, 8662, 15, 8, 6996, // 14, 7 + 13, 8, 8718, 13, 9, 7020, 14, 8, 38481, 14, 9, 11317, // 14, 8 + 13, 9, 9086, 13, 10, 7224, 14, 9, 37866, 14, 10, 11360, // 14, 9 + 13, 10, 9587, 13, 11, 7517, 14, 10, 36926, 14, 11, 11506, // 14,10 + 13, 11, 10204, 13, 12, 7881, 14, 11, 35730, 14, 12, 11721, // 14,11 + 13, 12, 10918, 13, 13, 8296, 14, 12, 34358, 14, 13, 11964, // 14,12 + 13, 13, 11709, 13, 14, 8742, 14, 13, 32881, 14, 14, 12204, // 14,13 + 13, 14, 12564, 13, 15, 9202, 14, 14, 31358, 14, 15, 12412, // 14,14 + 13, 15, 13470, 13, 16, 9662, 14, 15, 29831, 14, 16, 12573, // 14,15 + 15, 0, 28495, 15, 1, 13569, 16, 0, 13368, 16, 1, 10104, // 15, 0 + 15, 1, 29831, 15, 2, 13470, 16, 1, 12574, 16, 2, 9661, // 15, 1 + 15, 2, 31146, 15, 3, 13332, 16, 2, 11829, 16, 3, 9229, // 15, 2 + 15, 3, 32406, 15, 4, 13171, 16, 3, 11143, 16, 4, 8816, // 15, 3 + 15, 4, 33564, 15, 5, 13007, 16, 4, 10528, 16, 5, 8437, // 15, 4 + 15, 5, 34567, 15, 6, 12867, 16, 5, 9995, 16, 6, 8107, // 15, 5 + 15, 6, 35362, 15, 7, 12777, 16, 6, 9558, 16, 7, 7839, // 15, 6 + 15, 7, 35905, 15, 8, 12764, 16, 7, 9224, 16, 8, 7643, // 15, 7 + 14, 8, 9290, 14, 9, 7674, 15, 8, 35844, 15, 9, 12728, // 15, 8 + 14, 9, 9635, 14, 10, 7868, 15, 9, 35315, 15, 10, 12718, // 15, 9 + 14, 10, 10086, 14, 11, 8135, 15, 10, 34532, 15, 11, 12783, // 15,10 + 14, 11, 10635, 14, 12, 8463, 15, 11, 33539, 15, 12, 12899, // 15,11 + 14, 12, 11269, 14, 13, 8838, 15, 12, 32391, 15, 13, 13038, // 15,12 + 14, 13, 11977, 14, 14, 9245, 15, 13, 31138, 15, 14, 13176, // 15,13 + 14, 14, 12746, 14, 15, 9671, 15, 14, 29828, 15, 15, 13291, // 15,14 + 14, 15, 13569, 14, 16, 10104, 15, 15, 28495, 15, 16, 13368, // 15,15 + // angle of 2.5 degrees + 0, -1, 14696, 0, 0, 24063, 1, -1, 11702, 1, 0, 15075, // 0, 0 + 0, 0, 14872, 0, 1, 25368, 1, 0, 11187, 1, 1, 14109, // 0, 1 + 0, 1, 14990, 0, 2, 26660, 1, 1, 10676, 1, 2, 13210, // 0, 2 + 0, 2, 15060, 0, 3, 27903, 1, 2, 10185, 1, 3, 12388, // 0, 3 + 0, 3, 15100, 0, 4, 29055, 1, 3, 9728, 1, 4, 11653, // 0, 4 + 0, 4, 15135, 0, 5, 30064, 1, 4, 9323, 1, 5, 11014, // 0, 5 + 0, 5, 15193, 0, 6, 30876, 1, 5, 8986, 1, 6, 10481, // 0, 6 + 0, 6, 15301, 0, 7, 31444, 1, 6, 8727, 1, 7, 10064, // 0, 7 + -1, 7, 8669, -1, 8, 9959, 0, 7, 15376, 0, 8, 31532, // 0, 8 + -1, 8, 8927, -1, 9, 10351, 0, 8, 15319, 0, 9, 30939, // 0, 9 + -1, 9, 9265, -1, 10, 10855, 0, 9, 15311, 0, 10, 30105, // 0,10 + -1, 10, 9673, -1, 11, 11461, 0, 10, 15325, 0, 11, 29077, // 0,11 + -1, 11, 10135, -1, 12, 12159, 0, 11, 15330, 0, 12, 27912, // 0,12 + -1, 12, 10637, -1, 13, 12938, 0, 12, 15301, 0, 13, 26660, // 0,13 + -1, 13, 11164, -1, 14, 13787, 0, 13, 15220, 0, 14, 25365, // 0,14 + -1, 14, 11702, -1, 15, 14696, 0, 14, 15076, 0, 15, 24062, // 0,15 + 1, -1, 13787, 1, 0, 25366, 2, -1, 11164, 2, 0, 15219, // 1, 0 + 1, 0, 13853, 1, 1, 26893, 2, 0, 10644, 2, 1, 14146, // 1, 1 + 1, 1, 13850, 1, 2, 28427, 2, 1, 10119, 2, 2, 13140, // 1, 2 + 1, 2, 13789, 1, 3, 29928, 2, 2, 9603, 2, 3, 12216, // 1, 3 + 1, 3, 13694, 1, 4, 31339, 2, 3, 9118, 2, 4, 11385, // 1, 4 + 1, 4, 13600, 1, 5, 32586, 2, 4, 8685, 2, 5, 10665, // 1, 5 + 1, 5, 13548, 1, 6, 33585, 2, 5, 8329, 2, 6, 10074, // 1, 6 + 1, 6, 13582, 1, 7, 34261, 2, 6, 8068, 2, 7, 9625, // 1, 7 + 0, 7, 8024, 0, 8, 9534, 1, 7, 13638, 1, 8, 34340, // 1, 8 + 0, 8, 8286, 0, 9, 9961, 1, 8, 13647, 1, 9, 33642, // 1, 9 + 0, 9, 8645, 0, 10, 10528, 1, 9, 13740, 1, 10, 32623, // 1,10 + 0, 10, 9082, 0, 11, 11218, 1, 10, 13875, 1, 11, 31361, // 1,11 + 0, 11, 9575, 0, 12, 12014, 1, 11, 14009, 1, 12, 29938, // 1,12 + 0, 12, 10102, 0, 13, 12897, 1, 12, 14107, 1, 13, 28430, // 1,13 + 0, 13, 10644, 0, 14, 13853, 1, 13, 14145, 1, 14, 26894, // 1,14 + 0, 14, 11187, 0, 15, 14872, 1, 14, 14109, 1, 15, 25368, // 1,15 + 2, -1, 12938, 2, 0, 26660, 3, -1, 10637, 3, 0, 15301, // 2, 0 + 2, 0, 12897, 2, 1, 28430, 3, 0, 10102, 3, 1, 14107, // 2, 1 + 2, 1, 12769, 2, 2, 30239, 3, 1, 9546, 3, 2, 12982, // 2, 2 + 2, 2, 12569, 2, 3, 32045, 3, 2, 8988, 3, 3, 11934, // 2, 3 + 2, 3, 12323, 2, 4, 33777, 3, 3, 8452, 3, 4, 10984, // 2, 4 + 2, 4, 12079, 2, 5, 35332, 3, 4, 7969, 3, 5, 10156, // 2, 5 + 2, 5, 11897, 2, 6, 36582, 3, 5, 7573, 3, 6, 9484, // 2, 6 + 2, 6, 11842, 2, 7, 37402, 3, 6, 7298, 3, 7, 8994, // 2, 7 + 1, 7, 7266, 1, 8, 8918, 2, 7, 11883, 2, 8, 37469, // 2, 8 + 1, 8, 7543, 1, 9, 9390, 2, 8, 11972, 2, 9, 36631, // 2, 9 + 1, 9, 7943, 1, 10, 10041, 2, 9, 12188, 2, 10, 35364, // 2,10 + 1, 10, 8432, 1, 11, 10842, 2, 10, 12467, 2, 11, 33795, // 2,11 + 1, 11, 8976, 1, 12, 11760, 2, 11, 12747, 2, 12, 32053, // 2,12 + 1, 12, 9546, 1, 13, 12769, 2, 12, 12982, 2, 13, 30239, // 2,13 + 1, 13, 10119, 1, 14, 13850, 2, 13, 13141, 2, 14, 28426, // 2,14 + 1, 14, 10676, 1, 15, 14990, 2, 14, 13211, 2, 15, 26659, // 2,15 + 3, -1, 12159, 3, 0, 27912, 4, -1, 10135, 4, 0, 15330, // 3, 0 + 3, 0, 12014, 3, 1, 29938, 4, 0, 9575, 4, 1, 14009, // 3, 1 + 3, 1, 11760, 3, 2, 32052, 4, 1, 8976, 4, 2, 12748, // 3, 2 + 3, 2, 11411, 3, 3, 34213, 4, 2, 8358, 4, 3, 11554, // 3, 3 + 3, 3, 10995, 3, 4, 36343, 4, 3, 7746, 4, 4, 10452, // 3, 4 + 3, 4, 10569, 3, 5, 38307, 4, 4, 7180, 4, 5, 9480, // 3, 5 + 3, 5, 10221, 3, 6, 39912, 4, 5, 6714, 4, 6, 8689, // 3, 6 + 3, 6, 10051, 3, 7, 40940, 4, 6, 6403, 4, 7, 8142, // 3, 7 + 2, 7, 6381, 2, 8, 8082, 3, 7, 10079, 3, 8, 40994, // 3, 8 + 2, 8, 6695, 2, 9, 8617, 3, 8, 10275, 3, 9, 39949, // 3, 9 + 2, 9, 7165, 2, 10, 9388, 3, 9, 10653, 3, 10, 38330, // 3,10 + 2, 10, 7737, 2, 11, 10337, 3, 10, 11108, 3, 11, 36354, // 3,11 + 2, 11, 8358, 2, 12, 11411, 3, 11, 11554, 3, 12, 34213, // 3,12 + 2, 12, 8988, 2, 13, 12569, 3, 12, 11934, 3, 13, 32045, // 3,13 + 2, 13, 9603, 2, 14, 13789, 3, 13, 12216, 3, 14, 29928, // 3,14 + 2, 14, 10185, 2, 15, 15060, 3, 14, 12388, 3, 15, 27903, // 3,15 + 4, -1, 11461, 4, 0, 29078, 5, -1, 9673, 5, 0, 15324, // 4, 0 + 4, 0, 11218, 4, 1, 31361, 5, 0, 9082, 5, 1, 13875, // 4, 1 + 4, 1, 10842, 4, 2, 33795, 5, 1, 8432, 5, 2, 12467, // 4, 2 + 4, 2, 10337, 4, 3, 36354, 5, 2, 7737, 5, 3, 11108, // 4, 3 + 4, 3, 9730, 4, 4, 38966, 5, 3, 7022, 5, 4, 9818, // 4, 4 + 4, 4, 9081, 4, 5, 41475, 5, 4, 6334, 5, 5, 8646, // 4, 5 + 4, 5, 8507, 4, 6, 43602, 5, 5, 5749, 5, 6, 7678, // 4, 6 + 4, 6, 8177, 4, 7, 44962, 5, 6, 5368, 5, 7, 7029, // 4, 7 + 3, 7, 5354, 3, 8, 6987, 4, 7, 8195, 4, 8, 45000, // 4, 8 + 3, 8, 5739, 3, 9, 7626, 4, 8, 8545, 4, 9, 43626, // 4, 9 + 3, 9, 6328, 3, 10, 8578, 4, 9, 9143, 4, 10, 41487, // 4,10 + 3, 10, 7022, 3, 11, 9730, 4, 10, 9818, 4, 11, 38966, // 4,11 + 3, 11, 7746, 3, 12, 10995, 4, 11, 10452, 4, 12, 36343, // 4,12 + 3, 12, 8452, 3, 13, 12323, 4, 12, 10983, 4, 13, 33778, // 4,13 + 3, 13, 9118, 3, 14, 13694, 4, 13, 11385, 4, 14, 31339, // 4,14 + 3, 14, 9728, 3, 15, 15100, 4, 14, 11652, 4, 15, 29056, // 4,15 + 5, -1, 10855, 5, 0, 30105, 6, -1, 9265, 6, 0, 15311, // 5, 0 + 5, 0, 10528, 5, 1, 32624, 6, 0, 8645, 6, 1, 13739, // 5, 1 + 5, 1, 10041, 5, 2, 35364, 6, 1, 7943, 6, 2, 12188, // 5, 2 + 5, 2, 9388, 5, 3, 38330, 6, 2, 7165, 6, 3, 10653, // 5, 3 + 5, 3, 8578, 5, 4, 41487, 6, 3, 6328, 6, 4, 9143, // 5, 4 + 5, 4, 7659, 5, 5, 44700, 6, 4, 5472, 6, 5, 7705, // 5, 5 + 5, 5, 6768, 5, 6, 47619, 6, 5, 4694, 6, 6, 6455, // 5, 6 + 5, 6, 6183, 5, 7, 49566, 6, 6, 4172, 6, 7, 5615, // 5, 7 + 4, 7, 4164, 4, 8, 5590, 5, 7, 6193, 5, 8, 49589, // 5, 8 + 4, 8, 4690, 4, 9, 6422, 5, 8, 6794, 5, 9, 47630, // 5, 9 + 4, 9, 5472, 4, 10, 7659, 5, 9, 7705, 5, 10, 44700, // 5,10 + 4, 10, 6334, 4, 11, 9081, 5, 10, 8646, 5, 11, 41475, // 5,11 + 4, 11, 7180, 4, 12, 10569, 5, 11, 9479, 5, 12, 38308, // 5,12 + 4, 12, 7969, 4, 13, 12079, 5, 12, 10156, 5, 13, 35332, // 5,13 + 4, 13, 8685, 4, 14, 13600, 5, 13, 10665, 5, 14, 32586, // 5,14 + 4, 14, 9323, 4, 15, 15135, 5, 14, 11013, 5, 15, 30065, // 5,15 + 6, -1, 10351, 6, 0, 30939, 7, -1, 8927, 7, 0, 15319, // 6, 0 + 6, 0, 9961, 6, 1, 33642, 7, 0, 8286, 7, 1, 13647, // 6, 1 + 6, 1, 9390, 6, 2, 36631, 7, 1, 7543, 7, 2, 11972, // 6, 2 + 6, 2, 8617, 6, 3, 39949, 7, 2, 6695, 7, 3, 10275, // 6, 3 + 6, 3, 7626, 6, 4, 43626, 7, 3, 5739, 7, 4, 8545, // 6, 4 + 6, 4, 6422, 6, 5, 47630, 7, 4, 4690, 7, 5, 6794, // 6, 5 + 6, 5, 5099, 6, 6, 51701, 7, 5, 3620, 7, 6, 5116, // 6, 6 + 6, 6, 4044, 6, 7, 54831, 7, 6, 2797, 7, 7, 3864, // 6, 7 + 5, 7, 2795, 5, 8, 3853, 6, 7, 4049, 6, 8, 54839, // 6, 8 + 5, 8, 3620, 5, 9, 5099, 6, 8, 5116, 6, 9, 51701, // 6, 9 + 5, 9, 4694, 5, 10, 6768, 6, 9, 6455, 6, 10, 47619, // 6,10 + 5, 10, 5749, 5, 11, 8507, 6, 10, 7678, 6, 11, 43602, // 6,11 + 5, 11, 6714, 5, 12, 10221, 6, 11, 8690, 6, 12, 39911, // 6,12 + 5, 12, 7573, 5, 13, 11897, 6, 12, 9484, 6, 13, 36582, // 6,13 + 5, 13, 8329, 5, 14, 13548, 6, 13, 10074, 6, 14, 33585, // 6,14 + 5, 14, 8986, 5, 15, 15193, 6, 14, 10482, 6, 15, 30875, // 6,15 + 7, -1, 9959, 7, 0, 31532, 8, -1, 8669, 8, 0, 15376, // 7, 0 + 7, 0, 9534, 7, 1, 34340, 8, 0, 8024, 8, 1, 13638, // 7, 1 + 7, 1, 8918, 7, 2, 37470, 8, 1, 7266, 8, 2, 11882, // 7, 2 + 7, 2, 8082, 7, 3, 40994, 8, 2, 6381, 8, 3, 10079, // 7, 3 + 7, 3, 6987, 7, 4, 44999, 8, 3, 5354, 8, 4, 8196, // 7, 4 + 7, 4, 5590, 7, 5, 49588, 8, 4, 4164, 8, 5, 6194, // 7, 5 + 7, 5, 3853, 7, 6, 54839, 8, 5, 2795, 8, 6, 4049, // 7, 6 + 7, 6, 1903, 7, 7, 60382, 8, 6, 1347, 8, 7, 1904, // 7, 7 + 6, 7, 1347, 6, 8, 1903, 7, 7, 1905, 7, 8, 60381, // 7, 8 + 6, 8, 2797, 6, 9, 4044, 7, 8, 3864, 7, 9, 54831, // 7, 9 + 6, 9, 4172, 6, 10, 6183, 7, 9, 5615, 7, 10, 49566, // 7,10 + 6, 10, 5368, 6, 11, 8177, 7, 10, 7029, 7, 11, 44962, // 7,11 + 6, 11, 6403, 6, 12, 10051, 7, 11, 8141, 7, 12, 40941, // 7,12 + 6, 12, 7298, 6, 13, 11842, 7, 12, 8994, 7, 13, 37402, // 7,13 + 6, 13, 8068, 6, 14, 13582, 7, 13, 9626, 7, 14, 34260, // 7,14 + 6, 14, 8727, 6, 15, 15301, 7, 14, 10065, 7, 15, 31443, // 7,15 + 8, 0, 31444, 8, 1, 10065, 9, 0, 15301, 9, 1, 8726, // 8, 0 + 8, 1, 34261, 8, 2, 9626, 9, 1, 13582, 9, 2, 8067, // 8, 1 + 8, 2, 37402, 8, 3, 8994, 9, 2, 11842, 9, 3, 7298, // 8, 2 + 8, 3, 40940, 8, 4, 8141, 9, 3, 10051, 9, 4, 6404, // 8, 3 + 8, 4, 44962, 8, 5, 7029, 9, 4, 8177, 9, 5, 5368, // 8, 4 + 8, 5, 49566, 8, 6, 5615, 9, 5, 6183, 9, 6, 4172, // 8, 5 + 8, 6, 54831, 8, 7, 3864, 9, 6, 4044, 9, 7, 2797, // 8, 6 + 8, 7, 60382, 8, 8, 1905, 9, 7, 1903, 9, 8, 1346, // 8, 7 + 7, 8, 1905, 7, 9, 1347, 8, 8, 60382, 8, 9, 1902, // 8, 8 + 7, 9, 4049, 7, 10, 2795, 8, 9, 54839, 8, 10, 3853, // 8, 9 + 7, 10, 6193, 7, 11, 4164, 8, 10, 49588, 8, 11, 5591, // 8,10 + 7, 11, 8195, 7, 12, 5354, 8, 11, 44999, 8, 12, 6988, // 8,11 + 7, 12, 10079, 7, 13, 6381, 8, 12, 40994, 8, 13, 8082, // 8,12 + 7, 13, 11883, 7, 14, 7266, 8, 13, 37470, 8, 14, 8917, // 8,13 + 7, 14, 13638, 7, 15, 8024, 8, 14, 34340, 8, 15, 9534, // 8,14 + 7, 15, 15376, 7, 16, 8669, 8, 15, 31532, 8, 16, 9959, // 8,15 + 9, 0, 30876, 9, 1, 10482, 10, 0, 15193, 10, 1, 8985, // 9, 0 + 9, 1, 33585, 9, 2, 10074, 10, 1, 13548, 10, 2, 8329, // 9, 1 + 9, 2, 36582, 9, 3, 9484, 10, 2, 11897, 10, 3, 7573, // 9, 2 + 9, 3, 39912, 9, 4, 8690, 10, 3, 10221, 10, 4, 6713, // 9, 3 + 9, 4, 43602, 9, 5, 7678, 10, 4, 8507, 10, 5, 5749, // 9, 4 + 9, 5, 47619, 9, 6, 6455, 10, 5, 6768, 10, 6, 4694, // 9, 5 + 9, 6, 51701, 9, 7, 5116, 10, 6, 5099, 10, 7, 3620, // 9, 6 + 9, 7, 54839, 9, 8, 4049, 10, 7, 3853, 10, 8, 2795, // 9, 7 + 8, 8, 3864, 8, 9, 2797, 9, 8, 54831, 9, 9, 4044, // 9, 8 + 8, 9, 5116, 8, 10, 3620, 9, 9, 51701, 9, 10, 5099, // 9, 9 + 8, 10, 6794, 8, 11, 4690, 9, 10, 47630, 9, 11, 6422, // 9,10 + 8, 11, 8545, 8, 12, 5739, 9, 11, 43626, 9, 12, 7626, // 9,11 + 8, 12, 10275, 8, 13, 6695, 9, 12, 39949, 9, 13, 8617, // 9,12 + 8, 13, 11972, 8, 14, 7543, 9, 13, 36631, 9, 14, 9390, // 9,13 + 8, 14, 13647, 8, 15, 8286, 9, 14, 33642, 9, 15, 9961, // 9,14 + 8, 15, 15319, 8, 16, 8927, 9, 15, 30939, 9, 16, 10351, // 9,15 + 10, 0, 30064, 10, 1, 11013, 11, 0, 15135, 11, 1, 9324, // 10, 0 + 10, 1, 32586, 10, 2, 10665, 11, 1, 13600, 11, 2, 8685, // 10, 1 + 10, 2, 35332, 10, 3, 10156, 11, 2, 12079, 11, 3, 7969, // 10, 2 + 10, 3, 38307, 10, 4, 9479, 11, 3, 10569, 11, 4, 7181, // 10, 3 + 10, 4, 41475, 10, 5, 8646, 11, 4, 9081, 11, 5, 6334, // 10, 4 + 10, 5, 44700, 10, 6, 7705, 11, 5, 7659, 11, 6, 5472, // 10, 5 + 10, 6, 47630, 10, 7, 6794, 11, 6, 6422, 11, 7, 4690, // 10, 6 + 10, 7, 49588, 10, 8, 6193, 11, 7, 5590, 11, 8, 4165, // 10, 7 + 9, 8, 5615, 9, 9, 4172, 10, 8, 49566, 10, 9, 6183, // 10, 8 + 9, 9, 6455, 9, 10, 4694, 10, 9, 47619, 10, 10, 6768, // 10, 9 + 9, 10, 7705, 9, 11, 5472, 10, 10, 44700, 10, 11, 7659, // 10,10 + 9, 11, 9143, 9, 12, 6328, 10, 11, 41487, 10, 12, 8578, // 10,11 + 9, 12, 10653, 9, 13, 7165, 10, 12, 38330, 10, 13, 9388, // 10,12 + 9, 13, 12188, 9, 14, 7943, 10, 13, 35364, 10, 14, 10041, // 10,13 + 9, 14, 13740, 9, 15, 8645, 10, 14, 32624, 10, 15, 10527, // 10,14 + 9, 15, 15311, 9, 16, 9265, 10, 15, 30105, 10, 16, 10855, // 10,15 + 11, 0, 29055, 11, 1, 11652, 12, 0, 15100, 12, 1, 9729, // 11, 0 + 11, 1, 31339, 11, 2, 11385, 12, 1, 13694, 12, 2, 9118, // 11, 1 + 11, 2, 33777, 11, 3, 10983, 12, 2, 12323, 12, 3, 8453, // 11, 2 + 11, 3, 36343, 11, 4, 10452, 12, 3, 10995, 12, 4, 7746, // 11, 3 + 11, 4, 38966, 11, 5, 9818, 12, 4, 9730, 12, 5, 7022, // 11, 4 + 11, 5, 41487, 11, 6, 9143, 12, 5, 8578, 12, 6, 6328, // 11, 5 + 11, 6, 43626, 11, 7, 8545, 12, 6, 7626, 12, 7, 5739, // 11, 6 + 11, 7, 44999, 11, 8, 8195, 12, 7, 6987, 12, 8, 5355, // 11, 7 + 10, 8, 7029, 10, 9, 5368, 11, 8, 44962, 11, 9, 8177, // 11, 8 + 10, 9, 7678, 10, 10, 5749, 11, 9, 43602, 11, 10, 8507, // 11, 9 + 10, 10, 8646, 10, 11, 6334, 11, 10, 41475, 11, 11, 9081, // 11,10 + 10, 11, 9818, 10, 12, 7022, 11, 11, 38966, 11, 12, 9730, // 11,11 + 10, 12, 11108, 10, 13, 7737, 11, 12, 36354, 11, 13, 10337, // 11,12 + 10, 13, 12467, 10, 14, 8432, 11, 13, 33795, 11, 14, 10842, // 11,13 + 10, 14, 13875, 10, 15, 9082, 11, 14, 31361, 11, 15, 11218, // 11,14 + 10, 15, 15325, 10, 16, 9673, 11, 15, 29078, 11, 16, 11460, // 11,15 + 12, 0, 27903, 12, 1, 12388, 13, 0, 15060, 13, 1, 10185, // 12, 0 + 12, 1, 29928, 12, 2, 12216, 13, 1, 13789, 13, 2, 9603, // 12, 1 + 12, 2, 32045, 12, 3, 11934, 13, 2, 12569, 13, 3, 8988, // 12, 2 + 12, 3, 34213, 12, 4, 11554, 13, 3, 11411, 13, 4, 8358, // 12, 3 + 12, 4, 36354, 12, 5, 11108, 13, 4, 10337, 13, 5, 7737, // 12, 4 + 12, 5, 38330, 12, 6, 10653, 13, 5, 9388, 13, 6, 7165, // 12, 5 + 12, 6, 39949, 12, 7, 10275, 13, 6, 8617, 13, 7, 6695, // 12, 6 + 12, 7, 40994, 12, 8, 10079, 13, 7, 8082, 13, 8, 6381, // 12, 7 + 11, 8, 8141, 11, 9, 6403, 12, 8, 40940, 12, 9, 10052, // 12, 8 + 11, 9, 8690, 11, 10, 6714, 12, 9, 39912, 12, 10, 10220, // 12, 9 + 11, 10, 9479, 11, 11, 7180, 12, 10, 38307, 12, 11, 10570, // 12,10 + 11, 11, 10452, 11, 12, 7746, 12, 11, 36343, 12, 12, 10995, // 12,11 + 11, 12, 11554, 11, 13, 8358, 12, 12, 34213, 12, 13, 11411, // 12,12 + 11, 13, 12747, 11, 14, 8976, 12, 13, 32052, 12, 14, 11761, // 12,13 + 11, 14, 14009, 11, 15, 9575, 12, 14, 29938, 12, 15, 12014, // 12,14 + 11, 15, 15330, 11, 16, 10135, 12, 15, 27912, 12, 16, 12159, // 12,15 + 13, 0, 26660, 13, 1, 13211, 14, 0, 14990, 14, 1, 10675, // 13, 0 + 13, 1, 28427, 13, 2, 13141, 14, 1, 13850, 14, 2, 10118, // 13, 1 + 13, 2, 30239, 13, 3, 12982, 14, 2, 12769, 14, 3, 9546, // 13, 2 + 13, 3, 32052, 13, 4, 12747, 14, 3, 11760, 14, 4, 8977, // 13, 3 + 13, 4, 33795, 13, 5, 12467, 14, 4, 10842, 14, 5, 8432, // 13, 4 + 13, 5, 35364, 13, 6, 12188, 14, 5, 10041, 14, 6, 7943, // 13, 5 + 13, 6, 36631, 13, 7, 11972, 14, 6, 9390, 14, 7, 7543, // 13, 6 + 13, 7, 37470, 13, 8, 11883, 14, 7, 8918, 14, 8, 7265, // 13, 7 + 12, 8, 8994, 12, 9, 7298, 13, 8, 37402, 13, 9, 11842, // 13, 8 + 12, 9, 9484, 12, 10, 7573, 13, 9, 36582, 13, 10, 11897, // 13, 9 + 12, 10, 10156, 12, 11, 7969, 13, 10, 35332, 13, 11, 12079, // 13,10 + 12, 11, 10983, 12, 12, 8452, 13, 11, 33777, 13, 12, 12324, // 13,11 + 12, 12, 11934, 12, 13, 8988, 13, 12, 32045, 13, 13, 12569, // 13,12 + 12, 13, 12982, 12, 14, 9546, 13, 13, 30239, 13, 14, 12769, // 13,13 + 12, 14, 14107, 12, 15, 10102, 13, 14, 28430, 13, 15, 12897, // 13,14 + 12, 15, 15301, 12, 16, 10637, 13, 15, 26660, 13, 16, 12938, // 13,15 + 14, 0, 25368, 14, 1, 14109, 15, 0, 14872, 15, 1, 11187, // 14, 0 + 14, 1, 26893, 14, 2, 14145, 15, 1, 13853, 15, 2, 10645, // 14, 1 + 14, 2, 28430, 14, 3, 14107, 15, 2, 12897, 15, 3, 10102, // 14, 2 + 14, 3, 29938, 14, 4, 14009, 15, 3, 12014, 15, 4, 9575, // 14, 3 + 14, 4, 31361, 14, 5, 13875, 15, 4, 11218, 15, 5, 9082, // 14, 4 + 14, 5, 32624, 14, 6, 13740, 15, 5, 10528, 15, 6, 8644, // 14, 5 + 14, 6, 33642, 14, 7, 13647, 15, 6, 9961, 15, 7, 8286, // 14, 6 + 14, 7, 34340, 14, 8, 13638, 15, 7, 9534, 15, 8, 8024, // 14, 7 + 13, 8, 9626, 13, 9, 8068, 14, 8, 34261, 14, 9, 13581, // 14, 8 + 13, 9, 10074, 13, 10, 8329, 14, 9, 33585, 14, 10, 13548, // 14, 9 + 13, 10, 10665, 13, 11, 8685, 14, 10, 32586, 14, 11, 13600, // 14,10 + 13, 11, 11385, 13, 12, 9118, 14, 11, 31339, 14, 12, 13694, // 14,11 + 13, 12, 12216, 13, 13, 9603, 14, 12, 29928, 14, 13, 13789, // 14,12 + 13, 13, 13141, 13, 14, 10119, 14, 13, 28427, 14, 14, 13849, // 14,13 + 13, 14, 14145, 13, 15, 10644, 14, 14, 26893, 14, 15, 13854, // 14,14 + 13, 15, 15220, 13, 16, 11164, 14, 15, 25366, 14, 16, 13786, // 14,15 + 15, 0, 24063, 15, 1, 15076, 16, 0, 14696, 16, 1, 11701, // 15, 0 + 15, 1, 25366, 15, 2, 15220, 16, 1, 13787, 16, 2, 11163, // 15, 1 + 15, 2, 26660, 15, 3, 15301, 16, 2, 12938, 16, 3, 10637, // 15, 2 + 15, 3, 27912, 15, 4, 15330, 16, 3, 12159, 16, 4, 10135, // 15, 3 + 15, 4, 29078, 15, 5, 15325, 16, 4, 11461, 16, 5, 9672, // 15, 4 + 15, 5, 30105, 15, 6, 15311, 16, 5, 10855, 16, 6, 9265, // 15, 5 + 15, 6, 30939, 15, 7, 15319, 16, 6, 10351, 16, 7, 8927, // 15, 6 + 15, 7, 31532, 15, 8, 15376, 16, 7, 9959, 16, 8, 8669, // 15, 7 + 14, 8, 10065, 14, 9, 8727, 15, 8, 31444, 15, 9, 15300, // 15, 8 + 14, 9, 10482, 14, 10, 8986, 15, 9, 30876, 15, 10, 15192, // 15, 9 + 14, 10, 11013, 14, 11, 9323, 15, 10, 30064, 15, 11, 15136, // 15,10 + 14, 11, 11652, 14, 12, 9728, 15, 11, 29055, 15, 12, 15101, // 15,11 + 14, 12, 12388, 14, 13, 10185, 15, 12, 27903, 15, 13, 15060, // 15,12 + 14, 13, 13211, 14, 14, 10676, 15, 13, 26660, 15, 14, 14989, // 15,13 + 14, 14, 14109, 14, 15, 11187, 15, 14, 25368, 15, 15, 14872, // 15,14 + 14, 15, 15076, 14, 16, 11702, 15, 15, 24063, 15, 16, 14695, // 15,15 diff --git a/vp8/common/seg_common.c b/vp8/common/seg_common.c new file mode 100644 index 000000000..3ba374a49 --- /dev/null +++ b/vp8/common/seg_common.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vp8/common/seg_common.h" + +const int segfeaturedata_signed[SEG_LVL_MAX] = {1, 1, 0, 0, 0, 0}; +const int vp8_seg_feature_data_bits[SEG_LVL_MAX] = + {QINDEX_BITS, 6, 4, 4, 6, 2}; + +// These functions provide access to new segment level features. +// Eventually these function may be "optimized out" but for the moment, +// the coding mechanism is still subject to change so these provide a +// convenient single point of change. + +int segfeature_active( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ) +{ + // Return true if mask bit set and segmentation enabled. + return ( xd->segmentation_enabled && + ( xd->segment_feature_mask[segment_id] & + (0x01 << feature_id) ) ); +} + +void clearall_segfeatures( MACROBLOCKD *xd ) +{ + vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data)); + vpx_memset(xd->segment_feature_mask, 0, sizeof(xd->segment_feature_mask)); +} + +void enable_segfeature( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ) +{ + xd->segment_feature_mask[segment_id] |= (0x01 << feature_id); +} + +void disable_segfeature( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ) +{ + xd->segment_feature_mask[segment_id] &= ~(1 << feature_id); +} + +int seg_feature_data_bits( SEG_LVL_FEATURES feature_id ) +{ + return vp8_seg_feature_data_bits[feature_id]; +} + +int is_segfeature_signed( SEG_LVL_FEATURES feature_id ) +{ + return ( segfeaturedata_signed[feature_id] ); +} + +void clear_segdata( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id) +{ + xd->segment_feature_data[segment_id][feature_id] = 0; +} + +void set_segdata( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id, + int seg_data ) +{ + xd->segment_feature_data[segment_id][feature_id] = seg_data; +} + +int get_segdata( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ) +{ + return xd->segment_feature_data[segment_id][feature_id]; +} +#if CONFIG_FEATUREUPDATES +int old_segfeature_active( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ) +{ + // Return true if mask bit set and segmentation enabled. + return ( xd->segmentation_enabled && + ( xd->old_segment_feature_mask[segment_id] & + (0x01 << feature_id) ) ); +} + +int get_old_segdata( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ) +{ + return xd->old_segment_feature_data[segment_id][feature_id]; +} + +int segfeature_changed( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ) +{ + // Return true if mask bit or data is different from last time + return + ( xd->segmentation_enabled && + ( + (xd->old_segment_feature_mask[segment_id] & (1 << feature_id) ) != + (xd->segment_feature_mask[segment_id] & (1 << feature_id) ) + || xd->old_segment_feature_data[segment_id][feature_id] != + xd->segment_feature_data[segment_id][feature_id] + ) + ); +} + +void save_segment_info ( MACROBLOCKD *xd ) +{ + int i,j; + for (i = 0; i < MAX_MB_SEGMENTS; i++) + { + xd->old_segment_feature_mask[i] = xd->segment_feature_mask[i]; + + // For each segmentation codable feature... + for (j = 0; j < SEG_LVL_MAX; j++) + { + xd->old_segment_feature_data[i][j]=xd->segment_feature_data[i][j]; + + } + } +} +#endif +void clear_segref( MACROBLOCKD *xd, int segment_id ) +{ + xd->segment_feature_data[segment_id][SEG_LVL_REF_FRAME] = 0; +} + +void set_segref( MACROBLOCKD *xd, + int segment_id, + MV_REFERENCE_FRAME ref_frame ) +{ + xd->segment_feature_data[segment_id][SEG_LVL_REF_FRAME] |= + (1 << ref_frame); +} + +int check_segref( MACROBLOCKD *xd, + int segment_id, + MV_REFERENCE_FRAME ref_frame ) +{ + return ( xd->segment_feature_data[segment_id][SEG_LVL_REF_FRAME] & + (1 << ref_frame) ) ? 1 : 0; +} + +int check_segref_inter(MACROBLOCKD *xd, int segment_id) +{ + return ( xd->segment_feature_data[segment_id][SEG_LVL_REF_FRAME] & + ~(1 << INTRA_FRAME) ) ? 1 : 0; +} + +int get_seg_tx_type(MACROBLOCKD *xd, int segment_id) +{ + if ( segfeature_active(xd, segment_id, SEG_LVL_TRANSFORM) ) + return get_segdata(xd, segment_id, SEG_LVL_TRANSFORM); + else + return TX_4X4; +} +// TBD? Functions to read and write segment data with range / validity checking diff --git a/vp8/common/seg_common.h b/vp8/common/seg_common.h new file mode 100644 index 000000000..bfd364e6d --- /dev/null +++ b/vp8/common/seg_common.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "type_aliases.h" +#include "onyxc_int.h" +#include "vp8/common/blockd.h" + +#ifndef __INC_SEG_COMMON_H__ +#define __INC_SEG_COMMON_H__ 1 + +int segfeature_active( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ); + +void clearall_segfeatures( MACROBLOCKD *xd ); + +void enable_segfeature( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ); + +void disable_segfeature( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ); + +int seg_feature_data_bits( SEG_LVL_FEATURES feature_id ); + +int is_segfeature_signed( SEG_LVL_FEATURES feature_id ); + +void clear_segdata( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id); + +void set_segdata( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id, + int seg_data ); + +int get_segdata( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ); + +#if CONFIG_FEATUREUPDATES + +int old_segfeature_active( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ); + +int get_old_segdata( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ); + +void save_segment_info ( MACROBLOCKD *xd ); + +int segfeature_changed( MACROBLOCKD *xd, + int segment_id, + SEG_LVL_FEATURES feature_id ); + + + +#endif + + +void clear_segref( MACROBLOCKD *xd, int segment_id ); + +void set_segref( MACROBLOCKD *xd, + int segment_id, + MV_REFERENCE_FRAME ref_frame ); + +int check_segref( MACROBLOCKD *xd, + int segment_id, + MV_REFERENCE_FRAME ref_frame ); + +int check_segref_inter(MACROBLOCKD *xd, int segment_id); + +int get_seg_tx_type(MACROBLOCKD *xd, int segment_id); + +#endif /* __INC_SEG_COMMON_H__ */ + diff --git a/vp8/common/subpixel.h b/vp8/common/subpixel.h index acdeec3bc..0b1b72fa0 100644 --- a/vp8/common/subpixel.h +++ b/vp8/common/subpixel.h @@ -34,6 +34,15 @@ extern prototype_subpixel_predict(vp8_subpix_sixtap16x16); #endif extern prototype_subpixel_predict(vp8_subpix_sixtap8x8); +#ifndef vp8_subpix_sixtap_avg16x16 +#define vp8_subpix_sixtap_avg16x16 vp8_sixtap_predict_avg16x16_c +#endif +extern prototype_subpixel_predict(vp8_subpix_sixtap_avg16x16); + +#ifndef vp8_subpix_sixtap_avg8x8 +#define vp8_subpix_sixtap_avg8x8 vp8_sixtap_predict_avg8x8_c +#endif +extern prototype_subpixel_predict(vp8_subpix_sixtap_avg8x8); #ifndef vp8_subpix_sixtap8x4 #define vp8_subpix_sixtap8x4 vp8_sixtap_predict8x4_c #endif @@ -54,6 +63,16 @@ extern prototype_subpixel_predict(vp8_subpix_bilinear16x16); #endif extern prototype_subpixel_predict(vp8_subpix_bilinear8x8); +#ifndef vp8_subpix_bilinear_avg16x16 +#define vp8_subpix_bilinear_avg16x16 vp8_bilinear_predict_avg16x16_c +#endif +extern prototype_subpixel_predict(vp8_subpix_bilinear_avg16x16); + +#ifndef vp8_subpix_bilinear_avg8x8 +#define vp8_subpix_bilinear_avg8x8 vp8_bilinear_predict_avg8x8_c +#endif +extern prototype_subpixel_predict(vp8_subpix_bilinear_avg8x8); + #ifndef vp8_subpix_bilinear8x4 #define vp8_subpix_bilinear8x4 vp8_bilinear_predict8x4_c #endif @@ -69,10 +88,14 @@ typedef struct { vp8_subpix_fn_t sixtap16x16; vp8_subpix_fn_t sixtap8x8; + vp8_subpix_fn_t sixtap_avg16x16; + vp8_subpix_fn_t sixtap_avg8x8; vp8_subpix_fn_t sixtap8x4; vp8_subpix_fn_t sixtap4x4; vp8_subpix_fn_t bilinear16x16; vp8_subpix_fn_t bilinear8x8; + vp8_subpix_fn_t bilinear_avg16x16; + vp8_subpix_fn_t bilinear_avg8x8; vp8_subpix_fn_t bilinear8x4; vp8_subpix_fn_t bilinear4x4; } vp8_subpix_rtcd_vtable_t; diff --git a/vp8/common/systemdependent.h b/vp8/common/systemdependent.h index f99c4bb2a..db996987a 100644 --- a/vp8/common/systemdependent.h +++ b/vp8/common/systemdependent.h @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #if ARCH_X86 || ARCH_X86_64 void vpx_reset_mmx_state(void); #define vp8_clear_system_state() vpx_reset_mmx_state() diff --git a/vp8/common/tapify.py b/vp8/common/tapify.py new file mode 100644 index 000000000..99529cff0 --- /dev/null +++ b/vp8/common/tapify.py @@ -0,0 +1,106 @@ +""" + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. +""" +#!/usr/bin/env python +import sys,string,os,re,math,numpy +scale = 2**16 +def dist(p1,p2): + x1,y1 = p1 + x2,y2 = p2 + if x1==x2 and y1==y2 : + return 1.0 + return 1/ math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) + +def gettaps(p): + def l(b): + return int(math.floor(b)) + def h(b): + return int(math.ceil(b)) + def t(b,p,s): + return int((scale*dist(b,p)+s/2)/s) + r,c = p + ul=[l(r),l(c)] + ur=[l(r),h(c)] + ll=[h(r),l(c)] + lr=[h(r),h(c)] + sum = dist(ul,p)+dist(ur,p)+dist(ll,p)+dist(lr,p) + t4 = scale - t(ul,p,sum) - t(ur,p,sum) - t(ll,p,sum); + return [[ul,t(ul,p,sum)],[ur,t(ur,p,sum)], + [ll,t(ll,p,sum)],[lr,t4]] + +def print_mb_taps(angle,blocksize): + theta = angle / 57.2957795; + affine = [[math.cos(theta),-math.sin(theta)], + [math.sin(theta),math.cos(theta)]] + radius = (float(blocksize)-1)/2 + print " // angle of",angle,"degrees" + for y in range(blocksize) : + for x in range(blocksize) : + r,c = numpy.dot(affine,[y-radius, x-radius]) + tps = gettaps([r+radius,c+radius]) + for t in tps : + p,t = t + tr,tc = p + print " %2d, %2d, %5d, " % (tr,tc,t,), + print " // %2d,%2d " % (y,x) + +i=float(sys.argv[1]) +while i <= float(sys.argv[2]) : + print_mb_taps(i,float(sys.argv[4])) + i=i+float(sys.argv[3]) +""" + +taps = [] +pt=dict() +ptr=dict() +for y in range(16) : + for x in range(16) : + r,c = numpy.dot(affine,[y-7.5, x-7.5]) + tps = gettaps([r+7.5,c+7.5]) + j=0 + for tp in tps : + p,i = tp + r,c = p + pt[y,x,j]= [p,i] + try: + ptr[r,j,c].append([y,x]) + except: + ptr[r,j,c]=[[y,x]] + j = j+1 + +for key in sorted(pt.keys()) : + print key,pt[key] + +lr = -99 +lj = -99 +lc = 0 + +shuf="" +mask="" +for r,j,c in sorted(ptr.keys()) : + for y,x in ptr[r,j,c] : + if lr != r or lj != j : + print "shuf_"+str(lr)+"_"+str(lj)+"_"+shuf.ljust(16,"0"), lc + shuf="" + lc = 0 + for i in range(lc,c-1) : + shuf = shuf +"0" + shuf = shuf + hex(x)[2] + lc =c + break + lr = r + lj = j +# print r,j,c,ptr[r,j,c] +# print + +for r,j,c in sorted(ptr.keys()) : + for y,x in ptr[r,j,c] : + print r,j,c,y,x + break +""" diff --git a/vp8/common/threading.h b/vp8/common/threading.h deleted file mode 100644 index 5927cb165..000000000 --- a/vp8/common/threading.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -#ifndef _PTHREAD_EMULATION -#define _PTHREAD_EMULATION - -#if CONFIG_OS_SUPPORT && CONFIG_MULTITHREAD - -/* Thread management macros */ -#ifdef _WIN32 -/* Win32 */ -#define _WIN32_WINNT 0x500 /* WINBASE.H - Enable signal_object_and_wait */ -#include -#include -#define THREAD_FUNCTION DWORD WINAPI -#define THREAD_FUNCTION_RETURN DWORD -#define THREAD_SPECIFIC_INDEX DWORD -#define pthread_t HANDLE -#define pthread_attr_t DWORD -#define pthread_create(thhandle,attr,thfunc,tharg) (int)((*thhandle=(HANDLE)_beginthreadex(NULL,0,(unsigned int (__stdcall *)(void *))thfunc,tharg,0,NULL))==NULL) -#define pthread_join(thread, result) ((WaitForSingleObject((thread),INFINITE)!=WAIT_OBJECT_0) || !CloseHandle(thread)) -#define pthread_detach(thread) if(thread!=NULL)CloseHandle(thread) -#define thread_sleep(nms) Sleep(nms) -#define pthread_cancel(thread) terminate_thread(thread,0) -#define ts_key_create(ts_key, destructor) {ts_key = TlsAlloc();}; -#define pthread_getspecific(ts_key) TlsGetValue(ts_key) -#define pthread_setspecific(ts_key, value) TlsSetValue(ts_key, (void *)value) -#define pthread_self() GetCurrentThreadId() -#else -#ifdef __APPLE__ -#include -#include -#include -#include -#include - -#else -#include -#endif - -#include -/* pthreads */ -/* Nearly everything is already defined */ -#define THREAD_FUNCTION void * -#define THREAD_FUNCTION_RETURN void * -#define THREAD_SPECIFIC_INDEX pthread_key_t -#define ts_key_create(ts_key, destructor) pthread_key_create (&(ts_key), destructor); -#endif - -/* Syncrhronization macros: Win32 and Pthreads */ -#ifdef _WIN32 -#define sem_t HANDLE -#define pause(voidpara) __asm PAUSE -#define sem_init(sem, sem_attr1, sem_init_value) (int)((*sem = CreateSemaphore(NULL,0,32768,NULL))==NULL) -#define sem_wait(sem) (int)(WAIT_OBJECT_0 != WaitForSingleObject(*sem,INFINITE)) -#define sem_post(sem) ReleaseSemaphore(*sem,1,NULL) -#define sem_destroy(sem) if(*sem)((int)(CloseHandle(*sem))==TRUE) -#define thread_sleep(nms) Sleep(nms) - -#else - -#ifdef __APPLE__ -#define sem_t semaphore_t -#define sem_init(X,Y,Z) semaphore_create(mach_task_self(), X, SYNC_POLICY_FIFO, Z) -#define sem_wait(sem) (semaphore_wait(*sem) ) -#define sem_post(sem) semaphore_signal(*sem) -#define sem_destroy(sem) semaphore_destroy(mach_task_self(),*sem) -#define thread_sleep(nms) /* { struct timespec ts;ts.tv_sec=0; ts.tv_nsec = 1000*nms;nanosleep(&ts, NULL);} */ -#else -#include -#include -#define thread_sleep(nms) sched_yield();/* {struct timespec ts;ts.tv_sec=0; ts.tv_nsec = 1000*nms;nanosleep(&ts, NULL);} */ -#endif -/* Not Windows. Assume pthreads */ - -#endif - -#if ARCH_X86 || ARCH_X86_64 -#include "vpx_ports/x86.h" -#else -#define x86_pause_hint() -#endif - -#endif /* CONFIG_OS_SUPPORT && CONFIG_MULTITHREAD */ - -#endif diff --git a/vp8/common/x86/mask_sse3.asm b/vp8/common/x86/mask_sse3.asm new file mode 100644 index 000000000..0d90cfa86 --- /dev/null +++ b/vp8/common/x86/mask_sse3.asm @@ -0,0 +1,484 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void int vp8_makemask_sse3( +; unsigned char *y, +; unsigned char *u, +; unsigned char *v, +; unsigned char *ym, +; unsigned char *uvm, +; int yp, +; int uvp, +; int ys, +; int us, +; int vs, +; int yt, +; int ut, +; int vt) +global sym(vp8_makemask_sse3) +sym(vp8_makemask_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 14 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;y + mov rdi, arg(1) ;u + mov rcx, arg(2) ;v + mov rax, arg(3) ;ym + movsxd rbx, dword arg(4) ;yp + movsxd rdx, dword arg(5) ;uvp + + pxor xmm0,xmm0 + + ;make 16 copies of the center y value + movd xmm1, arg(6) + pshufb xmm1, xmm0 + + ; make 16 copies of the center u value + movd xmm2, arg(7) + pshufb xmm2, xmm0 + + ; make 16 copies of the center v value + movd xmm3, arg(8) + pshufb xmm3, xmm0 + unpcklpd xmm2, xmm3 + + ;make 16 copies of the y tolerance + movd xmm3, arg(9) + pshufb xmm3, xmm0 + + ;make 16 copies of the u tolerance + movd xmm4, arg(10) + pshufb xmm4, xmm0 + + ;make 16 copies of the v tolerance + movd xmm5, arg(11) + pshufb xmm5, xmm0 + unpckhpd xmm4, xmm5 + + mov r8,8 + +NextPairOfRows: + + ;grab the y source values + movdqu xmm0, [rsi] + + ;compute abs difference between source and y target + movdqa xmm6, xmm1 + movdqa xmm7, xmm0 + psubusb xmm0, xmm1 + psubusb xmm6, xmm7 + por xmm0, xmm6 + + ;compute abs difference between + movdqa xmm6, xmm3 + pcmpgtb xmm6, xmm0 + + ;grab the y source values + add rsi, rbx + movdqu xmm0, [rsi] + + ;compute abs difference between source and y target + movdqa xmm11, xmm1 + movdqa xmm7, xmm0 + psubusb xmm0, xmm1 + psubusb xmm11, xmm7 + por xmm0, xmm11 + + ;compute abs difference between + movdqa xmm11, xmm3 + pcmpgtb xmm11, xmm0 + + + ;grab the u and v source values + movdqu xmm7, [rdi] + movdqu xmm8, [rcx] + unpcklpd xmm7, xmm8 + + ;compute abs difference between source and uv targets + movdqa xmm9, xmm2 + movdqa xmm10, xmm7 + psubusb xmm7, xmm2 + psubusb xmm9, xmm10 + por xmm7, xmm9 + + ;check whether the number is < tolerance + movdqa xmm0, xmm4 + pcmpgtb xmm0, xmm7 + + ;double u and v masks + movdqa xmm8, xmm0 + punpckhbw xmm0, xmm0 + punpcklbw xmm8, xmm8 + + ;mask row 0 and output + pand xmm6, xmm8 + pand xmm6, xmm0 + movdqa [rax],xmm6 + + ;mask row 1 and output + pand xmm11, xmm8 + pand xmm11, xmm0 + movdqa [rax+16],xmm11 + + + ; to the next row or set of rows + add rsi, rbx + add rdi, rdx + add rcx, rdx + add rax,32 + dec r8 + jnz NextPairOfRows + + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;GROW_HORIZ (register for result, source register or mem local) +; takes source and shifts left and ors with source +; then shifts right and ors with source +%macro GROW_HORIZ 2 + movdqa %1, %2 + movdqa xmm14, %1 + movdqa xmm15, %1 + pslldq xmm14, 1 + psrldq xmm15, 1 + por %1,xmm14 + por %1,xmm15 +%endmacro +;GROW_VERT (result, center row, above row, below row) +%macro GROW_VERT 4 + movdqa %1,%2 + por %1,%3 + por %1,%4 +%endmacro + +;GROW_NEXTLINE (new line to grow, new source, line to write) +%macro GROW_NEXTLINE 3 + GROW_HORIZ %1, %2 + GROW_VERT xmm3, xmm0, xmm1, xmm2 + movdqa %3,xmm3 +%endmacro + + +;void int vp8_growmaskmb_sse3( +; unsigned char *om, +; unsigned char *nm, +global sym(vp8_growmaskmb_sse3) +sym(vp8_growmaskmb_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src + mov rdi, arg(1) ;rst + + GROW_HORIZ xmm0, [rsi] + GROW_HORIZ xmm1, [rsi+16] + GROW_HORIZ xmm2, [rsi+32] + + GROW_VERT xmm3, xmm0, xmm1, xmm2 + por xmm0,xmm1 + movdqa [rdi], xmm0 + movdqa [rdi+16],xmm3 + + GROW_NEXTLINE xmm0,[rsi+48],[rdi+32] + GROW_NEXTLINE xmm1,[rsi+64],[rdi+48] + GROW_NEXTLINE xmm2,[rsi+80],[rdi+64] + GROW_NEXTLINE xmm0,[rsi+96],[rdi+80] + GROW_NEXTLINE xmm1,[rsi+112],[rdi+96] + GROW_NEXTLINE xmm2,[rsi+128],[rdi+112] + GROW_NEXTLINE xmm0,[rsi+144],[rdi+128] + GROW_NEXTLINE xmm1,[rsi+160],[rdi+144] + GROW_NEXTLINE xmm2,[rsi+176],[rdi+160] + GROW_NEXTLINE xmm0,[rsi+192],[rdi+176] + GROW_NEXTLINE xmm1,[rsi+208],[rdi+192] + GROW_NEXTLINE xmm2,[rsi+224],[rdi+208] + GROW_NEXTLINE xmm0,[rsi+240],[rdi+224] + + por xmm0,xmm2 + movdqa [rdi+240], xmm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + + +;unsigned int vp8_sad16x16_masked_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; unsigned char *mask) +global sym(vp8_sad16x16_masked_wmt) +sym(vp8_sad16x16_masked_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + mov rbx, arg(4) ;mask + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + mov rcx, 16 + + pxor xmm3, xmm3 + +NextSadRow: + movdqu xmm0, [rsi] + movdqu xmm1, [rdi] + movdqu xmm2, [rbx] + pand xmm0, xmm2 + pand xmm1, xmm2 + + psadbw xmm0, xmm1 + paddw xmm3, xmm0 + + add rsi, rax + add rdi, rdx + add rbx, 16 + + dec rcx + jnz NextSadRow + + movdqa xmm4 , xmm3 + psrldq xmm4, 8 + paddw xmm3, xmm4 + movq rax, xmm3 + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad16x16_unmasked_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; unsigned char *mask) +global sym(vp8_sad16x16_unmasked_wmt) +sym(vp8_sad16x16_unmasked_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + mov rbx, arg(4) ;mask + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + mov rcx, 16 + + pxor xmm3, xmm3 + +next_vp8_sad16x16_unmasked_wmt: + movdqu xmm0, [rsi] + movdqu xmm1, [rdi] + movdqu xmm2, [rbx] + por xmm0, xmm2 + por xmm1, xmm2 + + psadbw xmm0, xmm1 + paddw xmm3, xmm0 + + add rsi, rax + add rdi, rdx + add rbx, 16 + + dec rcx + jnz next_vp8_sad16x16_unmasked_wmt + + movdqa xmm4 , xmm3 + psrldq xmm4, 8 + paddw xmm3, xmm4 + movq rax, xmm3 + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_masked_predictor_wmt( +; unsigned char *masked, +; unsigned char *unmasked, +; int src_stride, +; unsigned char *dst_ptr, +; int dst_stride, +; unsigned char *mask) +global sym(vp8_masked_predictor_wmt) +sym(vp8_masked_predictor_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + push rsi + push rdi + ; end prolog + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;ref_ptr + + mov rbx, arg(5) ;mask + movsxd rax, dword ptr arg(2) ;src_stride + mov r11, arg(3) ; destination + movsxd rdx, dword ptr arg(4) ;dst_stride + + mov rcx, 16 + + pxor xmm3, xmm3 + +next_vp8_masked_predictor_wmt: + movdqu xmm0, [rsi] + movdqu xmm1, [rdi] + movdqu xmm2, [rbx] + + pand xmm0, xmm2 + pandn xmm2, xmm1 + por xmm0, xmm2 + movdqu [r11], xmm0 + + add r11, rdx + add rsi, rax + add rdi, rdx + add rbx, 16 + + dec rcx + jnz next_vp8_masked_predictor_wmt + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;unsigned int vp8_masked_predictor_uv_wmt( +; unsigned char *masked, +; unsigned char *unmasked, +; int src_stride, +; unsigned char *dst_ptr, +; int dst_stride, +; unsigned char *mask) +global sym(vp8_masked_predictor_uv_wmt) +sym(vp8_masked_predictor_uv_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + push rsi + push rdi + ; end prolog + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;ref_ptr + + mov rbx, arg(5) ;mask + movsxd rax, dword ptr arg(2) ;src_stride + mov r11, arg(3) ; destination + movsxd rdx, dword ptr arg(4) ;dst_stride + + mov rcx, 8 + + pxor xmm3, xmm3 + +next_vp8_masked_predictor_uv_wmt: + movq xmm0, [rsi] + movq xmm1, [rdi] + movq xmm2, [rbx] + + pand xmm0, xmm2 + pandn xmm2, xmm1 + por xmm0, xmm2 + movq [r11], xmm0 + + add r11, rdx + add rsi, rax + add rdi, rax + add rbx, 8 + + dec rcx + jnz next_vp8_masked_predictor_uv_wmt + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_uv_from_y_mask( +; unsigned char *ymask, +; unsigned char *uvmask) +global sym(vp8_uv_from_y_mask) +sym(vp8_uv_from_y_mask): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + push rsi + push rdi + ; end prolog + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;dst_ptr + + + mov rcx, 8 + + pxor xmm3, xmm3 + +next_p8_uv_from_y_mask: + movdqu xmm0, [rsi] + pshufb xmm0, [shuf1b] ;[GLOBAL(shuf1b)] + movq [rdi],xmm0 + add rdi, 8 + add rsi,32 + + dec rcx + jnz next_p8_uv_from_y_mask + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +shuf1b: + db 0, 2, 4, 6, 8, 10, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0 + diff --git a/vp8/common/x86/recon_wrapper_sse2.c b/vp8/common/x86/recon_wrapper_sse2.c index fcc75a901..cb7b69c08 100644 --- a/vp8/common/x86/recon_wrapper_sse2.c +++ b/vp8/common/x86/recon_wrapper_sse2.c @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/recon.h" #include "recon_x86.h" #include "vpx_mem/vpx_mem.h" diff --git a/vp8/common/x86/subpixel_ssse3.asm b/vp8/common/x86/subpixel_ssse3.asm index 6bca82bfb..39f4f7b88 100644 --- a/vp8/common/x86/subpixel_ssse3.asm +++ b/vp8/common/x86/subpixel_ssse3.asm @@ -1495,6 +1495,25 @@ k2_k4: times 8 db 36, -11 times 8 db 12, -6 align 16 +%if CONFIG_SIXTEENTH_SUBPEL_UV +vp8_bilinear_filters_ssse3: + times 8 db 128, 0 + times 8 db 120, 8 + times 8 db 112, 16 + times 8 db 104, 24 + times 8 db 96, 32 + times 8 db 88, 40 + times 8 db 80, 48 + times 8 db 72, 56 + times 8 db 64, 64 + times 8 db 56, 72 + times 8 db 48, 80 + times 8 db 40, 88 + times 8 db 32, 96 + times 8 db 24, 104 + times 8 db 16, 112 + times 8 db 8, 120 +%else vp8_bilinear_filters_ssse3: times 8 db 128, 0 times 8 db 112, 16 @@ -1504,4 +1523,5 @@ vp8_bilinear_filters_ssse3: times 8 db 48, 80 times 8 db 32, 96 times 8 db 16, 112 +%endif diff --git a/vp8/common/x86/vp8_asm_stubs.c b/vp8/common/x86/vp8_asm_stubs.c index bce7bc38e..458b3f638 100644 --- a/vp8/common/x86/vp8_asm_stubs.c +++ b/vp8/common/x86/vp8_asm_stubs.c @@ -9,12 +9,19 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_ports/mem.h" #include "vp8/common/subpixel.h" +#if CONFIG_SIXTEENTH_SUBPEL_UV +extern const short vp8_six_tap_mmx[16][6*8]; +extern const short vp8_bilinear_filters_mmx[16][2*8]; +#else extern const short vp8_six_tap_mmx[8][6*8]; extern const short vp8_bilinear_filters_mmx[8][2*8]; +#endif + +//#define ANNOUNCE_FUNCTION extern void vp8_filter_block1d_h6_mmx ( @@ -128,6 +135,9 @@ void vp8_sixtap_predict4x4_mmx int dst_pitch ) { +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict4x4_mmx\n"); +#endif DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 16*16); /* Temp data bufffer used in filtering */ const short *HFilter, *VFilter; HFilter = vp8_six_tap_mmx[xoffset]; @@ -149,6 +159,9 @@ void vp8_sixtap_predict16x16_mmx ) { +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict16x16_mmx\n"); +#endif DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 24*24); /* Temp data bufffer used in filtering */ const short *HFilter, *VFilter; @@ -181,6 +194,9 @@ void vp8_sixtap_predict8x8_mmx ) { +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict8x8_mmx\n"); +#endif DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); /* Temp data bufffer used in filtering */ const short *HFilter, *VFilter; @@ -206,7 +222,9 @@ void vp8_sixtap_predict8x4_mmx int dst_pitch ) { - +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict8x4_mmx\n"); +#endif DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); /* Temp data bufffer used in filtering */ const short *HFilter, *VFilter; @@ -256,6 +274,9 @@ void vp8_sixtap_predict16x16_sse2 DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 24*24); /* Temp data bufffer used in filtering */ const short *HFilter, *VFilter; +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict16x16_sse2\n"); +#endif if (xoffset) { @@ -295,6 +316,9 @@ void vp8_sixtap_predict8x8_sse2 { DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); /* Temp data bufffer used in filtering */ const short *HFilter, *VFilter; +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict8x8_sse2\n"); +#endif if (xoffset) { @@ -333,6 +357,9 @@ void vp8_sixtap_predict8x4_sse2 { DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); /* Temp data bufffer used in filtering */ const short *HFilter, *VFilter; +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict8x4_sse2\n"); +#endif if (xoffset) { @@ -434,6 +461,9 @@ void vp8_sixtap_predict16x16_ssse3 ) { DECLARE_ALIGNED_ARRAY(16, unsigned char, FData2, 24*24); +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict16x16_ssse3\n"); +#endif if (xoffset) { @@ -466,6 +496,9 @@ void vp8_sixtap_predict8x8_ssse3 ) { DECLARE_ALIGNED_ARRAY(16, unsigned char, FData2, 256); +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict8x8_ssse3\n"); +#endif if (xoffset) { @@ -498,6 +531,9 @@ void vp8_sixtap_predict8x4_ssse3 ) { DECLARE_ALIGNED_ARRAY(16, unsigned char, FData2, 256); +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict8x4_ssse3\n"); +#endif if (xoffset) { @@ -530,6 +566,9 @@ void vp8_sixtap_predict4x4_ssse3 ) { DECLARE_ALIGNED_ARRAY(16, unsigned char, FData2, 4*9); +#ifdef ANNOUNCE_FUNCTION + printf("vp8_sixtap_predict4x4_ssse3\n"); +#endif if (xoffset) { diff --git a/vp8/common/x86/x86_systemdependent.c b/vp8/common/x86/x86_systemdependent.c index 33a984b79..53009502c 100644 --- a/vp8/common/x86/x86_systemdependent.c +++ b/vp8/common/x86/x86_systemdependent.c @@ -43,17 +43,17 @@ void vp8_arch_x86_common_init(VP8_COMMON *ctx) rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_mmx; rtcd->idct.iwalsh1 = vp8_short_inv_walsh4x4_1_mmx; - - rtcd->recon.recon = vp8_recon_b_mmx; rtcd->recon.copy8x8 = vp8_copy_mem8x8_mmx; rtcd->recon.copy8x4 = vp8_copy_mem8x4_mmx; rtcd->recon.copy16x16 = vp8_copy_mem16x16_mmx; +#if CONFIG_ENHANCED_INTERP == 0 && CONFIG_HIGH_PRECISION_MV == 0 && CONFIG_SIXTEENTH_SUBPEL_UV == 0 rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_mmx; rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_mmx; rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_mmx; rtcd->subpix.sixtap4x4 = vp8_sixtap_predict4x4_mmx; +#endif rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_mmx; rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_mmx; rtcd->subpix.bilinear8x4 = vp8_bilinear_predict8x4_mmx; @@ -91,9 +91,11 @@ void vp8_arch_x86_common_init(VP8_COMMON *ctx) rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_sse2; +#if CONFIG_ENHANCED_INTERP == 0 && CONFIG_HIGH_PRECISION_MV == 0 && CONFIG_SIXTEENTH_SUBPEL_UV == 0 rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_sse2; rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_sse2; rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_sse2; +#endif rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_sse2; rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_sse2; @@ -120,12 +122,14 @@ void vp8_arch_x86_common_init(VP8_COMMON *ctx) if (flags & HAS_SSSE3) { +#if CONFIG_ENHANCED_INTERP == 0 && CONFIG_HIGH_PRECISION_MV == 0 rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_ssse3; rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_ssse3; rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_ssse3; rtcd->subpix.sixtap4x4 = vp8_sixtap_predict4x4_ssse3; rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_ssse3; rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_ssse3; +#endif rtcd->recon.build_intra_predictors_mbuv = vp8_build_intra_predictors_mbuv_ssse3; diff --git a/vp8/decoder/arm/arm_dsystemdependent.c b/vp8/decoder/arm/arm_dsystemdependent.c index 1b0091cdb..6ce471217 100644 --- a/vp8/decoder/arm/arm_dsystemdependent.c +++ b/vp8/decoder/arm/arm_dsystemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_ports/arm.h" #include "vp8/common/blockd.h" #include "vp8/common/pragmas.h" diff --git a/vp8/decoder/arm/armv6/idct_blk_v6.c b/vp8/decoder/arm/armv6/idct_blk_v6.c index 5c7592f35..57c344698 100644 --- a/vp8/decoder/arm/armv6/idct_blk_v6.c +++ b/vp8/decoder/arm/armv6/idct_blk_v6.c @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/idct.h" #include "vp8/decoder/dequantize.h" diff --git a/vp8/decoder/arm/dequantize_arm.c b/vp8/decoder/arm/dequantize_arm.c index 2918e0512..98db6eeff 100644 --- a/vp8/decoder/arm/dequantize_arm.c +++ b/vp8/decoder/arm/dequantize_arm.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/decoder/dequantize.h" #include "vp8/common/idct.h" #include "vpx_mem/vpx_mem.h" diff --git a/vp8/decoder/arm/neon/idct_blk_neon.c b/vp8/decoder/arm/neon/idct_blk_neon.c index f31654060..ee3500425 100644 --- a/vp8/decoder/arm/neon/idct_blk_neon.c +++ b/vp8/decoder/arm/neon/idct_blk_neon.c @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/idct.h" #include "vp8/decoder/dequantize.h" diff --git a/vp8/decoder/dboolhuff.h b/vp8/decoder/dboolhuff.h index 880c18522..853c10f14 100644 --- a/vp8/decoder/dboolhuff.h +++ b/vp8/decoder/dboolhuff.h @@ -13,7 +13,7 @@ #define DBOOLHUFF_H #include #include -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_ports/mem.h" #include "vpx/vpx_integer.h" diff --git a/vp8/decoder/decodemv.c b/vp8/decoder/decodemv.c index 54547d95c..8539ff25c 100644 --- a/vp8/decoder/decodemv.c +++ b/vp8/decoder/decodemv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + Copyright (c) 2010 The WebM project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -15,9 +15,18 @@ #include "onyxd_int.h" #include "vp8/common/findnearmv.h" +#include "vp8/common/seg_common.h" +#include "vp8/common/pred_common.h" + #if CONFIG_DEBUG #include #endif + +//#define DEBUG_DEC_MV +#ifdef DEBUG_DEC_MV +int dec_mvcount = 0; +#endif + static int vp8_read_bmode(vp8_reader *bc, const vp8_prob *p) { const int i = vp8_treed_read(bc, vp8_bmode_tree, p); @@ -39,7 +48,12 @@ static int vp8_kfread_ymode(vp8_reader *bc, const vp8_prob *p) return i; } +static int vp8_read_i8x8_mode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_i8x8_mode_tree, p); + return i; +} static int vp8_read_uv_mode(vp8_reader *bc, const vp8_prob *p) @@ -49,7 +63,9 @@ static int vp8_read_uv_mode(vp8_reader *bc, const vp8_prob *p) return i; } -static void vp8_read_mb_features(vp8_reader *r, MB_MODE_INFO *mi, MACROBLOCKD *x) +// This function reads the current macro block's segnent id from the bitstream +// It should only be called if a segment map update is indicated. +static void vp8_read_mb_segid(vp8_reader *r, MB_MODE_INFO *mi, MACROBLOCKD *x) { /* Is segmentation enabled */ if (x->segmentation_enabled && x->update_mb_segmentation_map) @@ -61,49 +77,120 @@ static void vp8_read_mb_features(vp8_reader *r, MB_MODE_INFO *mi, MACROBLOCKD *x mi->segment_id = (unsigned char)(vp8_read(r, x->mb_segment_tree_probs[1])); } } - -static void vp8_kfread_modes(VP8D_COMP *pbi, MODE_INFO *m, int mb_row, int mb_col) +extern const int vp8_i8x8_block[4]; +static void vp8_kfread_modes(VP8D_COMP *pbi, + MODE_INFO *m, + int mb_row, + int mb_col) { vp8_reader *const bc = & pbi->bc; const int mis = pbi->common.mode_info_stride; + int map_index = mb_row * pbi->common.mb_cols + mb_col; + MB_PREDICTION_MODE y_mode; + // Read the Macroblock segmentation map if it is being updated explicitly + // this frame (reset to 0 by default). + m->mbmi.segment_id = 0; + if (pbi->mb.update_mb_segmentation_map) + { + vp8_read_mb_segid(bc, &m->mbmi, &pbi->mb); + pbi->common.last_frame_seg_map[map_index] = m->mbmi.segment_id; + } + + if ( pbi->common.mb_no_coeff_skip && + ( !segfeature_active( &pbi->mb, + m->mbmi.segment_id, SEG_LVL_EOB ) || + ( get_segdata( &pbi->mb, + m->mbmi.segment_id, SEG_LVL_EOB ) != 0 ) ) ) + { + m->mbmi.mb_skip_coeff = vp8_read(bc, pbi->prob_skip_false); + } + else + { + if ( segfeature_active( &pbi->mb, + m->mbmi.segment_id, SEG_LVL_EOB ) && + ( get_segdata( &pbi->mb, + m->mbmi.segment_id, SEG_LVL_EOB ) == 0 ) ) { - MB_PREDICTION_MODE y_mode; - - /* Read the Macroblock segmentation map if it is being updated explicitly this frame (reset to 0 above by default) - * By default on a key frame reset all MBs to segment 0 - */ - m->mbmi.segment_id = 0; - - if (pbi->mb.update_mb_segmentation_map) - vp8_read_mb_features(bc, &m->mbmi, &pbi->mb); - - /* Read the macroblock coeff skip flag if this feature is in use, else default to 0 */ - if (pbi->common.mb_no_coeff_skip) - m->mbmi.mb_skip_coeff = vp8_read(bc, pbi->prob_skip_false); - else - m->mbmi.mb_skip_coeff = 0; - - y_mode = (MB_PREDICTION_MODE) vp8_kfread_ymode(bc, pbi->common.kf_ymode_prob); - - m->mbmi.ref_frame = INTRA_FRAME; - - if ((m->mbmi.mode = y_mode) == B_PRED) - { - int i = 0; - - do - { - const B_PREDICTION_MODE A = above_block_mode(m, i, mis); - const B_PREDICTION_MODE L = left_block_mode(m, i); - - m->bmi[i].as_mode = (B_PREDICTION_MODE) vp8_read_bmode(bc, pbi->common.kf_bmode_prob [A] [L]); - } - while (++i < 16); - } - - m->mbmi.uv_mode = (MB_PREDICTION_MODE)vp8_read_uv_mode(bc, pbi->common.kf_uv_mode_prob); + m->mbmi.mb_skip_coeff = 1; } + else + m->mbmi.mb_skip_coeff = 0; + } + +#if CONFIG_QIMODE + y_mode = (MB_PREDICTION_MODE) vp8_kfread_ymode(bc, + pbi->common.kf_ymode_prob[pbi->common.kf_ymode_probs_index]); +#else + y_mode = (MB_PREDICTION_MODE) vp8_kfread_ymode( + bc, pbi->common.kf_ymode_prob); +#endif +#if CONFIG_COMP_INTRA_PRED + m->mbmi.second_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); +#endif + + m->mbmi.ref_frame = INTRA_FRAME; + + if ((m->mbmi.mode = y_mode) == B_PRED) + { + int i = 0; +#if CONFIG_COMP_INTRA_PRED + int use_comp_pred = vp8_read(bc, 128); +#endif + do + { + const B_PREDICTION_MODE A = above_block_mode(m, i, mis); + const B_PREDICTION_MODE L = left_block_mode(m, i); + + m->bmi[i].as_mode.first = + (B_PREDICTION_MODE) vp8_read_bmode( + bc, pbi->common.kf_bmode_prob [A] [L]); +#if CONFIG_COMP_INTRA_PRED + if (use_comp_pred) + { + m->bmi[i].as_mode.second = + (B_PREDICTION_MODE) vp8_read_bmode( + bc, pbi->common.kf_bmode_prob [A] [L]); + } + else + { + m->bmi[i].as_mode.second = (B_PREDICTION_MODE) (B_DC_PRED - 1); + } +#endif + } + while (++i < 16); + } + if((m->mbmi.mode = y_mode) == I8X8_PRED) + { + int i; + int mode8x8; + for(i=0;i<4;i++) + { + int ib = vp8_i8x8_block[i]; + mode8x8 = vp8_read_i8x8_mode(bc, pbi->common.i8x8_mode_prob); + m->bmi[ib+0].as_mode.first= mode8x8; + m->bmi[ib+1].as_mode.first= mode8x8; + m->bmi[ib+4].as_mode.first= mode8x8; + m->bmi[ib+5].as_mode.first= mode8x8; +#if CONFIG_COMP_INTRA_PRED + m->bmi[ib+0].as_mode.second= (MB_PREDICTION_MODE) (DC_PRED - 1); + m->bmi[ib+1].as_mode.second= (MB_PREDICTION_MODE) (DC_PRED - 1); + m->bmi[ib+4].as_mode.second= (MB_PREDICTION_MODE) (DC_PRED - 1); + m->bmi[ib+5].as_mode.second= (MB_PREDICTION_MODE) (DC_PRED - 1); +#endif + } + } + else +#if CONFIG_UVINTRA + m->mbmi.uv_mode = (MB_PREDICTION_MODE)vp8_read_uv_mode(bc, + pbi->common.kf_uv_mode_prob[m->mbmi.mode]); +#else + m->mbmi.uv_mode = (MB_PREDICTION_MODE)vp8_read_uv_mode(bc, + pbi->common.kf_uv_mode_prob); +#endif +#if CONFIG_COMP_INTRA_PRED + m->mbmi.second_uv_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); +#endif } static int read_mvcomponent(vp8_reader *r, const MV_CONTEXT *mvc) @@ -119,7 +206,7 @@ static int read_mvcomponent(vp8_reader *r, const MV_CONTEXT *mvc) { x += vp8_read(r, p [MVPbits + i]) << i; } - while (++i < 3); + while (++i < mvnum_short_bits); i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ @@ -127,10 +214,10 @@ static int read_mvcomponent(vp8_reader *r, const MV_CONTEXT *mvc) { x += vp8_read(r, p [MVPbits + i]) << i; } - while (--i > 3); + while (--i > mvnum_short_bits); - if (!(x & 0xFFF0) || vp8_read(r, p [MVPbits + 3])) - x += 8; + if (!(x & ~((2<row = (short)(read_mvcomponent(r, mvc) << 1); mv->col = (short)(read_mvcomponent(r, ++mvc) << 1); +#ifdef DEBUG_DEC_MV + int i; + printf("%d (np): %d %d\n", dec_mvcount++, mv->row, mv->col); + //for (i=0; iprob[i]); printf("\n"); + //for (i=0; iprob[i]); printf("\n"); +#endif } @@ -172,6 +265,206 @@ static void read_mvcontexts(vp8_reader *bc, MV_CONTEXT *mvc) while (++i < 2); } +#if CONFIG_HIGH_PRECISION_MV +static int read_mvcomponent_hp(vp8_reader *r, const MV_CONTEXT_HP *mvc) +{ + const vp8_prob *const p = (const vp8_prob *) mvc; + int x = 0; + + if (vp8_read(r, p [mvpis_short_hp])) /* Large */ + { + int i = 0; + + do + { + x += vp8_read(r, p [MVPbits_hp + i]) << i; + } + while (++i < mvnum_short_bits_hp); + + i = mvlong_width_hp - 1; /* Skip bit 3, which is sometimes implicit */ + + do + { + x += vp8_read(r, p [MVPbits_hp + i]) << i; + } + while (--i > mvnum_short_bits_hp); + + if (!(x & ~((2<row = (short)(read_mvcomponent_hp(r, mvc)); + mv->col = (short)(read_mvcomponent_hp(r, ++mvc)); +#ifdef DEBUG_DEC_MV + int i; + printf("%d (hp): %d %d\n", dec_mvcount++, mv->row, mv->col); + //for (i=0; iprob[i]); printf("\n"); + //for (i=0; iprob[i]); printf("\n"); +#endif +} + +static void read_mvcontexts_hp(vp8_reader *bc, MV_CONTEXT_HP *mvc) +{ + int i = 0; + + do + { + const vp8_prob *up = vp8_mv_update_probs_hp[i].prob; + vp8_prob *p = (vp8_prob *)(mvc + i); + vp8_prob *const pstop = p + MVPcount_hp; + + do + { + if (vp8_read(bc, *up++)) + { + const vp8_prob x = (vp8_prob)vp8_read_literal(bc, 7); + + *p = x ? x << 1 : 1; + } + } + while (++p < pstop); + } + while (++i < 2); +} +#endif /* CONFIG_HIGH_PRECISION_MV */ + +// Read the referncence frame +static MV_REFERENCE_FRAME read_ref_frame( VP8D_COMP *pbi, + vp8_reader *const bc, + unsigned char segment_id ) +{ + MV_REFERENCE_FRAME ref_frame; + int seg_ref_active; + int seg_ref_count = 0; + + VP8_COMMON *const cm = & pbi->common; + MACROBLOCKD *const xd = &pbi->mb; + + seg_ref_active = segfeature_active( xd, + segment_id, + SEG_LVL_REF_FRAME ); + + // If segment coding enabled does the segment allow for more than one + // possible reference frame + if ( seg_ref_active ) + { + seg_ref_count = check_segref( xd, segment_id, INTRA_FRAME ) + + check_segref( xd, segment_id, LAST_FRAME ) + + check_segref( xd, segment_id, GOLDEN_FRAME ) + + check_segref( xd, segment_id, ALTREF_FRAME ); + } + + // Segment reference frame features not available or allows for + // multiple reference frame options + if ( !seg_ref_active || (seg_ref_count > 1) ) + { + // Values used in prediction model coding + unsigned char prediction_flag; + vp8_prob pred_prob; + MV_REFERENCE_FRAME pred_ref; + + // Get the context probability the prediction flag + pred_prob = get_pred_prob( cm, xd, PRED_REF ); + + // Read the prediction status flag + prediction_flag = (unsigned char)vp8_read( bc, pred_prob ); + + // Store the prediction flag. + set_pred_flag( xd, PRED_REF, prediction_flag ); + + // Get the predicted reference frame. + pred_ref = get_pred_ref( cm, xd ); + + // If correctly predicted then use the predicted value + if ( prediction_flag ) + { + ref_frame = pred_ref; + } + // else decode the explicitly coded value + else + { + vp8_prob mod_refprobs[PREDICTION_PROBS]; + vpx_memcpy( mod_refprobs, + cm->mod_refprobs[pred_ref], sizeof(mod_refprobs) ); + + // If segment coding enabled blank out options that cant occur by + // setting the branch probability to 0. + if ( seg_ref_active ) + { + mod_refprobs[INTRA_FRAME] *= + check_segref( xd, segment_id, INTRA_FRAME ); + mod_refprobs[LAST_FRAME] *= + check_segref( xd, segment_id, LAST_FRAME ); + mod_refprobs[GOLDEN_FRAME] *= + ( check_segref( xd, segment_id, GOLDEN_FRAME ) * + check_segref( xd, segment_id, ALTREF_FRAME ) ); + } + + // Default to INTRA_FRAME (value 0) + ref_frame = INTRA_FRAME; + + // Do we need to decode the Intra/Inter branch + if ( mod_refprobs[0] ) + ref_frame = (MV_REFERENCE_FRAME) vp8_read(bc, mod_refprobs[0]); + else + ref_frame ++; + + if (ref_frame) + { + // Do we need to decode the Last/Gf_Arf branch + if ( mod_refprobs[1] ) + ref_frame += vp8_read(bc, mod_refprobs[1]); + else + ref_frame++; + + if ( ref_frame > 1 ) + { + // Do we need to decode the GF/Arf branch + if ( mod_refprobs[2] ) + ref_frame += vp8_read(bc, mod_refprobs[2]); + else + { + if ( seg_ref_active ) + { + if ( (pred_ref == GOLDEN_FRAME) || + !check_segref( xd, segment_id, GOLDEN_FRAME) ) + { + ref_frame = ALTREF_FRAME; + } + else + ref_frame = GOLDEN_FRAME; + } + else + ref_frame = (pred_ref == GOLDEN_FRAME) + ? ALTREF_FRAME : GOLDEN_FRAME; + } + } + } + } + } + + // Segment reference frame features are enabled + else + { + // The reference frame for the mb is considered as correclty predicted + // if it is signaled at the segment level for the purposes of the + // common prediction model + set_pred_flag( xd, PRED_REF, 1 ); + ref_frame = get_pred_ref( cm, xd ); + } + + return (MV_REFERENCE_FRAME)ref_frame; +} static MB_PREDICTION_MODE read_mv_ref(vp8_reader *bc, const vp8_prob *p) { @@ -208,37 +501,39 @@ static const unsigned char mbsplit_fill_offset[4][16] = { - static void mb_mode_mv_init(VP8D_COMP *pbi) { + VP8_COMMON *const cm = & pbi->common; vp8_reader *const bc = & pbi->bc; MV_CONTEXT *const mvc = pbi->common.fc.mvc; - -#if CONFIG_ERROR_CONCEALMENT - /* Default is that no macroblock is corrupt, therefore we initialize - * mvs_corrupt_from_mb to something very big, which we can be sure is - * outside the frame. */ - pbi->mvs_corrupt_from_mb = UINT_MAX; +#if CONFIG_HIGH_PRECISION_MV + MV_CONTEXT_HP *const mvc_hp = pbi->common.fc.mvc_hp; + MACROBLOCKD *const xd = & pbi->mb; #endif + pbi->prob_skip_false = 0; if (pbi->common.mb_no_coeff_skip) pbi->prob_skip_false = (vp8_prob)vp8_read_literal(bc, 8); if(pbi->common.frame_type != KEY_FRAME) { - pbi->prob_intra = (vp8_prob)vp8_read_literal(bc, 8); - pbi->prob_last = (vp8_prob)vp8_read_literal(bc, 8); - pbi->prob_gf = (vp8_prob)vp8_read_literal(bc, 8); + // Decode the baseline probabilities for decoding reference frame + cm->prob_intra_coded = (vp8_prob)vp8_read_literal(bc, 8); + cm->prob_last_coded = (vp8_prob)vp8_read_literal(bc, 8); + cm->prob_gf_coded = (vp8_prob)vp8_read_literal(bc, 8); - if (vp8_read_bit(bc)) + // Computes a modified set of probabilities for use when reference + // frame prediction fails. + compute_mod_refprobs( cm ); + + pbi->common.comp_pred_mode = vp8_read(bc, 128); + if (cm->comp_pred_mode) + cm->comp_pred_mode += vp8_read(bc, 128); + if (cm->comp_pred_mode == HYBRID_PREDICTION) { - int i = 0; - - do - { - pbi->common.fc.ymode_prob[i] = (vp8_prob) vp8_read_literal(bc, 8); - } - while (++i < 4); + int i; + for ( i = 0; i < COMP_PRED_CONTEXTS; i++ ) + cm->prob_comppred[i] = (vp8_prob)vp8_read_literal(bc, 8); } if (vp8_read_bit(bc)) @@ -247,73 +542,191 @@ static void mb_mode_mv_init(VP8D_COMP *pbi) do { - pbi->common.fc.uv_mode_prob[i] = (vp8_prob) vp8_read_literal(bc, 8); + cm->fc.ymode_prob[i] = (vp8_prob) vp8_read_literal(bc, 8); } - while (++i < 3); + while (++i < VP8_YMODES-1); } +#if CONFIG_UVINTRA + //vp8_read_bit(bc); +#else + if (vp8_read_bit(bc)) + { + int i = 0; + do + { + cm->fc.uv_mode_prob[i] = (vp8_prob) vp8_read_literal(bc, 8); + } + while (++i < VP8_UV_MODES-1); + } +#endif /* CONFIG_UVINTRA */ +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + read_mvcontexts_hp(bc, mvc_hp); + else +#endif read_mvcontexts(bc, mvc); } } - -static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, - int mb_row, int mb_col) +// This function either reads the segment id for the current macroblock from +// the bitstream or if the value is temporally predicted asserts the predicted +// value +static void read_mb_segment_id ( VP8D_COMP *pbi, + int mb_row, int mb_col ) { vp8_reader *const bc = & pbi->bc; - MV_CONTEXT *const mvc = pbi->common.fc.mvc; - const int mis = pbi->common.mode_info_stride; + VP8_COMMON *const cm = & pbi->common; + MACROBLOCKD *const xd = & pbi->mb; + MODE_INFO *mi = xd->mode_info_context; + MB_MODE_INFO *mbmi = &mi->mbmi; + int index = mb_row * pbi->common.mb_cols + mb_col; + if (xd->segmentation_enabled) + { + if (xd->update_mb_segmentation_map) + { + // Is temporal coding of the segment id for this mb enabled. + if (cm->temporal_update) + { + // Get the context based probability for reading the + // prediction status flag + vp8_prob pred_prob = + get_pred_prob( cm, xd, PRED_SEG_ID ); + + // Read the prediction status flag + unsigned char seg_pred_flag = + (unsigned char)vp8_read(bc, pred_prob ); + + // Store the prediction flag. + set_pred_flag( xd, PRED_SEG_ID, seg_pred_flag ); + + // If the value is flagged as correctly predicted + // then use the predicted value + if ( seg_pred_flag ) + { + mbmi->segment_id = get_pred_mb_segid( cm, index ); + } + // Else .... decode it explicitly + else + { + vp8_read_mb_segid(bc, mbmi, xd ); + cm->last_frame_seg_map[index] = mbmi->segment_id; + } + + } + // Normal unpredicted coding mode + else + { + vp8_read_mb_segid(bc, mbmi, xd); + cm->last_frame_seg_map[index] = mbmi->segment_id; + } + } + } + else + { + // The encoder explicitly sets the segment_id to 0 + // when segmentation is disabled + mbmi->segment_id = 0; + } +} + +static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, + MODE_INFO *prev_mi, + int mb_row, int mb_col) +{ + VP8_COMMON *const cm = & pbi->common; + vp8_reader *const bc = & pbi->bc; + MV_CONTEXT *const mvc = pbi->common.fc.mvc; +#if CONFIG_HIGH_PRECISION_MV + MV_CONTEXT_HP *const mvc_hp = pbi->common.fc.mvc_hp; +#endif + const int mis = pbi->common.mode_info_stride; + MACROBLOCKD *const xd = & pbi->mb; + + int index = mb_row * pbi->common.mb_cols + mb_col; int_mv *const mv = & mbmi->mv; int mb_to_left_edge; int mb_to_right_edge; int mb_to_top_edge; int mb_to_bottom_edge; - mb_to_top_edge = pbi->mb.mb_to_top_edge; - mb_to_bottom_edge = pbi->mb.mb_to_bottom_edge; + mb_to_top_edge = xd->mb_to_top_edge; + mb_to_bottom_edge = xd->mb_to_bottom_edge; mb_to_top_edge -= LEFT_TOP_MARGIN; mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN; - mbmi->need_to_clamp_mvs = 0; + mbmi->second_ref_frame = 0; /* Distance of Mb to the various image edges. * These specified to 8th pel as they are always compared to MV values that are in 1/8th pel units */ - pbi->mb.mb_to_left_edge = + xd->mb_to_left_edge = mb_to_left_edge = -((mb_col * 16) << 3); mb_to_left_edge -= LEFT_TOP_MARGIN; - pbi->mb.mb_to_right_edge = + xd->mb_to_right_edge = mb_to_right_edge = ((pbi->common.mb_cols - 1 - mb_col) * 16) << 3; mb_to_right_edge += RIGHT_BOTTOM_MARGIN; - /* If required read in new segmentation data for this MB */ - if (pbi->mb.update_mb_segmentation_map) - vp8_read_mb_features(bc, mbmi, &pbi->mb); + // Make sure the MACROBLOCKD mode info pointer is pointed at the + // correct entry for the current macroblock. + xd->mode_info_context = mi; - /* Read the macroblock coeff skip flag if this feature is in use, else default to 0 */ - if (pbi->common.mb_no_coeff_skip) + // Read the macroblock segment id. + read_mb_segment_id ( pbi, mb_row, mb_col ); + + if ( pbi->common.mb_no_coeff_skip && + ( !segfeature_active( xd, + mbmi->segment_id, SEG_LVL_EOB ) || + (get_segdata( xd, mbmi->segment_id, SEG_LVL_EOB ) != 0) ) ) + { + // Read the macroblock coeff skip flag if this feature is in use, + // else default to 0 mbmi->mb_skip_coeff = vp8_read(bc, pbi->prob_skip_false); + } else - mbmi->mb_skip_coeff = 0; + { + if ( segfeature_active( xd, + mbmi->segment_id, SEG_LVL_EOB ) && + (get_segdata( xd, mbmi->segment_id, SEG_LVL_EOB ) == 0) ) + { + mbmi->mb_skip_coeff = 1; + } + else + mbmi->mb_skip_coeff = 0; + } - if ((mbmi->ref_frame = (MV_REFERENCE_FRAME) vp8_read(bc, pbi->prob_intra))) /* inter MB */ + // Read the reference frame + mbmi->ref_frame = read_ref_frame( pbi, bc, mbmi->segment_id ); + + // If reference frame is an Inter frame + if (mbmi->ref_frame) { int rct[4]; - vp8_prob mv_ref_p [VP8_MVREFS-1]; int_mv nearest, nearby, best_mv; + vp8_prob mv_ref_p [VP8_MVREFS-1]; - if (vp8_read(bc, pbi->prob_last)) + vp8_find_near_mvs(xd, mi, + prev_mi, + &nearest, &nearby, &best_mv, rct, + mbmi->ref_frame, pbi->common.ref_frame_sign_bias); + vp8_mv_ref_probs(&pbi->common, mv_ref_p, rct); + + // Is the segment level mode feature enabled for this segment + if ( segfeature_active( xd, mbmi->segment_id, SEG_LVL_MODE ) ) { - mbmi->ref_frame = (MV_REFERENCE_FRAME)((int)mbmi->ref_frame + (int)(1 + vp8_read(bc, pbi->prob_gf))); + mbmi->mode = + get_segdata( xd, mbmi->segment_id, SEG_LVL_MODE ); + } + else + { + mbmi->mode = read_mv_ref(bc, mv_ref_p); + + vp8_accum_mv_refs(&pbi->common, mbmi->mode, rct); } - vp8_find_near_mvs(&pbi->mb, mi, &nearest, &nearby, &best_mv, rct, mbmi->ref_frame, pbi->common.ref_frame_sign_bias); - - vp8_mv_ref_probs(mv_ref_p, rct); - mbmi->uv_mode = DC_PRED; - switch (mbmi->mode = read_mv_ref(bc, mv_ref_p)) + switch (mbmi->mode) { case SPLITMV: { @@ -322,6 +735,7 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, const int num_p = vp8_mbsplit_count [s]; int j = 0; + mbmi->need_to_clamp_mvs = 0; do /* for each subset j */ { int_mv leftmv, abovemv; @@ -337,6 +751,11 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, switch (sub_mv_ref(bc, vp8_sub_mv_ref_prob2 [mv_contz])) /*pc->fc.sub_mv_ref_prob))*/ { case NEW4X4: +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + read_mv_hp(bc, &blockmv.as_mv, (const MV_CONTEXT_HP *) mvc_hp); + else +#endif read_mv(bc, &blockmv.as_mv, (const MV_CONTEXT *) mvc); blockmv.as_mv.row += best_mv.as_mv.row; blockmv.as_mv.col += best_mv.as_mv.col; @@ -366,7 +785,7 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, break; } - mbmi->need_to_clamp_mvs = vp8_check_mv_bounds(&blockmv, + mbmi->need_to_clamp_mvs |= vp8_check_mv_bounds(&blockmv, mb_to_left_edge, mb_to_right_edge, mb_to_top_edge, @@ -414,6 +833,11 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, goto propagate_mv; case NEWMV: +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + read_mv_hp(bc, &mv->as_mv, (const MV_CONTEXT_HP *) mvc_hp); + else +#endif read_mv(bc, &mv->as_mv, (const MV_CONTEXT *) mvc); mv->as_mv.row += best_mv.as_mv.row; mv->as_mv.col += best_mv.as_mv.col; @@ -430,27 +854,57 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, mb_to_bottom_edge); propagate_mv: /* same MV throughout */ -#if CONFIG_ERROR_CONCEALMENT - if(pbi->ec_enabled) + + if ( cm->comp_pred_mode == COMP_PREDICTION_ONLY || + (cm->comp_pred_mode == HYBRID_PREDICTION && + vp8_read(bc, get_pred_prob( cm, xd, PRED_COMP ))) ) { - mi->bmi[ 0].mv.as_int = - mi->bmi[ 1].mv.as_int = - mi->bmi[ 2].mv.as_int = - mi->bmi[ 3].mv.as_int = - mi->bmi[ 4].mv.as_int = - mi->bmi[ 5].mv.as_int = - mi->bmi[ 6].mv.as_int = - mi->bmi[ 7].mv.as_int = - mi->bmi[ 8].mv.as_int = - mi->bmi[ 9].mv.as_int = - mi->bmi[10].mv.as_int = - mi->bmi[11].mv.as_int = - mi->bmi[12].mv.as_int = - mi->bmi[13].mv.as_int = - mi->bmi[14].mv.as_int = - mi->bmi[15].mv.as_int = mv->as_int; + mbmi->second_ref_frame = mbmi->ref_frame + 1; + if (mbmi->second_ref_frame == 4) + mbmi->second_ref_frame = 1; } + if (mbmi->second_ref_frame) + { + vp8_find_near_mvs(xd, mi, + prev_mi, + &nearest, &nearby, &best_mv, rct, + (int)mbmi->second_ref_frame, + pbi->common.ref_frame_sign_bias); + switch (mbmi->mode) { + case ZEROMV: + mbmi->second_mv.as_int = 0; + break; + case NEARMV: + mbmi->second_mv.as_int = nearby.as_int; + vp8_clamp_mv(&mbmi->second_mv, mb_to_left_edge, mb_to_right_edge, + mb_to_top_edge, mb_to_bottom_edge); + break; + case NEARESTMV: + mbmi->second_mv.as_int = nearest.as_int; + vp8_clamp_mv(&mbmi->second_mv, mb_to_left_edge, mb_to_right_edge, + mb_to_top_edge, mb_to_bottom_edge); + break; + case NEWMV: +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + read_mv_hp(bc, &mbmi->second_mv.as_mv, + (const MV_CONTEXT_HP *) mvc_hp); + else #endif + read_mv(bc, &mbmi->second_mv.as_mv, (const MV_CONTEXT *) mvc); + mbmi->second_mv.as_mv.row += best_mv.as_mv.row; + mbmi->second_mv.as_mv.col += best_mv.as_mv.col; + mbmi->need_to_clamp_mvs |= vp8_check_mv_bounds(&mbmi->second_mv, + mb_to_left_edge, + mb_to_right_edge, + mb_to_top_edge, + mb_to_bottom_edge); + break; + default: + break; + } + } + break; default:; #if CONFIG_DEBUG @@ -463,18 +917,73 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, /* required for left and above block mv */ mbmi->mv.as_int = 0; - /* MB is intra coded */ - if ((mbmi->mode = (MB_PREDICTION_MODE) vp8_read_ymode(bc, pbi->common.fc.ymode_prob)) == B_PRED) + if ( segfeature_active( xd, mbmi->segment_id, SEG_LVL_MODE ) ) + mbmi->mode = (MB_PREDICTION_MODE) + get_segdata( xd, mbmi->segment_id, SEG_LVL_MODE ); + else + { + mbmi->mode = (MB_PREDICTION_MODE) + vp8_read_ymode(bc, pbi->common.fc.ymode_prob); + } +#if CONFIG_COMP_INTRA_PRED + mbmi->second_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); +#endif + + // If MB mode is BPRED read the block modes + if (mbmi->mode == B_PRED) { int j = 0; +#if CONFIG_COMP_INTRA_PRED + int use_comp_pred = vp8_read(bc, 128); +#endif do { - mi->bmi[j].as_mode = (B_PREDICTION_MODE)vp8_read_bmode(bc, pbi->common.fc.bmode_prob); + mi->bmi[j].as_mode.first = (B_PREDICTION_MODE)vp8_read_bmode(bc, pbi->common.fc.bmode_prob); +#if CONFIG_COMP_INTRA_PRED + if (use_comp_pred) + { + mi->bmi[j].as_mode.second = (B_PREDICTION_MODE)vp8_read_bmode(bc, pbi->common.fc.bmode_prob); + } + else + { + mi->bmi[j].as_mode.second = (B_PREDICTION_MODE) (B_DC_PRED - 1); + } +#endif } while (++j < 16); } - mbmi->uv_mode = (MB_PREDICTION_MODE)vp8_read_uv_mode(bc, pbi->common.fc.uv_mode_prob); + if(mbmi->mode == I8X8_PRED) + { + int i; + int mode8x8; + for(i=0;i<4;i++) + { + int ib = vp8_i8x8_block[i]; + mode8x8 = vp8_read_i8x8_mode(bc, pbi->common.i8x8_mode_prob); + mi->bmi[ib+0].as_mode.first= mode8x8; + mi->bmi[ib+1].as_mode.first= mode8x8; + mi->bmi[ib+4].as_mode.first= mode8x8; + mi->bmi[ib+5].as_mode.first= mode8x8; +#if CONFIG_COMP_INTRA_PRED + mi->bmi[ib+0].as_mode.second= (MB_PREDICTION_MODE) (DC_PRED - 1); + mi->bmi[ib+1].as_mode.second= (MB_PREDICTION_MODE) (DC_PRED - 1); + mi->bmi[ib+4].as_mode.second= (MB_PREDICTION_MODE) (DC_PRED - 1); + mi->bmi[ib+5].as_mode.second= (MB_PREDICTION_MODE) (DC_PRED - 1); +#endif + } + } + else +#if CONFIG_UVINTRA + mbmi->uv_mode = (MB_PREDICTION_MODE)vp8_read_uv_mode(bc, + pbi->common.fc.uv_mode_prob[mbmi->mode]); +#else + mbmi->uv_mode = (MB_PREDICTION_MODE)vp8_read_uv_mode(bc, + pbi->common.fc.uv_mode_prob); +#endif /*CONFIG_UVINTRA*/ +#if CONFIG_COMP_INTRA_PRED + mbmi->second_uv_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); +#endif } } @@ -482,10 +991,26 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, void vp8_decode_mode_mvs(VP8D_COMP *pbi) { MODE_INFO *mi = pbi->common.mi; + + MODE_INFO *prev_mi = pbi->common.prev_mi; + int mb_row = -1; +#if 0 + FILE *statsfile; + statsfile = fopen("decsegmap.stt", "a"); + fprintf(statsfile, "\n" ); +#endif + mb_mode_mv_init(pbi); +#if CONFIG_QIMODE + if(pbi->common.frame_type==KEY_FRAME && !pbi->common.kf_ymode_probs_update) + { + pbi->common.kf_ymode_probs_index = vp8_read_literal(&pbi->bc, 3); + } +#endif + while (++mb_row < pbi->common.mb_rows) { int mb_col = -1; @@ -500,34 +1025,51 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi) mb_to_bottom_edge = ((pbi->common.mb_rows - 1 - mb_row) * 16) << 3; mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN; +#if 0 + fprintf(statsfile, "\n" ); +#endif + while (++mb_col < pbi->common.mb_cols) { -#if CONFIG_ERROR_CONCEALMENT - int mb_num = mb_row * pbi->common.mb_cols + mb_col; -#endif /*read_mb_modes_mv(pbi, xd->mode_info_context, &xd->mode_info_context->mbmi, mb_row, mb_col);*/ if(pbi->common.frame_type == KEY_FRAME) vp8_kfread_modes(pbi, mi, mb_row, mb_col); else - read_mb_modes_mv(pbi, mi, &mi->mbmi, mb_row, mb_col); + read_mb_modes_mv(pbi, mi, &mi->mbmi, + prev_mi, + mb_row, mb_col); -#if CONFIG_ERROR_CONCEALMENT - /* look for corruption. set mvs_corrupt_from_mb to the current - * mb_num if the frame is corrupt from this macroblock. */ - if (vp8dx_bool_error(&pbi->bc) && mb_num < pbi->mvs_corrupt_from_mb) + //printf("%3d", mi->mbmi.mode); + + /* + if(pbi->common.current_video_frame==7) { - pbi->mvs_corrupt_from_mb = mb_num; - /* no need to continue since the partition is corrupt from - * here on. - */ - return; - } -#endif + FILE *fmode=fopen("kfmode.txt", "a"); + fprintf(fmode, "%3d:%3d:%d\n",mb_row, mb_col, mi->mbmi.mode); + fclose(fmode); + }*/ + /* + if(mi->mbmi.mode==I8X8_PRED) + { + printf("F%3d:%d:%d\n", pbi->common.current_video_frame, mb_row, mb_col); + } + */ +#if 0 + fprintf(statsfile, "%2d%2d%2d ", + mi->mbmi.segment_id, mi->mbmi.ref_frame, mi->mbmi.mode ); +#endif + prev_mi++; mi++; /* next macroblock */ } - + // printf("\n"); + prev_mi++; mi++; /* skip left predictor each row */ } -} +#if 0 + fclose(statsfile); +#endif + + +} diff --git a/vp8/decoder/decoderthreading.h b/vp8/decoder/decoderthreading.h deleted file mode 100644 index 60c39d1e1..000000000 --- a/vp8/decoder/decoderthreading.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - - - - -#ifndef _DECODER_THREADING_H -#define _DECODER_THREADING_H - -#if CONFIG_MULTITHREAD -extern void vp8mt_decode_mb_rows(VP8D_COMP *pbi, MACROBLOCKD *xd); -extern void vp8_decoder_remove_threads(VP8D_COMP *pbi); -extern void vp8_decoder_create_threads(VP8D_COMP *pbi); -extern void vp8mt_alloc_temp_buffers(VP8D_COMP *pbi, int width, int prev_mb_rows); -extern void vp8mt_de_alloc_temp_buffers(VP8D_COMP *pbi, int mb_rows); -#endif - -#endif diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c index 6bbc71f79..29b9e9b85 100644 --- a/vp8/decoder/decodframe.c +++ b/vp8/decoder/decodframe.c @@ -27,19 +27,22 @@ #include "decodemv.h" #include "vp8/common/extend.h" -#if CONFIG_ERROR_CONCEALMENT -#include "error_concealment.h" -#endif +#include "vp8/common/modecont.h" #include "vpx_mem/vpx_mem.h" #include "vp8/common/idct.h" #include "dequantize.h" -#include "vp8/common/threading.h" -#include "decoderthreading.h" #include "dboolhuff.h" +#include "vp8/common/seg_common.h" + #include #include + +#ifdef DEC_DEBUG +int dec_debug = 0; +#endif + void vp8cx_init_de_quantizer(VP8D_COMP *pbi) { int i; @@ -68,20 +71,21 @@ void mb_init_dequantizer(VP8D_COMP *pbi, MACROBLOCKD *xd) { int i; int QIndex; - MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi; VP8_COMMON *const pc = & pbi->common; + int segment_id = xd->mode_info_context->mbmi.segment_id; - /* Decide whether to use the default or alternate baseline Q value. */ - if (xd->segmentation_enabled) + // Set the Q baseline allowing for any segment level adjustment + if ( segfeature_active( xd, segment_id, SEG_LVL_ALT_Q ) ) { /* Abs Value */ - if (xd->mb_segement_abs_delta == SEGMENT_ABSDATA) - QIndex = xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id]; + if (xd->mb_segment_abs_delta == SEGMENT_ABSDATA) + QIndex = get_segdata( xd, segment_id, SEG_LVL_ALT_Q ); /* Delta Value */ else { - QIndex = pc->base_qindex + xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id]; + QIndex = pc->base_qindex + + get_segdata( xd, segment_id, SEG_LVL_ALT_Q ); QIndex = (QIndex >= 0) ? ((QIndex <= MAXQ) ? QIndex : MAXQ) : 0; /* Clamp to valid range */ } } @@ -125,32 +129,85 @@ static void skip_recon_mb(VP8D_COMP *pbi, MACROBLOCKD *xd) vp8_build_inter16x16_predictors_mb(xd, xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, xd->dst.y_stride, xd->dst.uv_stride); + + if (xd->mode_info_context->mbmi.second_ref_frame) + { + vp8_build_2nd_inter16x16_predictors_mb(xd, xd->dst.y_buffer, + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.y_stride, xd->dst.uv_stride); + } } +#ifdef DEC_DEBUG + if (dec_debug) { + int i, j; + printf("Generating predictors\n"); + for (i=0;i<16;i++) { + for (j=0;j<16;j++) printf("%3d ", xd->dst.y_buffer[i*xd->dst.y_stride+j]); + printf("\n"); + } + } +#endif + } +extern const int vp8_i8x8_block[4]; static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, unsigned int mb_idx) { int eobtotal = 0; - int throw_residual = 0; MB_PREDICTION_MODE mode; int i; + int tx_type; + if( pbi->common.txfm_mode==ONLY_4X4 ) + { + xd->mode_info_context->mbmi.txfm_size = TX_4X4; + } + else if( pbi->common.txfm_mode == ALLOW_8X8 ) + { + if( xd->mode_info_context->mbmi.mode ==B_PRED + ||xd->mode_info_context->mbmi.mode ==I8X8_PRED + ||xd->mode_info_context->mbmi.mode ==SPLITMV) + xd->mode_info_context->mbmi.txfm_size = TX_4X4; + else + xd->mode_info_context->mbmi.txfm_size = TX_8X8; + } + + tx_type = xd->mode_info_context->mbmi.txfm_size; + if (xd->mode_info_context->mbmi.mb_skip_coeff) { vp8_reset_mb_tokens_context(xd); } else if (!vp8dx_bool_error(xd->current_bc)) { - eobtotal = vp8_decode_mb_tokens(pbi, xd); + for(i = 0; i < 25; i++) + { + xd->block[i].eob = 0; + xd->eobs[i] = 0; + } + if ( tx_type == TX_8X8 ) + eobtotal = vp8_decode_mb_tokens_8x8(pbi, xd); + else + eobtotal = vp8_decode_mb_tokens(pbi, xd); +#ifdef DEC_DEBUG + if (dec_debug) { + printf("\nTokens (%d)\n", eobtotal); + for (i =0; i<400; i++) { + printf("%3d ", xd->qcoeff[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + } +#endif } - - mode = xd->mode_info_context->mbmi.mode; - if (eobtotal == 0 && mode != B_PRED && mode != SPLITMV && - !vp8dx_bool_error(xd->current_bc)) + if (eobtotal == 0 && mode != B_PRED && mode != SPLITMV + && mode != I8X8_PRED + &&!vp8dx_bool_error(xd->current_bc) + ) { /* Special case: Force the loopfilter to skip when eobtotal and * mb_skip_coeff are zero. @@ -161,57 +218,114 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, return; } +#ifdef DEC_DEBUG + if (dec_debug) { + int i, j; + printf("Generating predictors\n"); + for (i=0;i<16;i++) { + for (j=0;j<16;j++) printf("%3d ", xd->dst.y_buffer[i*xd->dst.y_stride+j]); + printf("\n"); + } + } +#endif + + + if (xd->segmentation_enabled) mb_init_dequantizer(pbi, xd); /* do prediction */ if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) { - RECON_INVOKE(&pbi->common.rtcd.recon, build_intra_predictors_mbuv)(xd); - - if (mode != B_PRED) + if(mode != I8X8_PRED) { - RECON_INVOKE(&pbi->common.rtcd.recon, - build_intra_predictors_mby)(xd); - } else { - vp8_intra_prediction_down_copy(xd); + RECON_INVOKE(&pbi->common.rtcd.recon, build_intra_predictors_mbuv)(xd); + if (mode != B_PRED) + { + RECON_INVOKE(&pbi->common.rtcd.recon, + build_intra_predictors_mby)(xd); + } + else + { + vp8_intra_prediction_down_copy(xd); + } } } else { vp8_build_inter_predictors_mb(xd); } - /* When we have independent partitions we can apply residual even - * though other partitions within the frame are corrupt. - */ - throw_residual = (!pbi->independent_partitions && - pbi->frame_corrupt_residual); - throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc)); - -#if CONFIG_ERROR_CONCEALMENT - if (pbi->ec_active && - (mb_idx >= pbi->mvs_corrupt_from_mb || throw_residual)) - { - /* MB with corrupt residuals or corrupt mode/motion vectors. - * Better to use the predictor as reconstruction. - */ - pbi->frame_corrupt_residual = 1; - vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff)); - vp8_conceal_corrupt_mb(xd); - return; - } -#endif /* dequantization and idct */ - if (mode == B_PRED) + if (mode == I8X8_PRED) + { + for (i = 0; i < 4; i++) + { + int ib = vp8_i8x8_block[i]; + const int iblock[4]={0,1,4,5}; + int j; + int i8x8mode; + BLOCKD *b; + + b = &xd->block[ib]; + i8x8mode= b->bmi.as_mode.first; + RECON_INVOKE(RTCD_VTABLE(recon), intra8x8_predict) + (b, i8x8mode, b->predictor); + + for(j = 0; j < 4; j++) + { + b = &xd->block[ib+iblock[j]]; + if (xd->eobs[ib+iblock[j]] > 1) + { + DEQUANT_INVOKE(&pbi->dequant, idct_add) + (b->qcoeff, b->dequant, b->predictor, + *(b->base_dst) + b->dst, 16, b->dst_stride); + } + else + { + IDCT_INVOKE(RTCD_VTABLE(idct), idct1_scalar_add) + (b->qcoeff[0] * b->dequant[0], b->predictor, + *(b->base_dst) + b->dst, 16, b->dst_stride); + ((int *)b->qcoeff)[0] = 0; + } + } + + b = &xd->block[16+i]; + RECON_INVOKE(RTCD_VTABLE(recon), intra_uv4x4_predict) + (b, i8x8mode, b->predictor); + DEQUANT_INVOKE(&pbi->dequant, idct_add) + (b->qcoeff, b->dequant, b->predictor, + *(b->base_dst) + b->dst, 8, b->dst_stride); + b = &xd->block[20+i]; + RECON_INVOKE(RTCD_VTABLE(recon), intra_uv4x4_predict) + (b, i8x8mode, b->predictor); + DEQUANT_INVOKE(&pbi->dequant, idct_add) + (b->qcoeff, b->dequant, b->predictor, + *(b->base_dst) + b->dst, 8, b->dst_stride); + } + } + else if (mode == B_PRED) { for (i = 0; i < 16; i++) { BLOCKD *b = &xd->block[i]; - int b_mode = xd->mode_info_context->bmi[i].as_mode; + int b_mode = xd->mode_info_context->bmi[i].as_mode.first; +#if CONFIG_COMP_INTRA_PRED + int b_mode2 = xd->mode_info_context->bmi[i].as_mode.second; + if (b_mode2 == (B_PREDICTION_MODE) (B_DC_PRED - 1)) + { +#endif RECON_INVOKE(RTCD_VTABLE(recon), intra4x4_predict) (b, b_mode, b->predictor); +#if CONFIG_COMP_INTRA_PRED + } + else + { + RECON_INVOKE(RTCD_VTABLE(recon), comp_intra4x4_predict) + (b, b_mode, b_mode2, b->predictor); + } +#endif if (xd->eobs[i] > 1) { @@ -227,26 +341,35 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, ((int *)b->qcoeff)[0] = 0; } } - } else if (mode == SPLITMV) { DEQUANT_INVOKE (&pbi->dequant, idct_add_y_block) - (xd->qcoeff, xd->block[0].dequant, - xd->predictor, xd->dst.y_buffer, - xd->dst.y_stride, xd->eobs); + (xd->qcoeff, xd->block[0].dequant, + xd->predictor, xd->dst.y_buffer, + xd->dst.y_stride, xd->eobs); } else { BLOCKD *b = &xd->block[24]; - DEQUANT_INVOKE(&pbi->dequant, block)(b); - /* do 2nd order transform on the dc block */ - if (xd->eobs[24] > 1) + if( tx_type == TX_8X8 ) { - IDCT_INVOKE(RTCD_VTABLE(idct), iwalsh16)(&b->dqcoeff[0], b->diff); - ((int *)b->qcoeff)[0] = 0; + DEQUANT_INVOKE(&pbi->dequant, block_2x2)(b); +#ifdef DEC_DEBUG + if (dec_debug) + { + int j; + printf("DQcoeff Haar\n"); + for (j=0;j<16;j++) { + printf("%d ", b->dqcoeff[j]); + } + printf("\n"); + } +#endif + IDCT_INVOKE(RTCD_VTABLE(idct), ihaar2)(&b->dqcoeff[0], b->diff, 8); + ((int *)b->qcoeff)[0] = 0;//2nd order block are set to 0 after inverse transform ((int *)b->qcoeff)[1] = 0; ((int *)b->qcoeff)[2] = 0; ((int *)b->qcoeff)[3] = 0; @@ -254,23 +377,50 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, ((int *)b->qcoeff)[5] = 0; ((int *)b->qcoeff)[6] = 0; ((int *)b->qcoeff)[7] = 0; + DEQUANT_INVOKE (&pbi->dequant, dc_idct_add_y_block_8x8) + (xd->qcoeff, xd->block[0].dequant, + xd->predictor, xd->dst.y_buffer, + xd->dst.y_stride, xd->eobs, xd->block[24].diff, xd); } else { - IDCT_INVOKE(RTCD_VTABLE(idct), iwalsh1)(&b->dqcoeff[0], b->diff); - ((int *)b->qcoeff)[0] = 0; - } + DEQUANT_INVOKE(&pbi->dequant, block)(b); + if (xd->eobs[24] > 1) + { + IDCT_INVOKE(RTCD_VTABLE(idct), iwalsh16)(&b->dqcoeff[0], b->diff); + ((int *)b->qcoeff)[0] = 0; + ((int *)b->qcoeff)[1] = 0; + ((int *)b->qcoeff)[2] = 0; + ((int *)b->qcoeff)[3] = 0; + ((int *)b->qcoeff)[4] = 0; + ((int *)b->qcoeff)[5] = 0; + ((int *)b->qcoeff)[6] = 0; + ((int *)b->qcoeff)[7] = 0; + } + else + { + IDCT_INVOKE(RTCD_VTABLE(idct), iwalsh1)(&b->dqcoeff[0], b->diff); + ((int *)b->qcoeff)[0] = 0; + } - DEQUANT_INVOKE (&pbi->dequant, dc_idct_add_y_block) - (xd->qcoeff, xd->block[0].dequant, - xd->predictor, xd->dst.y_buffer, - xd->dst.y_stride, xd->eobs, xd->block[24].diff); + DEQUANT_INVOKE (&pbi->dequant, dc_idct_add_y_block) + (xd->qcoeff, xd->block[0].dequant, + xd->predictor, xd->dst.y_buffer, + xd->dst.y_stride, xd->eobs, xd->block[24].diff); + } } - DEQUANT_INVOKE (&pbi->dequant, idct_add_uv_block) - (xd->qcoeff+16*16, xd->block[16].dequant, - xd->predictor+16*16, xd->dst.u_buffer, xd->dst.v_buffer, - xd->dst.uv_stride, xd->eobs+16); + if( tx_type == TX_8X8 ) + DEQUANT_INVOKE (&pbi->dequant, idct_add_uv_block_8x8)// + (xd->qcoeff+16*16, xd->block[16].dequant, + xd->predictor+16*16, xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride, xd->eobs+16, xd);// + else if(xd->mode_info_context->mbmi.mode!=I8X8_PRED) + DEQUANT_INVOKE (&pbi->dequant, idct_add_uv_block) + (xd->qcoeff+16*16, xd->block[16].dequant, + xd->predictor+16*16, xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride, xd->eobs+16); + } @@ -298,8 +448,6 @@ static int get_delta_q(vp8_reader *bc, int prev, int *q_update) FILE *vpxlog = 0; #endif - - static void decode_mb_row(VP8D_COMP *pbi, VP8_COMMON *pc, int mb_row, MACROBLOCKD *xd) { @@ -330,31 +478,7 @@ decode_mb_row(VP8D_COMP *pbi, VP8_COMMON *pc, int mb_row, MACROBLOCKD *xd) xd->mb_to_left_edge = -((mb_col * 16) << 3); xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; -#if CONFIG_ERROR_CONCEALMENT - { - int corrupt_residual = (!pbi->independent_partitions && - pbi->frame_corrupt_residual) || - vp8dx_bool_error(xd->current_bc); - if (pbi->ec_active && - xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME && - corrupt_residual) - { - /* We have an intra block with corrupt coefficients, better to - * conceal with an inter block. Interpolate MVs from neighboring - * MBs. - * - * Note that for the first mb with corrupt residual in a frame, - * we might not discover that before decoding the residual. That - * happens after this check, and therefore no inter concealment - * will be done. - */ - vp8_interpolate_motion(xd, - mb_row, mb_col, - pc->mb_rows, pc->mb_cols, - pc->mode_info_stride); - } - } -#endif + update_blockd_bmi(xd); xd->dst.y_buffer = pc->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset; xd->dst.u_buffer = pc->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset; @@ -374,17 +498,36 @@ decode_mb_row(VP8D_COMP *pbi, VP8_COMMON *pc, int mb_row, MACROBLOCKD *xd) xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset; xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset; + if (xd->mode_info_context->mbmi.second_ref_frame) + { + int second_ref_fb_idx; + + /* Select the appropriate reference frame for this MB */ + if (xd->mode_info_context->mbmi.second_ref_frame == LAST_FRAME) + second_ref_fb_idx = pc->lst_fb_idx; + else if (xd->mode_info_context->mbmi.second_ref_frame == GOLDEN_FRAME) + second_ref_fb_idx = pc->gld_fb_idx; + else + second_ref_fb_idx = pc->alt_fb_idx; + + xd->second_pre.y_buffer = pc->yv12_fb[second_ref_fb_idx].y_buffer + recon_yoffset; + xd->second_pre.u_buffer = pc->yv12_fb[second_ref_fb_idx].u_buffer + recon_uvoffset; + xd->second_pre.v_buffer = pc->yv12_fb[second_ref_fb_idx].v_buffer + recon_uvoffset; + } + if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME) { /* propagate errors from reference frames */ xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted; } +#ifdef DEC_DEBUG + dec_debug = (pc->current_video_frame==1 && mb_row==4 && mb_col==0); +#endif decode_macroblock(pbi, xd, mb_row * pc->mb_cols + mb_col); /* check if the boolean decoder has suffered an error */ xd->corrupted |= vp8dx_bool_error(xd->current_bc); - recon_yoffset += 16; recon_uvoffset += 8; @@ -403,7 +546,6 @@ decode_mb_row(VP8D_COMP *pbi, VP8_COMMON *pc, int mb_row, MACROBLOCKD *xd) ++xd->mode_info_context; /* skip prediction column */ } - static unsigned int read_partition_size(const unsigned char *cx_size) { const unsigned int size = @@ -411,49 +553,6 @@ static unsigned int read_partition_size(const unsigned char *cx_size) return size; } -static void setup_token_decoder_partition_input(VP8D_COMP *pbi) -{ - vp8_reader *bool_decoder = &pbi->bc2; - int part_idx = 1; - int num_token_partitions; - - TOKEN_PARTITION multi_token_partition = - (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2); - if (!vp8dx_bool_error(&pbi->bc)) - pbi->common.multi_token_partition = multi_token_partition; - num_token_partitions = 1 << pbi->common.multi_token_partition; - if (num_token_partitions + 1 > pbi->num_partitions) - vpx_internal_error(&pbi->common.error, VPX_CODEC_CORRUPT_FRAME, - "Partitions missing"); - assert(vp8dx_bool_error(&pbi->bc) || - multi_token_partition == pbi->common.multi_token_partition); - if (pbi->num_partitions > 2) - { - CHECK_MEM_ERROR(pbi->mbc, vpx_malloc((pbi->num_partitions - 1) * - sizeof(vp8_reader))); - bool_decoder = pbi->mbc; - } - - for (; part_idx < pbi->num_partitions; ++part_idx) - { - if (vp8dx_start_decode(bool_decoder, - pbi->partitions[part_idx], - pbi->partition_sizes[part_idx])) - vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR, - "Failed to allocate bool decoder %d", - part_idx); - - bool_decoder++; - } - -#if CONFIG_MULTITHREAD - /* Clamp number of decoder threads */ - if (pbi->decoding_thread_count > pbi->num_partitions - 1) - pbi->decoding_thread_count = pbi->num_partitions - 1; -#endif -} - - static int read_is_valid(const unsigned char *start, size_t len, const unsigned char *end) @@ -465,99 +564,37 @@ static int read_is_valid(const unsigned char *start, static void setup_token_decoder(VP8D_COMP *pbi, const unsigned char *cx_data) { - int num_part; - int i; VP8_COMMON *pc = &pbi->common; const unsigned char *user_data_end = pbi->Source + pbi->source_sz; vp8_reader *bool_decoder; const unsigned char *partition; - /* Parse number of token partitions to use */ - const TOKEN_PARTITION multi_token_partition = - (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2); - /* Only update the multi_token_partition field if we are sure the value - * is correct. */ - if (!pbi->ec_active || !vp8dx_bool_error(&pbi->bc)) - pc->multi_token_partition = multi_token_partition; + ptrdiff_t partition_size; + ptrdiff_t bytes_left; - num_part = 1 << pc->multi_token_partition; + // Dummy read for now + vp8_read_literal(&pbi->bc, 2); - /* Set up pointers to the first partition */ + // Set up pointers to token partition partition = cx_data; bool_decoder = &pbi->bc2; + bytes_left = user_data_end - partition; + partition_size = bytes_left; - if (num_part > 1) + /* Validate the calculated partition length. If the buffer + * described by the partition can't be fully read, then restrict + * it to the portion that can be (for EC mode) or throw an error. + */ + if (!read_is_valid(partition, partition_size, user_data_end)) { - CHECK_MEM_ERROR(pbi->mbc, vpx_malloc(num_part * sizeof(vp8_reader))); - bool_decoder = pbi->mbc; - partition += 3 * (num_part - 1); + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Truncated packet or corrupt partition " + "%d length", 1); } - for (i = 0; i < num_part; i++) - { - const unsigned char *partition_size_ptr = cx_data + i * 3; - ptrdiff_t partition_size, bytes_left; - - bytes_left = user_data_end - partition; - - /* Calculate the length of this partition. The last partition - * size is implicit. If the partition size can't be read, then - * either use the remaining data in the buffer (for EC mode) - * or throw an error. - */ - if (i < num_part - 1) - { - if (read_is_valid(partition_size_ptr, 3, user_data_end)) - partition_size = read_partition_size(partition_size_ptr); - else if (pbi->ec_active) - partition_size = bytes_left; - else - vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, - "Truncated partition size data"); - } - else - partition_size = bytes_left; - - /* Validate the calculated partition length. If the buffer - * described by the partition can't be fully read, then restrict - * it to the portion that can be (for EC mode) or throw an error. - */ - if (!read_is_valid(partition, partition_size, user_data_end)) - { - if (pbi->ec_active) - partition_size = bytes_left; - else - vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, - "Truncated packet or corrupt partition " - "%d length", i + 1); - } - - if (vp8dx_start_decode(bool_decoder, partition, partition_size)) - vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, - "Failed to allocate bool decoder %d", i + 1); - - /* Advance to the next partition */ - partition += partition_size; - bool_decoder++; - } - -#if CONFIG_MULTITHREAD - /* Clamp number of decoder threads */ - if (pbi->decoding_thread_count > num_part - 1) - pbi->decoding_thread_count = num_part - 1; -#endif -} - - -static void stop_token_decoder(VP8D_COMP *pbi) -{ - VP8_COMMON *pc = &pbi->common; - - if (pc->multi_token_partition != ONE_PARTITION) - { - vpx_free(pbi->mbc); - pbi->mbc = NULL; - } + if (vp8dx_start_decode(bool_decoder, partition, partition_size)) + vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, + "Failed to allocate bool decoder %d", 1); } static void init_frame(VP8D_COMP *pbi) @@ -569,15 +606,21 @@ static void init_frame(VP8D_COMP *pbi) { /* Various keyframe initializations */ vpx_memcpy(pc->fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context)); +#if CONFIG_HIGH_PRECISION_MV + vpx_memcpy(pc->fc.mvc_hp, vp8_default_mv_context_hp, + sizeof(vp8_default_mv_context_hp)); +#endif vp8_init_mbmode_probs(pc); vp8_default_coef_probs(pc); vp8_kf_default_bmode_probs(pc->kf_bmode_prob); - /* reset the segment feature data to 0 with delta coding (Default state). */ - vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data)); - xd->mb_segement_abs_delta = SEGMENT_DELTADATA; + // Reset the segment feature data to the default stats: + // Features disabled, 0, with delta coding (Default state). + clearall_segfeatures( xd ); + + xd->mb_segment_abs_delta = SEGMENT_DELTADATA; /* reset the mode ref deltasa for loop filter */ vpx_memset(xd->ref_lf_deltas, 0, sizeof(xd->ref_lf_deltas)); @@ -594,9 +637,18 @@ static void init_frame(VP8D_COMP *pbi) */ pc->ref_frame_sign_bias[GOLDEN_FRAME] = 0; pc->ref_frame_sign_bias[ALTREF_FRAME] = 0; + + vpx_memcpy(&pc->lfc, &pc->fc, sizeof(pc->fc)); + vpx_memcpy(&pc->lfc_a, &pc->fc, sizeof(pc->fc)); + + vp8_init_mode_contexts(&pbi->common); + vpx_memcpy( pbi->common.vp8_mode_contexts, + pbi->common.mode_context, + sizeof(pbi->common.mode_context)); } else { + if (!pc->use_bilinear_mc_filter) pc->mcomp_filter_type = SIXTAP; else @@ -609,6 +661,8 @@ static void init_frame(VP8D_COMP *pbi) xd->subpixel_predict8x4 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap8x4); xd->subpixel_predict8x8 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap8x8); xd->subpixel_predict16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap16x16); + xd->subpixel_predict_avg8x8 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap_avg8x8); + xd->subpixel_predict_avg16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap_avg16x16); } else { @@ -616,10 +670,9 @@ static void init_frame(VP8D_COMP *pbi) xd->subpixel_predict8x4 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear8x4); xd->subpixel_predict8x8 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear8x8); xd->subpixel_predict16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear16x16); + xd->subpixel_predict_avg8x8 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear_avg8x8); + xd->subpixel_predict_avg16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear_avg16x16); } - - if (pbi->decoded_key_frame && pbi->ec_enabled && !pbi->ec_active) - pbi->ec_active = 1; } xd->left_context = &pc->left_context; @@ -646,15 +699,7 @@ int vp8_decode_frame(VP8D_COMP *pbi) int mb_row; int i, j, k, l; - const int *const mb_feature_data_bits = vp8_mb_feature_data_bits; int corrupt_tokens = 0; - int prev_independent_partitions = pbi->independent_partitions; - - if (pbi->input_partition) - { - data = pbi->partitions[0]; - data_end = data + pbi->partition_sizes[0]; - } /* start with no corruption of current frame */ xd->corrupted = 0; @@ -662,21 +707,8 @@ int vp8_decode_frame(VP8D_COMP *pbi) if (data_end - data < 3) { - if (pbi->ec_active) - { - /* Declare the missing frame as an inter frame since it will - be handled as an inter frame when we have estimated its - motion vectors. */ - pc->frame_type = INTER_FRAME; - pc->version = 0; - pc->show_frame = 1; - first_partition_length_in_bytes = 0; - } - else - { - vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, - "Truncated packet"); - } + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Truncated packet"); } else { @@ -686,7 +718,7 @@ int vp8_decode_frame(VP8D_COMP *pbi) first_partition_length_in_bytes = (data[0] | (data[1] << 8) | (data[2] << 16)) >> 5; - if (!pbi->ec_active && (data + first_partition_length_in_bytes > data_end + if ((data + first_partition_length_in_bytes > data_end || data + first_partition_length_in_bytes < data)) vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet or corrupt partition 0 length"); @@ -704,7 +736,7 @@ int vp8_decode_frame(VP8D_COMP *pbi) /* When error concealment is enabled we should only check the sync * code if we have enough bits available */ - if (!pbi->ec_active || data + 3 < data_end) + if (data + 3 < data_end) { if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a) vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM, @@ -715,7 +747,7 @@ int vp8_decode_frame(VP8D_COMP *pbi) * if we have enough data. Otherwise we will end up with the wrong * size. */ - if (!pbi->ec_active || data + 6 < data_end) + if (data + 6 < data_end) { pc->Width = (data[3] | (data[4] << 8)) & 0x3fff; pc->horiz_scale = data[4] >> 6; @@ -745,22 +777,6 @@ int vp8_decode_frame(VP8D_COMP *pbi) if (vp8_alloc_frame_buffers(pc, pc->Width, pc->Height)) vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, "Failed to allocate frame buffers"); - -#if CONFIG_ERROR_CONCEALMENT - pbi->overlaps = NULL; - if (pbi->ec_enabled) - { - if (vp8_alloc_overlap_lists(pbi)) - vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, - "Failed to allocate overlap lists " - "for error concealment"); - } -#endif - -#if CONFIG_MULTITHREAD - if (pbi->b_multithreaded_rd) - vp8mt_alloc_temp_buffers(pbi, pc->Width, prev_mb_rows); -#endif } } } @@ -786,51 +802,147 @@ int vp8_decode_frame(VP8D_COMP *pbi) if (xd->segmentation_enabled) { - /* Signal whether or not the segmentation map is being explicitly updated this frame. */ + // Read whether or not the segmentation map is being explicitly + // updated this frame. xd->update_mb_segmentation_map = (unsigned char)vp8_read_bit(bc); + + // If so what method will be used. + if ( xd->update_mb_segmentation_map ) + pc->temporal_update = (unsigned char)vp8_read_bit(bc); + + // Is the segment data being updated xd->update_mb_segmentation_data = (unsigned char)vp8_read_bit(bc); if (xd->update_mb_segmentation_data) { - xd->mb_segement_abs_delta = (unsigned char)vp8_read_bit(bc); + int data; - vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data)); + xd->mb_segment_abs_delta = (unsigned char)vp8_read_bit(bc); - /* For each segmentation feature (Quant and loop filter level) */ - for (i = 0; i < MB_LVL_MAX; i++) + clearall_segfeatures( xd ); + + // For each segmentation... + for (i = 0; i < MAX_MB_SEGMENTS; i++) { - for (j = 0; j < MAX_MB_SEGMENTS; j++) + // For each of the segments features... + for (j = 0; j < SEG_LVL_MAX; j++) { - /* Frame level data */ + +#if CONFIG_FEATUREUPDATES + // feature updated? if (vp8_read_bit(bc)) { - xd->segment_feature_data[i][j] = (signed char)vp8_read_literal(bc, mb_feature_data_bits[i]); + int active=1; - if (vp8_read_bit(bc)) - xd->segment_feature_data[i][j] = -xd->segment_feature_data[i][j]; + if ( segfeature_active( xd, i, j )) + active=vp8_read_bit(bc); + + // Is the feature enabled + if (active) + { + // Update the feature data and mask + enable_segfeature(xd, i, j); + + data = (signed char)vp8_read_literal( + bc, seg_feature_data_bits(j)); + + // Is the segment data signed.. + if ( is_segfeature_signed(j) ) + { + if (vp8_read_bit(bc)) + data = - data; + } + } + else + data = 0; + + set_segdata(xd, i, j, data); + } + +#else + // Is the feature enabled + if (vp8_read_bit(bc)) + { + // Update the feature data and mask + enable_segfeature(xd, i, j); + + data = (signed char)vp8_read_literal( + bc, seg_feature_data_bits(j)); + + // Is the segment data signed.. + if ( is_segfeature_signed(j) ) + { + if (vp8_read_bit(bc)) + data = - data; + } } else - xd->segment_feature_data[i][j] = 0; + data = 0; + + set_segdata(xd, i, j, data); +#endif } } } if (xd->update_mb_segmentation_map) { - /* Which macro block level features are enabled */ - vpx_memset(xd->mb_segment_tree_probs, 255, sizeof(xd->mb_segment_tree_probs)); + // Which macro block level features are enabled + vpx_memset(xd->mb_segment_tree_probs, 255, + sizeof(xd->mb_segment_tree_probs)); + vpx_memset(pc->segment_pred_probs, 255, + sizeof(pc->segment_pred_probs)); - /* Read the probs used to decode the segment id for each macro block. */ + // Read the probs used to decode the segment id for each macro + // block. for (i = 0; i < MB_FEATURE_TREE_PROBS; i++) { - /* If not explicitly set value is defaulted to 255 by memset above */ + // If not explicitly set value is defaulted to 255 by + //memset above if (vp8_read_bit(bc)) - xd->mb_segment_tree_probs[i] = (vp8_prob)vp8_read_literal(bc, 8); + xd->mb_segment_tree_probs[i] = + (vp8_prob)vp8_read_literal(bc, 8); + } + + // If predictive coding of segment map is enabled read the + // prediction probabilities. + if ( pc->temporal_update ) + { + // Read the prediction probs needed to decode the segment id + // when predictive coding enabled + for (i = 0; i < PREDICTION_PROBS; i++) + { + // If not explicitly set value is defaulted to 255 by + // memset above + if (vp8_read_bit(bc)) + pc->segment_pred_probs[i] = + (vp8_prob)vp8_read_literal(bc, 8); + } } } } + // Read common prediction model status flag probability updates for the + // reference frame + if ( pc->frame_type == KEY_FRAME ) + { + // Set the prediction probabilities to defaults + pc->ref_pred_probs[0] = 120; + pc->ref_pred_probs[1] = 80; + pc->ref_pred_probs[2] = 40; + } + else + { + for (i = 0; i < PREDICTION_PROBS; i++) + { + if ( vp8_read_bit(bc) ) + pc->ref_pred_probs[i] = (vp8_prob)vp8_read_literal(bc, 8); + } + } + /* Read the loop filter level and type */ + pc->txfm_mode = (TXFM_MODE) vp8_read_bit(bc); + pc->filter_type = (LOOPFILTERTYPE) vp8_read_bit(bc); pc->filter_level = vp8_read_literal(bc, 6); pc->sharpness_level = vp8_read_literal(bc, 3); @@ -874,21 +986,15 @@ int vp8_decode_frame(VP8D_COMP *pbi) } } - if (pbi->input_partition) - { - setup_token_decoder_partition_input(pbi); - } - else - { - setup_token_decoder(pbi, data + first_partition_length_in_bytes); - } + setup_token_decoder(pbi, data + first_partition_length_in_bytes); + xd->current_bc = &pbi->bc2; /* Read the default quantizers. */ { int Q, q_update; - Q = vp8_read_literal(bc, 7); /* AC 1st order Q = default */ + Q = vp8_read_literal(bc, QINDEX_BITS); /* AC 1st order Q = default */ pc->base_qindex = Q; q_update = 0; pc->y1dc_delta_q = get_delta_q(bc, pc->y1dc_delta_q, &q_update); @@ -912,20 +1018,22 @@ int vp8_decode_frame(VP8D_COMP *pbi) { /* Should the GF or ARF be updated from the current frame */ pc->refresh_golden_frame = vp8_read_bit(bc); -#if CONFIG_ERROR_CONCEALMENT - /* Assume we shouldn't refresh golden if the bit is missing */ - xd->corrupted |= vp8dx_bool_error(bc); - if (pbi->ec_active && xd->corrupted) - pc->refresh_golden_frame = 0; -#endif - pc->refresh_alt_ref_frame = vp8_read_bit(bc); -#if CONFIG_ERROR_CONCEALMENT - /* Assume we shouldn't refresh altref if the bit is missing */ - xd->corrupted |= vp8dx_bool_error(bc); - if (pbi->ec_active && xd->corrupted) - pc->refresh_alt_ref_frame = 0; -#endif + + if(pc->refresh_alt_ref_frame) + { + vpx_memcpy(&pc->fc, &pc->lfc_a, sizeof(pc->fc)); + vpx_memcpy( pc->vp8_mode_contexts, + pc->mode_context_a, + sizeof(pc->vp8_mode_contexts)); + } + else + { + vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc)); + vpx_memcpy( pc->vp8_mode_contexts, + pc->mode_context, + sizeof(pc->vp8_mode_contexts)); + } /* Buffer to buffer copy flags. */ pc->copy_buffer_to_gf = 0; @@ -940,6 +1048,11 @@ int vp8_decode_frame(VP8D_COMP *pbi) pc->ref_frame_sign_bias[GOLDEN_FRAME] = vp8_read_bit(bc); pc->ref_frame_sign_bias[ALTREF_FRAME] = vp8_read_bit(bc); + +#if CONFIG_HIGH_PRECISION_MV + /* Is high precision mv allowed */ + xd->allow_high_precision_mv = (unsigned char)vp8_read_bit(bc); +#endif } pc->refresh_entropy_probs = vp8_read_bit(bc); @@ -950,13 +1063,6 @@ int vp8_decode_frame(VP8D_COMP *pbi) pc->refresh_last_frame = pc->frame_type == KEY_FRAME || vp8_read_bit(bc); -#if CONFIG_ERROR_CONCEALMENT - /* Assume we should refresh the last frame if the bit is missing */ - xd->corrupted |= vp8dx_bool_error(bc); - if (pbi->ec_active && xd->corrupted) - pc->refresh_last_frame = 1; -#endif - if (0) { FILE *z = fopen("decodestats.stt", "a"); @@ -971,15 +1077,14 @@ int vp8_decode_frame(VP8D_COMP *pbi) } { - pbi->independent_partitions = 1; - + if(vp8_read_bit(bc)) + { /* read coef probability tree */ for (i = 0; i < BLOCK_TYPES; i++) for (j = 0; j < COEF_BANDS; j++) for (k = 0; k < PREV_COEF_CONTEXTS; k++) for (l = 0; l < ENTROPY_NODES; l++) { - vp8_prob *const p = pc->fc.coef_probs [i][j][k] + l; if (vp8_read(bc, vp8_coef_update_probs [i][j][k][l])) @@ -987,20 +1092,40 @@ int vp8_decode_frame(VP8D_COMP *pbi) *p = (vp8_prob)vp8_read_literal(bc, 8); } - if (k > 0 && *p != pc->fc.coef_probs[i][j][k-1][l]) - pbi->independent_partitions = 0; + } + } + } + if(pbi->common.txfm_mode == ALLOW_8X8 && vp8_read_bit(bc)) + { + // read coef probability tree + for (i = 0; i < BLOCK_TYPES; i++) + for (j = 0; j < COEF_BANDS; j++) + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + for (l = 0; l < MAX_ENTROPY_TOKENS - 1; l++) + { + + vp8_prob *const p = pc->fc.coef_probs_8x8 [i][j][k] + l; + + if (vp8_read(bc, vp8_coef_update_probs_8x8 [i][j][k][l])) + { + *p = (vp8_prob)vp8_read_literal(bc, 8); + + } } } + vpx_memcpy(&xd->pre, &pc->yv12_fb[pc->lst_fb_idx], sizeof(YV12_BUFFER_CONFIG)); vpx_memcpy(&xd->dst, &pc->yv12_fb[pc->new_fb_idx], sizeof(YV12_BUFFER_CONFIG)); + // Create the segmentation map structure and set to 0 + if (!pc->last_frame_seg_map) + CHECK_MEM_ERROR(pc->last_frame_seg_map, + vpx_calloc((pc->mb_rows * pc->mb_cols), 1)); + /* set up frame new frame for intra coded blocks */ -#if CONFIG_MULTITHREAD - if (!(pbi->b_multithreaded_rd) || pc->multi_token_partition == ONE_PARTITION || !(pc->filter_level)) -#endif - vp8_setup_intra_recon(&pc->yv12_fb[pc->new_fb_idx]); + vp8_setup_intra_recon(&pc->yv12_fb[pc->new_fb_idx]); vp8_setup_block_dptrs(xd); @@ -1012,57 +1137,23 @@ int vp8_decode_frame(VP8D_COMP *pbi) /* Read the mb_no_coeff_skip flag */ pc->mb_no_coeff_skip = (int)vp8_read_bit(bc); - vp8_decode_mode_mvs(pbi); - -#if CONFIG_ERROR_CONCEALMENT - if (pbi->ec_active && - pbi->mvs_corrupt_from_mb < (unsigned int)pc->mb_cols * pc->mb_rows) + if(pbi->common.frame_type != KEY_FRAME) { - /* Motion vectors are missing in this frame. We will try to estimate - * them and then continue decoding the frame as usual */ - vp8_estimate_missing_mvs(pbi); + vp8_update_mode_context(&pbi->common); } -#endif vpx_memset(pc->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES) * pc->mb_cols); -#if CONFIG_MULTITHREAD - if (pbi->b_multithreaded_rd && pc->multi_token_partition != ONE_PARTITION) + // Resset the macroblock mode info context to the start of the list + xd->mode_info_context = pc->mi; + + /* Decode a row of macro blocks */ + for (mb_row = 0; mb_row < pc->mb_rows; mb_row++) { - int i; - pbi->frame_corrupt_residual = 0; - vp8mt_decode_mb_rows(pbi, xd); - vp8_yv12_extend_frame_borders_ptr(&pc->yv12_fb[pc->new_fb_idx]); /*cm->frame_to_show);*/ - for (i = 0; i < pbi->decoding_thread_count; ++i) - corrupt_tokens |= pbi->mb_row_di[i].mbd.corrupted; + decode_mb_row(pbi, pc, mb_row, xd); } - else -#endif - { - int ibc = 0; - int num_part = 1 << pc->multi_token_partition; - pbi->frame_corrupt_residual = 0; - - /* Decode the individual macro block */ - for (mb_row = 0; mb_row < pc->mb_rows; mb_row++) - { - - if (num_part > 1) - { - xd->current_bc = & pbi->mbc[ibc]; - ibc++; - - if (ibc == num_part) - ibc = 0; - } - - decode_mb_row(pbi, pc, mb_row, xd); - } - corrupt_tokens |= xd->corrupted; - } - - stop_token_decoder(pbi); + corrupt_tokens |= xd->corrupted; /* Collect information about decoder corruption. */ /* 1. Check first boolean decoder for errors. */ @@ -1088,11 +1179,12 @@ int vp8_decode_frame(VP8D_COMP *pbi) { pc->last_kf_gf_q = pc->base_qindex; } - - if (pc->refresh_entropy_probs == 0) + if(pc->refresh_entropy_probs) { - vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc)); - pbi->independent_partitions = prev_independent_partitions; + if(pc->refresh_alt_ref_frame) + vpx_memcpy(&pc->lfc_a, &pc->fc, sizeof(pc->fc)); + else + vpx_memcpy(&pc->lfc, &pc->fc, sizeof(pc->fc)); } #ifdef PACKET_TESTING @@ -1104,6 +1196,7 @@ int vp8_decode_frame(VP8D_COMP *pbi) fclose(f); } #endif + //printf("Frame %d Done\n", frame_count++); return 0; } diff --git a/vp8/decoder/dequantize.c b/vp8/decoder/dequantize.c index a60442fe8..f83032766 100644 --- a/vp8/decoder/dequantize.c +++ b/vp8/decoder/dequantize.c @@ -9,17 +9,24 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "dequantize.h" #include "vp8/common/idct.h" #include "vpx_mem/vpx_mem.h" +#include "onyxd_int.h" extern void vp8_short_idct4x4llm_c(short *input, short *output, int pitch) ; extern void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch); +extern void vp8_short_idct8x8_c(short *input, short *output, int pitch); +extern void vp8_short_idct8x8_1_c(short *input, short *output, int pitch); +#ifdef DEC_DEBUG +extern int dec_debug; +#endif void vp8_dequantize_b_c(BLOCKD *d) { + int i; short *DQ = d->dqcoeff; short *Q = d->qcoeff; @@ -111,3 +118,212 @@ void vp8_dequant_dc_idct_add_c(short *input, short *dq, unsigned char *pred, pred += pitch; } } + +void vp8_dequantize_b_2x2_c(BLOCKD *d) +{ + int i; + short *DQ = d->dqcoeff; + short *Q = d->qcoeff; + short *DQC = d->dequant; + + for (i = 0; i < 16; i++) + { + DQ[i] = (short)((Q[i] * DQC[i])); + } +#ifdef DEC_DEBUG + if (dec_debug) { + int j; + printf("Dequantize 2x2\n"); + for (j=0;j<16;j++) printf("%d ", Q[j]); printf("\n"); + for (j=0;j<16;j++) printf("%d ", DQ[j]); printf("\n"); + } +#endif +} + +void vp8_dequant_idct_add_8x8_c(short *input, short *dq, unsigned char *pred, + unsigned char *dest, int pitch, int stride)//, MACROBLOCKD *xd, short blk_idx +{ + short output[64]; + short *diff_ptr = output; + int r, c, b; + int i; + unsigned char *origdest = dest; + unsigned char *origpred = pred; + +#ifdef DEC_DEBUG + if (dec_debug) { + int j; + printf("Input 8x8\n"); + for (j=0;j<64;j++) { + printf("%d ", input[j]); + if (j%8 == 7) printf("\n"); + } + } +#endif + + input[0]= input[0] * dq[0]; + + // recover quantizer for 4 4x4 blocks + for (i = 1; i < 64; i++) + { + input[i]=input[i] * dq[1]; + } +#ifdef DEC_DEBUG + if (dec_debug) { + int j; + printf("Input DQ 8x8\n"); + for (j=0;j<64;j++) { + printf("%d ", input[j]); + if (j%8 == 7) printf("\n"); + } + } +#endif + + // the idct halves ( >> 1) the pitch + vp8_short_idct8x8_c(input, output, 16); +#ifdef DEC_DEBUG + if (dec_debug) { + int j; + printf("Output 8x8\n"); + for (j=0;j<64;j++) { + printf("%d ", output[j]); + if (j%8 == 7) printf("\n"); + } + } +#endif + + vpx_memset(input, 0, 128);// test what should i put here + + for (b = 0; b < 4; b++) + { + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = diff_ptr[c] + pred[c]; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dest[c] = (unsigned char) a; + } + + dest += stride; + diff_ptr += 8; + pred += pitch; + } + diff_ptr = output + (b+1) / 2 * 4 * 8 + (b+1) % 2 * 4; + dest = origdest + (b+1) / 2 * 4 * stride + (b+1) % 2 * 4; + pred = origpred + (b+1) / 2 * 4 * pitch + (b+1) % 2 * 4; + } +#ifdef DEC_DEBUG + if (dec_debug) { + int k,j; + printf("Final 8x8\n"); + for (j=0;j<8;j++) { + for (k=0;k<8;k++) { + printf("%d ", origdest[k]); + } + printf("\n"); + origdest+=stride; + } + } +#endif +} + +void vp8_dequant_dc_idct_add_8x8_c(short *input, short *dq, unsigned char *pred, + unsigned char *dest, int pitch, int stride, + int Dc)// Dc for 1st order T in some rear case +{ + short output[64]; + short *diff_ptr = output; + int r, c, b; + int i; + unsigned char *origdest = dest; + unsigned char *origpred = pred; + + input[0] = (short)Dc;//Dc is the reconstructed value, do not need dequantization + //dc value is recovered after dequantization, since dc need not quantization +#ifdef DEC_DEBUG + if (dec_debug) { + int j; + printf("Input 8x8\n"); + for (j=0;j<64;j++) { + printf("%d ", input[j]); + if (j%8 == 7) printf("\n"); + } + } +#endif + for (i = 1; i < 64; i++) + { + input[i]=input[i] * dq[1]; + } + +#ifdef DEC_DEBUG + if (dec_debug) { + int j; + printf("Input DQ 8x8\n"); + for (j=0;j<64;j++) { + printf("%d ", input[j]); + if (j%8 == 7) printf("\n"); + } + } +#endif + + // the idct halves ( >> 1) the pitch + vp8_short_idct8x8_c(input, output,16); +#ifdef DEC_DEBUG + if (dec_debug) { + int j; + printf("Output 8x8\n"); + for (j=0;j<64;j++) { + printf("%d ", output[j]); + if (j%8 == 7) printf("\n"); + } + } +#endif + vpx_memset(input, 0, 128); + + for (b = 0; b < 4; b++) + { + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = diff_ptr[c] + pred[c]; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dest[c] = (unsigned char) a; + } + + dest += stride; + diff_ptr += 8; + pred += pitch; + } + diff_ptr = output + (b+1) / 2 * 4 * 8 + (b+1) % 2 * 4; + dest = origdest + (b+1) / 2 * 4 * stride + (b+1) % 2 * 4; + pred = origpred + (b+1) / 2 * 4 * pitch + (b+1) % 2 * 4; + } +#ifdef DEC_DEBUG + if (dec_debug) { + int k,j; + printf("Final 8x8\n"); + for (j=0;j<8;j++) { + for (k=0;k<8;k++) { + printf("%d ", origdest[k]); + } + printf("\n"); + origdest+=stride; + } + } +#endif +} + diff --git a/vp8/decoder/dequantize.h b/vp8/decoder/dequantize.h index 2e662a593..d0f162b48 100644 --- a/vp8/decoder/dequantize.h +++ b/vp8/decoder/dequantize.h @@ -42,6 +42,22 @@ unsigned char *pre, unsigned char *dst_u, \ unsigned char *dst_v, int stride, char *eobs) +#define prototype_dequant_dc_idct_add_y_block_8x8(sym) \ + void sym(short *q, short *dq, \ + unsigned char *pre, unsigned char *dst, \ + int stride, char *eobs, short *dc, MACROBLOCKD *xd) + +#define prototype_dequant_idct_add_y_block_8x8(sym) \ + void sym(short *q, short *dq, \ + unsigned char *pre, unsigned char *dst, \ + int stride, char *eobs, MACROBLOCKD *xd) + +#define prototype_dequant_idct_add_uv_block_8x8(sym) \ + void sym(short *q, short *dq, \ + unsigned char *pre, unsigned char *dst_u, \ + unsigned char *dst_v, int stride, char *eobs, \ + MACROBLOCKD *xd) + #if ARCH_X86 || ARCH_X86_64 #include "x86/dequantize_x86.h" #endif @@ -81,6 +97,38 @@ extern prototype_dequant_idct_add_y_block(vp8_dequant_idct_add_y_block); extern prototype_dequant_idct_add_uv_block(vp8_dequant_idct_add_uv_block); +#ifndef vp8_dequant_block_2x2 +#define vp8_dequant_block_2x2 vp8_dequantize_b_2x2_c +#endif +extern prototype_dequant_block(vp8_dequant_block_2x2); + +#ifndef vp8_dequant_idct_add_8x8 +#define vp8_dequant_idct_add_8x8 vp8_dequant_idct_add_8x8_c +#endif +extern prototype_dequant_idct_add(vp8_dequant_idct_add_8x8); + +#ifndef vp8_dequant_dc_idct_add_8x8 +#define vp8_dequant_dc_idct_add_8x8 vp8_dequant_dc_idct_add_8x8_c +#endif +extern prototype_dequant_dc_idct_add(vp8_dequant_dc_idct_add_8x8); + +#ifndef vp8_dequant_dc_idct_add_y_block_8x8 +#define vp8_dequant_dc_idct_add_y_block_8x8 vp8_dequant_dc_idct_add_y_block_8x8_c +#endif +extern prototype_dequant_dc_idct_add_y_block_8x8(vp8_dequant_dc_idct_add_y_block_8x8); + +#ifndef vp8_dequant_idct_add_y_block_8x8 +#define vp8_dequant_idct_add_y_block_8x8 vp8_dequant_idct_add_y_block_8x8_c +#endif +extern prototype_dequant_idct_add_y_block_8x8(vp8_dequant_idct_add_y_block_8x8); + +#ifndef vp8_dequant_idct_add_uv_block_8x8 +#define vp8_dequant_idct_add_uv_block_8x8 vp8_dequant_idct_add_uv_block_8x8_c +#endif +extern prototype_dequant_idct_add_uv_block_8x8(vp8_dequant_idct_add_uv_block_8x8); + + + typedef prototype_dequant_block((*vp8_dequant_block_fn_t)); typedef prototype_dequant_idct_add((*vp8_dequant_idct_add_fn_t)); @@ -93,6 +141,12 @@ typedef prototype_dequant_idct_add_y_block((*vp8_dequant_idct_add_y_block_fn_t)) typedef prototype_dequant_idct_add_uv_block((*vp8_dequant_idct_add_uv_block_fn_t)); +typedef prototype_dequant_dc_idct_add_y_block_8x8((*vp8_dequant_dc_idct_add_y_block_fn_t_8x8)); + +typedef prototype_dequant_idct_add_y_block_8x8((*vp8_dequant_idct_add_y_block_fn_t_8x8)); + +typedef prototype_dequant_idct_add_uv_block_8x8((*vp8_dequant_idct_add_uv_block_fn_t_8x8)); + typedef struct { vp8_dequant_block_fn_t block; @@ -101,6 +155,12 @@ typedef struct vp8_dequant_dc_idct_add_y_block_fn_t dc_idct_add_y_block; vp8_dequant_idct_add_y_block_fn_t idct_add_y_block; vp8_dequant_idct_add_uv_block_fn_t idct_add_uv_block; + vp8_dequant_block_fn_t block_2x2; + vp8_dequant_idct_add_fn_t idct_add_8x8; + vp8_dequant_dc_idct_add_fn_t dc_idct_add_8x8; + vp8_dequant_dc_idct_add_y_block_fn_t_8x8 dc_idct_add_y_block_8x8; + vp8_dequant_idct_add_y_block_fn_t_8x8 idct_add_y_block_8x8; + vp8_dequant_idct_add_uv_block_fn_t_8x8 idct_add_uv_block_8x8; } vp8_dequant_rtcd_vtable_t; #if CONFIG_RUNTIME_CPU_DETECT diff --git a/vp8/decoder/detokenize.c b/vp8/decoder/detokenize.c index 98be68558..ae105b139 100644 --- a/vp8/decoder/detokenize.c +++ b/vp8/decoder/detokenize.c @@ -16,6 +16,8 @@ #include "vpx_ports/mem.h" #include "detokenize.h" +#include "vp8/common/seg_common.h" + #define BOOL_DATA UINT8 #define OCB_X PREV_COEF_CONTEXTS * ENTROPY_NODES @@ -26,6 +28,17 @@ DECLARE_ALIGNED(16, static const unsigned char, coef_bands_x[16]) = 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 7 * OCB_X }; +DECLARE_ALIGNED(64, static const unsigned char, coef_bands_x_8x8[64]) = { + 0 * OCB_X, 1 * OCB_X, 2 * OCB_X, 3 * OCB_X, 5 * OCB_X, 4 * OCB_X, 4 * OCB_X, 5 * OCB_X, + 5 * OCB_X, 3 * OCB_X, 6 * OCB_X, 3 * OCB_X, 5 * OCB_X, 4 * OCB_X, 6 * OCB_X, 6 * OCB_X, + 6 * OCB_X, 5 * OCB_X, 5 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, + 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, + 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, + 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, + 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, + 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, 7 * OCB_X, +}; + #define EOB_CONTEXT_NODE 0 #define ZERO_CONTEXT_NODE 1 #define ONE_CONTEXT_NODE 2 @@ -44,7 +57,6 @@ DECLARE_ALIGNED(16, static const unsigned char, coef_bands_x[16]) = #define CAT4_MIN_VAL 19 #define CAT5_MIN_VAL 35 #define CAT6_MIN_VAL 67 - #define CAT1_PROB0 159 #define CAT2_PROB0 145 #define CAT2_PROB1 165 @@ -64,18 +76,14 @@ DECLARE_ALIGNED(16, static const unsigned char, coef_bands_x[16]) = #define CAT5_PROB3 157 #define CAT5_PROB4 180 -#if CONFIG_EXTEND_QRANGE static const unsigned char cat6_prob[14] = { 129, 130, 133, 140, 153, 177, 196, 230, 243, 249, 252, 254, 254, 0 }; -#else -static const unsigned char cat6_prob[12] = -{ 129, 130, 133, 140, 153, 177, 196, 230, 243, 254, 254, 0 }; -#endif void vp8_reset_mb_tokens_context(MACROBLOCKD *x) { /* Clear entropy contexts for Y2 blocks */ if (x->mode_info_context->mbmi.mode != B_PRED && + x->mode_info_context->mbmi.mode != I8X8_PRED && x->mode_info_context->mbmi.mode != SPLITMV) { vpx_memset(x->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); @@ -158,6 +166,47 @@ DECLARE_ALIGNED(16, extern const unsigned char, vp8_norm[256]); NORMALIZE \ } +#define DECODE_AND_LOOP_IF_ZERO_8x8_2(probability,branch) \ + { \ + split = 1 + ((( probability*(range-1) ) ) >> 8); \ + bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8); \ + FILL \ + if ( value < bigsplit ) \ + { \ + range = split; \ + NORMALIZE \ + Prob = coef_probs; \ + if(c<3) {\ + ++c; \ + Prob += coef_bands_x[c]; \ + goto branch; \ + } goto BLOCK_FINISHED_8x8; /*for malformed input */\ + } \ + value -= bigsplit; \ + range = range - split; \ + NORMALIZE \ + } +#define DECODE_AND_LOOP_IF_ZERO_8X8(probability,branch) \ + { \ + split = 1 + ((( probability*(range-1) ) ) >> 8); \ + bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8); \ + FILL \ + if ( value < bigsplit ) \ + { \ + range = split; \ + NORMALIZE \ + Prob = coef_probs; \ + if(c<63) {\ + ++c; \ + Prob += coef_bands_x_8x8[c]; \ + goto branch; \ + } goto BLOCK_FINISHED_8x8; /*for malformed input */\ + } \ + value -= bigsplit; \ + range = range - split; \ + NORMALIZE \ + } + #define DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val) \ DECODE_AND_APPLYSIGN(val) \ Prob = coef_probs + (ENTROPY_NODES*2); \ @@ -169,6 +218,26 @@ DECLARE_ALIGNED(16, extern const unsigned char, vp8_norm[256]); goto BLOCK_FINISHED; +#define DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(val) \ + DECODE_AND_APPLYSIGN(val) \ + Prob = coef_probs + (ENTROPY_NODES*2); \ + if(c < 3){\ + qcoeff_ptr [ scan[c] ] = (INT16) v; \ + ++c; \ + goto DO_WHILE_8x8; }\ + qcoeff_ptr [ scan[3] ] = (INT16) v; \ + goto BLOCK_FINISHED_8x8; +#define DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(val) \ + DECODE_AND_APPLYSIGN(val) \ + Prob = coef_probs + (ENTROPY_NODES*2); \ + if(c < 63){\ + qcoeff_ptr [ scan[c] ] = (INT16) v; \ + ++c; \ + goto DO_WHILE_8x8; }\ + qcoeff_ptr [ scan[63] ] = (INT16) v; \ + goto BLOCK_FINISHED_8x8; + + #define DECODE_EXTRABIT_AND_ADJUST_VAL(prob, bits_count)\ split = 1 + (((range-1) * prob) >> 8); \ bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8); \ @@ -185,11 +254,12 @@ DECLARE_ALIGNED(16, extern const unsigned char, vp8_norm[256]); }\ NORMALIZE -int vp8_decode_mb_tokens(VP8D_COMP *dx, MACROBLOCKD *x) + +int vp8_decode_mb_tokens_8x8(VP8D_COMP *dx, MACROBLOCKD *x) { ENTROPY_CONTEXT *A = (ENTROPY_CONTEXT *)x->above_context; ENTROPY_CONTEXT *L = (ENTROPY_CONTEXT *)x->left_context; - const FRAME_CONTEXT * const fc = &dx->common.fc; + const VP8_COMMON *const oc = & dx->common; BOOL_DECODER *bc = x->current_bc; @@ -203,6 +273,331 @@ int vp8_decode_mb_tokens(VP8D_COMP *dx, MACROBLOCKD *x) register int count; + const BOOL_DATA *bufptr; + const BOOL_DATA *bufend; + register unsigned int range; + VP8_BD_VALUE value; + const int *scan;// + register unsigned int shift; + UINT32 split; + VP8_BD_VALUE bigsplit; + INT16 *qcoeff_ptr; + + const vp8_prob *coef_probs;// + int type; + int stop; + INT16 val, bits_count; + INT16 c; + INT16 v; + const vp8_prob *Prob;// + + int seg_eob; + int segment_id = x->mode_info_context->mbmi.segment_id; + + type = 3; + i = 0; + stop = 16; + + scan = vp8_default_zig_zag1d_8x8; + qcoeff_ptr = &x->qcoeff[0]; + + if (x->mode_info_context->mbmi.mode != B_PRED && x->mode_info_context->mbmi.mode != SPLITMV) + { + i = 24; + stop = 24; + type = 1; + qcoeff_ptr += 24*16; + eobtotal -= 4; + scan = vp8_default_zig_zag1d; + } + + bufend = bc->user_buffer_end; + bufptr = bc->user_buffer; + value = bc->value; + count = bc->count; + range = bc->range; + + coef_probs = oc->fc.coef_probs_8x8 [type] [ 0 ] [0]; + +BLOCK_LOOP_8x8: + a = A + vp8_block2above_8x8[i]; + l = L + vp8_block2left_8x8[i]; + + c = (INT16)(!type); + +// Dest = ((A)!=0) + ((B)!=0); + if(i==24) + { + VP8_COMBINEENTROPYCONTEXTS(v, *a, *l); + if ( segfeature_active( x, segment_id, SEG_LVL_EOB ) ) + { + seg_eob = get_segdata( x, segment_id, SEG_LVL_EOB ); + } + else + seg_eob = 4; + } + else + { + VP8_COMBINEENTROPYCONTEXTS(v, *a, *l); + if ( segfeature_active( x, segment_id, SEG_LVL_EOB ) ) + { + seg_eob = get_segdata( x, segment_id, SEG_LVL_EOB ); + } + else + seg_eob = 64; + } + + Prob = coef_probs; + Prob += v * ENTROPY_NODES; + +DO_WHILE_8x8: + if ( c == seg_eob ) + goto BLOCK_FINISHED_8x8; + + if(i==24) + Prob += coef_bands_x[c]; + else + Prob += coef_bands_x_8x8[c]; + DECODE_AND_BRANCH_IF_ZERO(Prob[EOB_CONTEXT_NODE], BLOCK_FINISHED_8x8); + +CHECK_0_8x8_: + if (i==24) + { + DECODE_AND_LOOP_IF_ZERO_8x8_2(Prob[ZERO_CONTEXT_NODE], CHECK_0_8x8_); + } + else + { + DECODE_AND_LOOP_IF_ZERO_8X8(Prob[ZERO_CONTEXT_NODE], CHECK_0_8x8_); + } + DECODE_AND_BRANCH_IF_ZERO(Prob[ONE_CONTEXT_NODE], ONE_CONTEXT_NODE_0_8x8_); + DECODE_AND_BRANCH_IF_ZERO(Prob[LOW_VAL_CONTEXT_NODE], + LOW_VAL_CONTEXT_NODE_0_8x8_); + DECODE_AND_BRANCH_IF_ZERO(Prob[HIGH_LOW_CONTEXT_NODE], + HIGH_LOW_CONTEXT_NODE_0_8x8_); + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_THREEFOUR_CONTEXT_NODE], + CAT_THREEFOUR_CONTEXT_NODE_0_8x8_); + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_FIVE_CONTEXT_NODE], + CAT_FIVE_CONTEXT_NODE_0_8x8_); + val = CAT6_MIN_VAL; + bits_count = 12; + do + { + DECODE_EXTRABIT_AND_ADJUST_VAL(cat6_prob[bits_count], bits_count); + bits_count -- ; + } + while (bits_count >= 0); + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(val); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(val); + } + +CAT_FIVE_CONTEXT_NODE_0_8x8_: + val = CAT5_MIN_VAL; + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT5_PROB4, 4); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT5_PROB3, 3); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT5_PROB2, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT5_PROB1, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT5_PROB0, 0); + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(val); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(val); + } + +CAT_THREEFOUR_CONTEXT_NODE_0_8x8_: + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_THREE_CONTEXT_NODE], + CAT_THREE_CONTEXT_NODE_0_8x8_); + val = CAT4_MIN_VAL; + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT4_PROB3, 3); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT4_PROB2, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT4_PROB1, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT4_PROB0, 0); + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(val); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(val); + } + +CAT_THREE_CONTEXT_NODE_0_8x8_: + val = CAT3_MIN_VAL; + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT3_PROB2, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT3_PROB1, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT3_PROB0, 0); + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(val); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(val); + } + +HIGH_LOW_CONTEXT_NODE_0_8x8_: + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_ONE_CONTEXT_NODE], + CAT_ONE_CONTEXT_NODE_0_8x8_); + val = CAT2_MIN_VAL; + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT2_PROB1, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT2_PROB0, 0); + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(val); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(val); + } + +CAT_ONE_CONTEXT_NODE_0_8x8_: + val = CAT1_MIN_VAL; + DECODE_EXTRABIT_AND_ADJUST_VAL(CAT1_PROB0, 0); + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(val); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(val); + } + +LOW_VAL_CONTEXT_NODE_0_8x8_: + DECODE_AND_BRANCH_IF_ZERO(Prob[TWO_CONTEXT_NODE], + TWO_CONTEXT_NODE_0_8x8_); + DECODE_AND_BRANCH_IF_ZERO(Prob[THREE_CONTEXT_NODE], + THREE_CONTEXT_NODE_0_8x8_); + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(4); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(4); + } + + +THREE_CONTEXT_NODE_0_8x8_: + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(3); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(3); + } + + +TWO_CONTEXT_NODE_0_8x8_: + if(i==24) + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8_2(2); + } + else + { + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT_8x8(2); + } + + +ONE_CONTEXT_NODE_0_8x8_: + DECODE_AND_APPLYSIGN(1); + Prob = coef_probs + ENTROPY_NODES; + + if (i==24) + { + if (c < 3)//15 + { + qcoeff_ptr [ scan[c] ] = (INT16) v; + ++c; + goto DO_WHILE_8x8; + } + } + else + { + if (c < 63) + { + qcoeff_ptr [ scan[c] ] = (INT16) v; + ++c; + goto DO_WHILE_8x8; + } + } + + if(i==24) + qcoeff_ptr [ scan[3] ] = (INT16) v;//15 + else + qcoeff_ptr [ scan[63] ] = (INT16) v; + + +BLOCK_FINISHED_8x8: + *a = *l = ((eobs[i] = c) != !type); // any nonzero data? + if (i!=24) + { + *(a + 1) = *a; + *(l + 1) = *l; + } + + eobtotal += c; + qcoeff_ptr += (i==24 ? 16 : 64); + + i+=4; + + if (i < stop) + goto BLOCK_LOOP_8x8; + + if (i > 24) + { + type = 0; + i = 0; + stop = 16; + coef_probs = oc->fc.coef_probs_8x8 [type] [ 0 ] [0]; + qcoeff_ptr -= (24*16 + 16); + scan = vp8_default_zig_zag1d_8x8; + goto BLOCK_LOOP_8x8; + } + + if (i == 16) + { + type = 2; + coef_probs = oc->fc.coef_probs_8x8 [type] [ 0 ] [0]; + stop = 24; + goto BLOCK_LOOP_8x8; + } + + FILL + bc->user_buffer = bufptr; + bc->value = value; + bc->count = count; + bc->range = range; + + return eobtotal; + +} + +int vp8_decode_mb_tokens(VP8D_COMP *dx, MACROBLOCKD *xd) +{ + ENTROPY_CONTEXT *A = (ENTROPY_CONTEXT *)xd->above_context; + ENTROPY_CONTEXT *L = (ENTROPY_CONTEXT *)xd->left_context; + const FRAME_CONTEXT * const fc = &dx->common.fc; + + BOOL_DECODER *bc = xd->current_bc; + + char *eobs = xd->eobs; + + ENTROPY_CONTEXT *a; + ENTROPY_CONTEXT *l; + int i; + + int eobtotal = 0; + + register int count; + const BOOL_DATA *bufptr; const BOOL_DATA *bufend; register unsigned int range; @@ -221,15 +616,23 @@ int vp8_decode_mb_tokens(VP8D_COMP *dx, MACROBLOCKD *x) INT16 v; const vp8_prob *Prob; + int seg_eob = 16; + int segment_id = xd->mode_info_context->mbmi.segment_id; + + if ( segfeature_active( xd, segment_id, SEG_LVL_EOB ) ) + { + seg_eob = get_segdata( xd, segment_id, SEG_LVL_EOB ); + } + type = 3; i = 0; stop = 16; scan = vp8_default_zig_zag1d; - qcoeff_ptr = &x->qcoeff[0]; - - if (x->mode_info_context->mbmi.mode != B_PRED && - x->mode_info_context->mbmi.mode != SPLITMV) + qcoeff_ptr = &xd->qcoeff[0]; + if (xd->mode_info_context->mbmi.mode != B_PRED && + xd->mode_info_context->mbmi.mode != I8X8_PRED && + xd->mode_info_context->mbmi.mode != SPLITMV) { i = 24; stop = 24; @@ -259,6 +662,9 @@ BLOCK_LOOP: Prob += v * ENTROPY_NODES; DO_WHILE: + if ( c == seg_eob ) + goto BLOCK_FINISHED; + Prob += coef_bands_x[c]; DECODE_AND_BRANCH_IF_ZERO(Prob[EOB_CONTEXT_NODE], BLOCK_FINISHED); @@ -275,7 +681,7 @@ CHECK_0_: CAT_FIVE_CONTEXT_NODE_0_); val = CAT6_MIN_VAL; - bits_count = CONFIG_EXTEND_QRANGE?12:10; + bits_count = 12; do { @@ -382,6 +788,7 @@ BLOCK_FINISHED: bc->value = value; bc->count = count; bc->range = range; + return eobtotal; } diff --git a/vp8/decoder/detokenize.h b/vp8/decoder/detokenize.h index 8640bda4c..caedf2f37 100644 --- a/vp8/decoder/detokenize.h +++ b/vp8/decoder/detokenize.h @@ -16,5 +16,6 @@ void vp8_reset_mb_tokens_context(MACROBLOCKD *x); int vp8_decode_mb_tokens(VP8D_COMP *, MACROBLOCKD *); +int vp8_decode_mb_tokens_8x8(VP8D_COMP *, MACROBLOCKD *); #endif /* DETOKENIZE_H */ diff --git a/vp8/decoder/error_concealment.c b/vp8/decoder/error_concealment.c deleted file mode 100644 index 48f97b565..000000000 --- a/vp8/decoder/error_concealment.c +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright (c) 2011 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "error_concealment.h" -#include "onyxd_int.h" -#include "decodemv.h" -#include "vpx_mem/vpx_mem.h" -#include "vp8/common/recon.h" -#include "vp8/common/findnearmv.h" - -#include - -#define MIN(x,y) (((x)<(y))?(x):(y)) -#define MAX(x,y) (((x)>(y))?(x):(y)) - -#define FLOOR(x,q) ((x) & -(1 << (q))) - -#define NUM_NEIGHBORS 20 - -typedef struct ec_position -{ - int row; - int col; -} EC_POS; - -/* - * Regenerate the table in Matlab with: - * x = meshgrid((1:4), (1:4)); - * y = meshgrid((1:4), (1:4))'; - * W = round((1./(sqrt(x.^2 + y.^2))*2^7)); - * W(1,1) = 0; - */ -static const int weights_q7[5][5] = { - { 0, 128, 64, 43, 32 }, - {128, 91, 57, 40, 31 }, - { 64, 57, 45, 36, 29 }, - { 43, 40, 36, 30, 26 }, - { 32, 31, 29, 26, 23 } -}; - -int vp8_alloc_overlap_lists(VP8D_COMP *pbi) -{ - if (pbi->overlaps != NULL) - { - vpx_free(pbi->overlaps); - pbi->overlaps = NULL; - } - pbi->overlaps = vpx_calloc(pbi->common.mb_rows * pbi->common.mb_cols, - sizeof(MB_OVERLAP)); - if (pbi->overlaps == NULL) - return -1; - vpx_memset(pbi->overlaps, 0, - sizeof(MB_OVERLAP) * pbi->common.mb_rows * pbi->common.mb_cols); - return 0; -} - -void vp8_de_alloc_overlap_lists(VP8D_COMP *pbi) -{ - vpx_free(pbi->overlaps); - pbi->overlaps = NULL; -} - -/* Inserts a new overlap area value to the list of overlaps of a block */ -static void assign_overlap(OVERLAP_NODE* overlaps, - union b_mode_info *bmi, - int overlap) -{ - int i; - if (overlap <= 0) - return; - /* Find and assign to the next empty overlap node in the list of overlaps. - * Empty is defined as bmi == NULL */ - for (i = 0; i < MAX_OVERLAPS; i++) - { - if (overlaps[i].bmi == NULL) - { - overlaps[i].bmi = bmi; - overlaps[i].overlap = overlap; - break; - } - } -} - -/* Calculates the overlap area between two 4x4 squares, where the first - * square has its upper-left corner at (b1_row, b1_col) and the second - * square has its upper-left corner at (b2_row, b2_col). Doesn't - * properly handle squares which do not overlap. - */ -static int block_overlap(int b1_row, int b1_col, int b2_row, int b2_col) -{ - const int int_top = MAX(b1_row, b2_row); // top - const int int_left = MAX(b1_col, b2_col); // left - /* Since each block is 4x4 pixels, adding 4 (Q3) to the left/top edge - * gives us the right/bottom edge. - */ - const int int_right = MIN(b1_col + (4<<3), b2_col + (4<<3)); // right - const int int_bottom = MIN(b1_row + (4<<3), b2_row + (4<<3)); // bottom - return (int_bottom - int_top) * (int_right - int_left); -} - -/* Calculates the overlap area for all blocks in a macroblock at position - * (mb_row, mb_col) in macroblocks, which are being overlapped by a given - * overlapping block at position (new_row, new_col) (in pixels, Q3). The - * first block being overlapped in the macroblock has position (first_blk_row, - * first_blk_col) in blocks relative the upper-left corner of the image. - */ -static void calculate_overlaps_mb(B_OVERLAP *b_overlaps, union b_mode_info *bmi, - int new_row, int new_col, - int mb_row, int mb_col, - int first_blk_row, int first_blk_col) -{ - /* Find the blocks within this MB (defined by mb_row, mb_col) which are - * overlapped by bmi and calculate and assign overlap for each of those - * blocks. */ - - /* Block coordinates relative the upper-left block */ - const int rel_ol_blk_row = first_blk_row - mb_row * 4; - const int rel_ol_blk_col = first_blk_col - mb_col * 4; - /* If the block partly overlaps any previous MB, these coordinates - * can be < 0. We don't want to access blocks in previous MBs. - */ - const int blk_idx = MAX(rel_ol_blk_row,0) * 4 + MAX(rel_ol_blk_col,0); - /* Upper left overlapping block */ - B_OVERLAP *b_ol_ul = &(b_overlaps[blk_idx]); - - /* Calculate and assign overlaps for all blocks in this MB - * which the motion compensated block overlaps - */ - /* Avoid calculating overlaps for blocks in later MBs */ - int end_row = MIN(4 + mb_row * 4 - first_blk_row, 2); - int end_col = MIN(4 + mb_col * 4 - first_blk_col, 2); - int row, col; - - /* Check if new_row and new_col are evenly divisible by 4 (Q3), - * and if so we shouldn't check neighboring blocks - */ - if (new_row >= 0 && (new_row & 0x1F) == 0) - end_row = 1; - if (new_col >= 0 && (new_col & 0x1F) == 0) - end_col = 1; - - /* Check if the overlapping block partly overlaps a previous MB - * and if so, we're overlapping fewer blocks in this MB. - */ - if (new_row < (mb_row*16)<<3) - end_row = 1; - if (new_col < (mb_col*16)<<3) - end_col = 1; - - for (row = 0; row < end_row; ++row) - { - for (col = 0; col < end_col; ++col) - { - /* input in Q3, result in Q6 */ - const int overlap = block_overlap(new_row, new_col, - (((first_blk_row + row) * - 4) << 3), - (((first_blk_col + col) * - 4) << 3)); - assign_overlap(b_ol_ul[row * 4 + col].overlaps, bmi, overlap); - } - } -} - -void vp8_calculate_overlaps(MB_OVERLAP *overlap_ul, - int mb_rows, int mb_cols, - union b_mode_info *bmi, - int b_row, int b_col) -{ - MB_OVERLAP *mb_overlap; - int row, col, rel_row, rel_col; - int new_row, new_col; - int end_row, end_col; - int overlap_b_row, overlap_b_col; - int overlap_mb_row, overlap_mb_col; - - /* mb subpixel position */ - row = (4 * b_row) << 3; /* Q3 */ - col = (4 * b_col) << 3; /* Q3 */ - - /* reverse compensate for motion */ - new_row = row - bmi->mv.as_mv.row; - new_col = col - bmi->mv.as_mv.col; - - if (new_row >= ((16*mb_rows) << 3) || new_col >= ((16*mb_cols) << 3)) - { - /* the new block ended up outside the frame */ - return; - } - - if (new_row <= (-4 << 3) || new_col <= (-4 << 3)) - { - /* outside the frame */ - return; - } - /* overlapping block's position in blocks */ - overlap_b_row = FLOOR(new_row / 4, 3) >> 3; - overlap_b_col = FLOOR(new_col / 4, 3) >> 3; - - /* overlapping block's MB position in MBs - * operations are done in Q3 - */ - overlap_mb_row = FLOOR((overlap_b_row << 3) / 4, 3) >> 3; - overlap_mb_col = FLOOR((overlap_b_col << 3) / 4, 3) >> 3; - - end_row = MIN(mb_rows - overlap_mb_row, 2); - end_col = MIN(mb_cols - overlap_mb_col, 2); - - /* Don't calculate overlap for MBs we don't overlap */ - /* Check if the new block row starts at the last block row of the MB */ - if (abs(new_row - ((16*overlap_mb_row) << 3)) < ((3*4) << 3)) - end_row = 1; - /* Check if the new block col starts at the last block col of the MB */ - if (abs(new_col - ((16*overlap_mb_col) << 3)) < ((3*4) << 3)) - end_col = 1; - - /* find the MB(s) this block is overlapping */ - for (rel_row = 0; rel_row < end_row; ++rel_row) - { - for (rel_col = 0; rel_col < end_col; ++rel_col) - { - if (overlap_mb_row + rel_row < 0 || - overlap_mb_col + rel_col < 0) - continue; - mb_overlap = overlap_ul + (overlap_mb_row + rel_row) * mb_cols + - overlap_mb_col + rel_col; - - calculate_overlaps_mb(mb_overlap->overlaps, bmi, - new_row, new_col, - overlap_mb_row + rel_row, - overlap_mb_col + rel_col, - overlap_b_row + rel_row, - overlap_b_col + rel_col); - } - } -} - -/* Estimates a motion vector given the overlapping blocks' motion vectors. - * Filters out all overlapping blocks which do not refer to the correct - * reference frame type. - */ -static void estimate_mv(const OVERLAP_NODE *overlaps, union b_mode_info *bmi) -{ - int i; - int overlap_sum = 0; - int row_acc = 0; - int col_acc = 0; - - bmi->mv.as_int = 0; - for (i=0; i < MAX_OVERLAPS; ++i) - { - if (overlaps[i].bmi == NULL) - break; - col_acc += overlaps[i].overlap * overlaps[i].bmi->mv.as_mv.col; - row_acc += overlaps[i].overlap * overlaps[i].bmi->mv.as_mv.row; - overlap_sum += overlaps[i].overlap; - } - if (overlap_sum > 0) - { - /* Q9 / Q6 = Q3 */ - bmi->mv.as_mv.col = col_acc / overlap_sum; - bmi->mv.as_mv.row = row_acc / overlap_sum; - } - else - { - bmi->mv.as_mv.col = 0; - bmi->mv.as_mv.row = 0; - } -} - -/* Estimates all motion vectors for a macroblock given the lists of - * overlaps for each block. Decides whether or not the MVs must be clamped. - */ -static void estimate_mb_mvs(const B_OVERLAP *block_overlaps, - MODE_INFO *mi, - int mb_to_left_edge, - int mb_to_right_edge, - int mb_to_top_edge, - int mb_to_bottom_edge) -{ - int row, col; - int non_zero_count = 0; - MV * const filtered_mv = &(mi->mbmi.mv.as_mv); - union b_mode_info * const bmi = mi->bmi; - filtered_mv->col = 0; - filtered_mv->row = 0; - mi->mbmi.need_to_clamp_mvs = 0; - for (row = 0; row < 4; ++row) - { - int this_b_to_top_edge = mb_to_top_edge + ((row*4)<<3); - int this_b_to_bottom_edge = mb_to_bottom_edge - ((row*4)<<3); - for (col = 0; col < 4; ++col) - { - int i = row * 4 + col; - int this_b_to_left_edge = mb_to_left_edge + ((col*4)<<3); - int this_b_to_right_edge = mb_to_right_edge - ((col*4)<<3); - /* Estimate vectors for all blocks which are overlapped by this */ - /* type. Interpolate/extrapolate the rest of the block's MVs */ - estimate_mv(block_overlaps[i].overlaps, &(bmi[i])); - mi->mbmi.need_to_clamp_mvs |= vp8_check_mv_bounds( - &bmi[i].mv, - this_b_to_left_edge, - this_b_to_right_edge, - this_b_to_top_edge, - this_b_to_bottom_edge); - if (bmi[i].mv.as_int != 0) - { - ++non_zero_count; - filtered_mv->col += bmi[i].mv.as_mv.col; - filtered_mv->row += bmi[i].mv.as_mv.row; - } - } - } - if (non_zero_count > 0) - { - filtered_mv->col /= non_zero_count; - filtered_mv->row /= non_zero_count; - } -} - -static void calc_prev_mb_overlaps(MB_OVERLAP *overlaps, MODE_INFO *prev_mi, - int mb_row, int mb_col, - int mb_rows, int mb_cols) -{ - int sub_row; - int sub_col; - for (sub_row = 0; sub_row < 4; ++sub_row) - { - for (sub_col = 0; sub_col < 4; ++sub_col) - { - vp8_calculate_overlaps( - overlaps, mb_rows, mb_cols, - &(prev_mi->bmi[sub_row * 4 + sub_col]), - 4 * mb_row + sub_row, - 4 * mb_col + sub_col); - } - } -} - -/* Estimate all missing motion vectors. This function does the same as the one - * above, but has different input arguments. */ -static void estimate_missing_mvs(MB_OVERLAP *overlaps, - MODE_INFO *mi, MODE_INFO *prev_mi, - int mb_rows, int mb_cols, - unsigned int first_corrupt) -{ - int mb_row, mb_col; - vpx_memset(overlaps, 0, sizeof(MB_OVERLAP) * mb_rows * mb_cols); - /* First calculate the overlaps for all blocks */ - for (mb_row = 0; mb_row < mb_rows; ++mb_row) - { - for (mb_col = 0; mb_col < mb_cols; ++mb_col) - { - /* We're only able to use blocks referring to the last frame - * when extrapolating new vectors. - */ - if (prev_mi->mbmi.ref_frame == LAST_FRAME) - { - calc_prev_mb_overlaps(overlaps, prev_mi, - mb_row, mb_col, - mb_rows, mb_cols); - } - ++prev_mi; - } - ++prev_mi; - } - - mb_row = first_corrupt / mb_cols; - mb_col = first_corrupt - mb_row * mb_cols; - mi += mb_row*(mb_cols + 1) + mb_col; - /* Go through all macroblocks in the current image with missing MVs - * and calculate new MVs using the overlaps. - */ - for (; mb_row < mb_rows; ++mb_row) - { - int mb_to_top_edge = -((mb_row * 16)) << 3; - int mb_to_bottom_edge = ((mb_rows - 1 - mb_row) * 16) << 3; - for (; mb_col < mb_cols; ++mb_col) - { - int mb_to_left_edge = -((mb_col * 16) << 3); - int mb_to_right_edge = ((mb_cols - 1 - mb_col) * 16) << 3; - const B_OVERLAP *block_overlaps = - overlaps[mb_row*mb_cols + mb_col].overlaps; - mi->mbmi.ref_frame = LAST_FRAME; - mi->mbmi.mode = SPLITMV; - mi->mbmi.uv_mode = DC_PRED; - mi->mbmi.partitioning = 3; - mi->mbmi.segment_id = 0; - estimate_mb_mvs(block_overlaps, - mi, - mb_to_left_edge, - mb_to_right_edge, - mb_to_top_edge, - mb_to_bottom_edge); - ++mi; - } - mb_col = 0; - ++mi; - } -} - -void vp8_estimate_missing_mvs(VP8D_COMP *pbi) -{ - VP8_COMMON * const pc = &pbi->common; - estimate_missing_mvs(pbi->overlaps, - pc->mi, pc->prev_mi, - pc->mb_rows, pc->mb_cols, - pbi->mvs_corrupt_from_mb); -} - -static void assign_neighbor(EC_BLOCK *neighbor, MODE_INFO *mi, int block_idx) -{ - assert(mi->mbmi.ref_frame < MAX_REF_FRAMES); - neighbor->ref_frame = mi->mbmi.ref_frame; - neighbor->mv = mi->bmi[block_idx].mv.as_mv; -} - -/* Finds the neighboring blocks of a macroblocks. In the general case - * 20 blocks are found. If a fewer number of blocks are found due to - * image boundaries, those positions in the EC_BLOCK array are left "empty". - * The neighbors are enumerated with the upper-left neighbor as the first - * element, the second element refers to the neighbor to right of the previous - * neighbor, and so on. The last element refers to the neighbor below the first - * neighbor. - */ -static void find_neighboring_blocks(MODE_INFO *mi, - EC_BLOCK *neighbors, - int mb_row, int mb_col, - int mb_rows, int mb_cols, - int mi_stride) -{ - int i = 0; - int j; - if (mb_row > 0) - { - /* upper left */ - if (mb_col > 0) - assign_neighbor(&neighbors[i], mi - mi_stride - 1, 15); - ++i; - /* above */ - for (j = 12; j < 16; ++j, ++i) - assign_neighbor(&neighbors[i], mi - mi_stride, j); - } - else - i += 5; - if (mb_col < mb_cols - 1) - { - /* upper right */ - if (mb_row > 0) - assign_neighbor(&neighbors[i], mi - mi_stride + 1, 12); - ++i; - /* right */ - for (j = 0; j <= 12; j += 4, ++i) - assign_neighbor(&neighbors[i], mi + 1, j); - } - else - i += 5; - if (mb_row < mb_rows - 1) - { - /* lower right */ - if (mb_col < mb_cols - 1) - assign_neighbor(&neighbors[i], mi + mi_stride + 1, 0); - ++i; - /* below */ - for (j = 0; j < 4; ++j, ++i) - assign_neighbor(&neighbors[i], mi + mi_stride, j); - } - else - i += 5; - if (mb_col > 0) - { - /* lower left */ - if (mb_row < mb_rows - 1) - assign_neighbor(&neighbors[i], mi + mi_stride - 1, 4); - ++i; - /* left */ - for (j = 3; j < 16; j += 4, ++i) - { - assign_neighbor(&neighbors[i], mi - 1, j); - } - } - else - i += 5; - assert(i == 20); -} - -/* Calculates which reference frame type is dominating among the neighbors */ -static MV_REFERENCE_FRAME dominant_ref_frame(EC_BLOCK *neighbors) -{ - /* Default to referring to "skip" */ - MV_REFERENCE_FRAME dom_ref_frame = LAST_FRAME; - int max_ref_frame_cnt = 0; - int ref_frame_cnt[MAX_REF_FRAMES] = {0}; - int i; - /* Count neighboring reference frames */ - for (i = 0; i < NUM_NEIGHBORS; ++i) - { - if (neighbors[i].ref_frame < MAX_REF_FRAMES && - neighbors[i].ref_frame != INTRA_FRAME) - ++ref_frame_cnt[neighbors[i].ref_frame]; - } - /* Find maximum */ - for (i = 0; i < MAX_REF_FRAMES; ++i) - { - if (ref_frame_cnt[i] > max_ref_frame_cnt) - { - dom_ref_frame = i; - max_ref_frame_cnt = ref_frame_cnt[i]; - } - } - return dom_ref_frame; -} - -/* Interpolates all motion vectors for a macroblock from the neighboring blocks' - * motion vectors. - */ -static void interpolate_mvs(MACROBLOCKD *mb, - EC_BLOCK *neighbors, - MV_REFERENCE_FRAME dom_ref_frame) -{ - int row, col, i; - MODE_INFO * const mi = mb->mode_info_context; - /* Table with the position of the neighboring blocks relative the position - * of the upper left block of the current MB. Starting with the upper left - * neighbor and going to the right. - */ - const EC_POS neigh_pos[NUM_NEIGHBORS] = { - {-1,-1}, {-1,0}, {-1,1}, {-1,2}, {-1,3}, - {-1,4}, {0,4}, {1,4}, {2,4}, {3,4}, - {4,4}, {4,3}, {4,2}, {4,1}, {4,0}, - {4,-1}, {3,-1}, {2,-1}, {1,-1}, {0,-1} - }; - mi->mbmi.need_to_clamp_mvs = 0; - for (row = 0; row < 4; ++row) - { - int mb_to_top_edge = mb->mb_to_top_edge + ((row*4)<<3); - int mb_to_bottom_edge = mb->mb_to_bottom_edge - ((row*4)<<3); - for (col = 0; col < 4; ++col) - { - int mb_to_left_edge = mb->mb_to_left_edge + ((col*4)<<3); - int mb_to_right_edge = mb->mb_to_right_edge - ((col*4)<<3); - int w_sum = 0; - int mv_row_sum = 0; - int mv_col_sum = 0; - int_mv * const mv = &(mi->bmi[row*4 + col].mv); - mv->as_int = 0; - for (i = 0; i < NUM_NEIGHBORS; ++i) - { - /* Calculate the weighted sum of neighboring MVs referring - * to the dominant frame type. - */ - const int w = weights_q7[abs(row - neigh_pos[i].row)] - [abs(col - neigh_pos[i].col)]; - if (neighbors[i].ref_frame != dom_ref_frame) - continue; - w_sum += w; - /* Q7 * Q3 = Q10 */ - mv_row_sum += w*neighbors[i].mv.row; - mv_col_sum += w*neighbors[i].mv.col; - } - if (w_sum > 0) - { - /* Avoid division by zero. - * Normalize with the sum of the coefficients - * Q3 = Q10 / Q7 - */ - mv->as_mv.row = mv_row_sum / w_sum; - mv->as_mv.col = mv_col_sum / w_sum; - mi->mbmi.need_to_clamp_mvs |= vp8_check_mv_bounds( - mv, - mb_to_left_edge, - mb_to_right_edge, - mb_to_top_edge, - mb_to_bottom_edge); - } - } - } -} - -void vp8_interpolate_motion(MACROBLOCKD *mb, - int mb_row, int mb_col, - int mb_rows, int mb_cols, - int mi_stride) -{ - /* Find relevant neighboring blocks */ - EC_BLOCK neighbors[NUM_NEIGHBORS]; - MV_REFERENCE_FRAME dom_ref_frame; - int i; - /* Initialize the array. MAX_REF_FRAMES is interpreted as "doesn't exist" */ - for (i = 0; i < NUM_NEIGHBORS; ++i) - { - neighbors[i].ref_frame = MAX_REF_FRAMES; - neighbors[i].mv.row = neighbors[i].mv.col = 0; - } - find_neighboring_blocks(mb->mode_info_context, - neighbors, - mb_row, mb_col, - mb_rows, mb_cols, - mb->mode_info_stride); - /* Determine the dominant block type */ - dom_ref_frame = dominant_ref_frame(neighbors); - /* Interpolate MVs for the missing blocks - * from the dominating MVs */ - interpolate_mvs(mb, neighbors, dom_ref_frame); - - mb->mode_info_context->mbmi.ref_frame = dom_ref_frame; - mb->mode_info_context->mbmi.mode = SPLITMV; - mb->mode_info_context->mbmi.uv_mode = DC_PRED; - mb->mode_info_context->mbmi.partitioning = 3; - mb->mode_info_context->mbmi.segment_id = 0; -} - -void vp8_conceal_corrupt_mb(MACROBLOCKD *xd) -{ - /* This macroblock has corrupt residual, use the motion compensated - image (predictor) for concealment */ - vp8_recon_copy16x16(xd->predictor, 16, xd->dst.y_buffer, xd->dst.y_stride); - vp8_recon_copy8x8(xd->predictor + 256, 8, - xd->dst.u_buffer, xd->dst.uv_stride); - vp8_recon_copy8x8(xd->predictor + 320, 8, - xd->dst.v_buffer, xd->dst.uv_stride); -} diff --git a/vp8/decoder/error_concealment.h b/vp8/decoder/error_concealment.h deleted file mode 100644 index 65ae9d9be..000000000 --- a/vp8/decoder/error_concealment.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2011 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -#ifndef ERROR_CONCEALMENT_H -#define ERROR_CONCEALMENT_H - -#include "onyxd_int.h" -#include "ec_types.h" - -/* Allocate memory for the overlap lists */ -int vp8_alloc_overlap_lists(VP8D_COMP *pbi); - -/* Deallocate the overlap lists */ -void vp8_de_alloc_overlap_lists(VP8D_COMP *pbi); - -/* Estimate all missing motion vectors. */ -void vp8_estimate_missing_mvs(VP8D_COMP *pbi); - -/* Functions for spatial MV interpolation */ - -/* Interpolates all motion vectors for a macroblock mb at position - * (mb_row, mb_col). */ -void vp8_interpolate_motion(MACROBLOCKD *mb, - int mb_row, int mb_col, - int mb_rows, int mb_cols, - int mi_stride); - -/* Conceal a macroblock with corrupt residual. - * Copies the prediction signal to the reconstructed image. - */ -void vp8_conceal_corrupt_mb(MACROBLOCKD *xd); - -#endif diff --git a/vp8/decoder/generic/dsystemdependent.c b/vp8/decoder/generic/dsystemdependent.c index 0325fdf1c..fbba1b50a 100644 --- a/vp8/decoder/generic/dsystemdependent.c +++ b/vp8/decoder/generic/dsystemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/decoder/dequantize.h" #include "vp8/decoder/onyxd_int.h" @@ -21,6 +21,12 @@ void vp8_dmachine_specific_config(VP8D_COMP *pbi) /* Pure C: */ #if CONFIG_RUNTIME_CPU_DETECT pbi->mb.rtcd = &pbi->common.rtcd; + pbi->dequant.block_2x2 = vp8_dequantize_b_2x2_c; + pbi->dequant.idct_add_8x8 = vp8_dequant_idct_add_8x8_c; + pbi->dequant.dc_idct_add_8x8 = vp8_dequant_dc_idct_add_8x8_c; + pbi->dequant.dc_idct_add_y_block_8x8 = vp8_dequant_dc_idct_add_y_block_8x8_c; + pbi->dequant.idct_add_y_block_8x8 = vp8_dequant_idct_add_y_block_8x8_c; + pbi->dequant.idct_add_uv_block_8x8 = vp8_dequant_idct_add_uv_block_8x8_c; pbi->dequant.block = vp8_dequantize_b_c; pbi->dequant.idct_add = vp8_dequant_idct_add_c; pbi->dequant.dc_idct_add = vp8_dequant_dc_idct_add_c; @@ -38,11 +44,9 @@ void vp8_dmachine_specific_config(VP8D_COMP *pbi) vp8_arch_arm_decode_init(pbi); #endif -#if CONFIG_EXTEND_QRANGE pbi->dequant.idct_add = vp8_dequant_idct_add_c; pbi->dequant.dc_idct_add = vp8_dequant_dc_idct_add_c; pbi->dequant.dc_idct_add_y_block = vp8_dequant_dc_idct_add_y_block_c; pbi->dequant.idct_add_y_block = vp8_dequant_idct_add_y_block_c; pbi->dequant.idct_add_uv_block = vp8_dequant_idct_add_uv_block_c; -#endif } diff --git a/vp8/decoder/idct_blk.c b/vp8/decoder/idct_blk.c index 04bce665e..16ac46c48 100644 --- a/vp8/decoder/idct_blk.c +++ b/vp8/decoder/idct_blk.c @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/idct.h" #include "dequantize.h" @@ -122,3 +122,45 @@ void vp8_dequant_idct_add_uv_block_c dstv += 4*stride - 8; } } + + +void vp8_dequant_dc_idct_add_y_block_8x8_c + (short *q, short *dq, unsigned char *pre, + unsigned char *dst, int stride, char *eobs, short *dc, MACROBLOCKD *xd) +{ + + vp8_dequant_dc_idct_add_8x8_c (q, dq, pre, dst, 16, stride, dc[0]); + vp8_dequant_dc_idct_add_8x8_c (&q[64], dq, pre+8, dst+8, 16, stride, dc[1]); + vp8_dequant_dc_idct_add_8x8_c (&q[128], dq, pre+8*16, dst+8*stride, 16, stride, dc[4]); + vp8_dequant_dc_idct_add_8x8_c (&q[192], dq, pre+8*16+8, dst+8*stride+8, 16, stride, dc[8]); + +} + +void vp8_dequant_idct_add_y_block_8x8_c + (short *q, short *dq, unsigned char *pre, + unsigned char *dst, int stride, char *eobs, MACROBLOCKD *xd) +{ + + + unsigned char *origdest = dst; + unsigned char *origpred = pre; + + vp8_dequant_idct_add_8x8_c (q, dq, pre, dst, 16, stride); + vp8_dequant_idct_add_8x8_c (&q[64], dq, origpred+8, origdest+8, 16, stride); + vp8_dequant_idct_add_8x8_c (&q[128], dq, origpred+8*16, origdest+8*stride, 16, stride); + vp8_dequant_idct_add_8x8_c (&q[192], dq, origpred+8*16+8, origdest+8*stride+8, 16, stride); + +} + +void vp8_dequant_idct_add_uv_block_8x8_c + (short *q, short *dq, unsigned char *pre, + unsigned char *dstu, unsigned char *dstv, int stride, char *eobs, MACROBLOCKD *xd) +{ + vp8_dequant_idct_add_8x8_c (q, dq, pre, dstu, 8, stride); + + q += 64; + pre += 64; + + vp8_dequant_idct_add_8x8_c (q, dq, pre, dstv, 8, stride); +} + diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c index 357684ab9..96649b9e6 100644 --- a/vp8/decoder/onyxd_if.c +++ b/vp8/decoder/onyxd_if.c @@ -21,8 +21,6 @@ #include "vp8/common/loopfilter.h" #include "vp8/common/swapyv12buffer.h" #include "vp8/common/g_common.h" -#include "vp8/common/threading.h" -#include "decoderthreading.h" #include #include @@ -31,9 +29,6 @@ #include "vp8/common/systemdependent.h" #include "vpx_ports/vpx_timer.h" #include "detokenize.h" -#if CONFIG_ERROR_CONCEALMENT -#include "error_concealment.h" -#endif #if ARCH_ARM #include "vpx_ports/arm.h" #endif @@ -43,6 +38,79 @@ extern void vp8cx_init_de_quantizer(VP8D_COMP *pbi); static int get_free_fb (VP8_COMMON *cm); static void ref_cnt_fb (int *buf, int *idx, int new_idx); +#if CONFIG_DEBUG +void vp8_recon_write_yuv_frame(char *name, YV12_BUFFER_CONFIG *s) +{ + FILE *yuv_file = fopen((char *)name, "ab"); + unsigned char *src = s->y_buffer; + int h = s->y_height; + + do + { + fwrite(src, s->y_width, 1, yuv_file); + src += s->y_stride; + } + while (--h); + + src = s->u_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + src = s->v_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + fclose(yuv_file); +} +#endif +//#define WRITE_RECON_BUFFER 1 +#if WRITE_RECON_BUFFER +void write_dx_frame_to_file(YV12_BUFFER_CONFIG *frame, int this_frame) +{ + + // write the frame + FILE *yframe; + int i; + char filename[255]; + + sprintf(filename, "dx\\y%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->y_height; i++) + fwrite(frame->y_buffer + i * frame->y_stride, + frame->y_width, 1, yframe); + + fclose(yframe); + sprintf(filename, "dx\\u%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->uv_height; i++) + fwrite(frame->u_buffer + i * frame->uv_stride, + frame->uv_width, 1, yframe); + + fclose(yframe); + sprintf(filename, "dx\\v%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->uv_height; i++) + fwrite(frame->v_buffer + i * frame->uv_stride, + frame->uv_width, 1, yframe); + + fclose(yframe); +} +#endif void vp8dx_initialize() { @@ -51,12 +119,12 @@ void vp8dx_initialize() if (!init_done) { vp8_initialize_common(); + vp8_init_quant_tables(); vp8_scale_machine_specific_config(); init_done = 1; } } - VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf) { VP8D_COMP *pbi = vpx_memalign(32, sizeof(VP8D_COMP)); @@ -82,11 +150,6 @@ VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf) pbi->common.current_video_frame = 0; pbi->ready_for_new_data = 1; -#if CONFIG_MULTITHREAD - pbi->max_threads = oxcf->max_threads; - vp8_decoder_create_threads(pbi); -#endif - /* vp8cx_init_de_quantizer() is first called here. Add check in frame_init_dequantizer() to avoid * unnecessary calling of vp8cx_init_de_quantizer() for every frame. */ @@ -96,30 +159,11 @@ VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf) pbi->common.error.setjmp = 0; -#if CONFIG_ERROR_CONCEALMENT - pbi->ec_enabled = oxcf->error_concealment; -#else - pbi->ec_enabled = 0; -#endif - /* Error concealment is activated after a key frame has been - * decoded without errors when error concealment is enabled. - */ - pbi->ec_active = 0; - pbi->decoded_key_frame = 0; - pbi->input_partition = oxcf->input_partition; - - /* Independent partitions is activated when a frame updates the - * token probability table to have equal probabilities over the - * PREV_COEF context. - */ - pbi->independent_partitions = 0; - return (VP8D_PTR) pbi; } - void vp8dx_remove_decompressor(VP8D_PTR ptr) { VP8D_COMP *pbi = (VP8D_COMP *) ptr; @@ -127,14 +171,10 @@ void vp8dx_remove_decompressor(VP8D_PTR ptr) if (!pbi) return; -#if CONFIG_MULTITHREAD - if (pbi->b_multithreaded_rd) - vp8mt_de_alloc_temp_buffers(pbi, pbi->common.mb_rows); - vp8_decoder_remove_threads(pbi); -#endif -#if CONFIG_ERROR_CONCEALMENT - vp8_de_alloc_overlap_lists(pbi); -#endif + // Delete sementation map + if (pbi->common.last_frame_seg_map != 0) + vpx_free(pbi->common.last_frame_seg_map); + vp8_remove_common(&pbi->common); vpx_free(pbi->mbc); vpx_free(pbi); @@ -300,6 +340,22 @@ static int swap_frame_buffers (VP8_COMMON *cm) return err; } +/* +static void vp8_print_yuv_rec_mb(VP8_COMMON *cm, int mb_row, int mb_col) +{ + YV12_BUFFER_CONFIG *s = cm->frame_to_show; + unsigned char *src = s->y_buffer; + int i, j; + + printf("After loop filter\n"); + for (i=0;i<16;i++) { + for (j=0;j<16;j++) + printf("%3d ", src[(mb_row*16+i)*s->y_stride + mb_col*16+j]); + printf("\n"); + } +} +*/ + int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsigned char *source, int64_t time_stamp) { #if HAVE_ARMV7 @@ -319,115 +375,55 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign pbi->common.error.error_code = VPX_CODEC_OK; - if (pbi->input_partition && !(source == NULL && size == 0)) + pbi->Source = source; + pbi->source_sz = size; + + if (pbi->source_sz == 0) { - /* Store a pointer to this partition and return. We haven't - * received the complete frame yet, so we will wait with decoding. - */ - assert(pbi->num_partitions < MAX_PARTITIONS); - pbi->partitions[pbi->num_partitions] = source; - pbi->partition_sizes[pbi->num_partitions] = size; - pbi->source_sz += size; - pbi->num_partitions++; - if (pbi->num_partitions > (1 << EIGHT_PARTITION) + 1) - { - pbi->common.error.error_code = VPX_CODEC_UNSUP_BITSTREAM; - pbi->common.error.setjmp = 0; - pbi->num_partitions = 0; - return -1; - } - return 0; + /* This is used to signal that we are missing frames. + * We do not know if the missing frame(s) was supposed to update + * any of the reference buffers, but we act conservative and + * mark only the last buffer as corrupted. + */ + cm->yv12_fb[cm->lst_fb_idx].corrupted = 1; } - else + +#if HAVE_ARMV7 +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->rtcd.flags & HAS_NEON) +#endif { - if (!pbi->input_partition) - { - pbi->Source = source; - pbi->source_sz = size; - } - else - { - assert(pbi->common.multi_token_partition <= EIGHT_PARTITION); - if (pbi->num_partitions == 0) - { - pbi->num_partitions = 1; - pbi->partitions[0] = NULL; - pbi->partition_sizes[0] = 0; - } - while (pbi->num_partitions < (1 << pbi->common.multi_token_partition) + 1) - { - // Reset all missing partitions - pbi->partitions[pbi->num_partitions] = - pbi->partitions[pbi->num_partitions - 1] + - pbi->partition_sizes[pbi->num_partitions - 1]; - pbi->partition_sizes[pbi->num_partitions] = 0; - pbi->num_partitions++; - } - } + vp8_push_neon(dx_store_reg); + } +#endif - if (pbi->source_sz == 0) - { - /* This is used to signal that we are missing frames. - * We do not know if the missing frame(s) was supposed to update - * any of the reference buffers, but we act conservative and - * mark only the last buffer as corrupted. - */ - cm->yv12_fb[cm->lst_fb_idx].corrupted = 1; - - /* If error concealment is disabled we won't signal missing frames to - * the decoder. - */ - if (!pbi->ec_active) - { - /* Signal that we have no frame to show. */ - cm->show_frame = 0; - - pbi->num_partitions = 0; - - /* Nothing more to do. */ - return 0; - } - } + cm->new_fb_idx = get_free_fb (cm); + if (setjmp(pbi->common.error.jmp)) + { #if HAVE_ARMV7 #if CONFIG_RUNTIME_CPU_DETECT if (cm->rtcd.flags & HAS_NEON) #endif { - vp8_push_neon(dx_store_reg); + vp8_pop_neon(dx_store_reg); } #endif + pbi->common.error.setjmp = 0; - cm->new_fb_idx = get_free_fb (cm); + /* We do not know if the missing frame(s) was supposed to update + * any of the reference buffers, but we act conservative and + * mark only the last buffer as corrupted. + */ + cm->yv12_fb[cm->lst_fb_idx].corrupted = 1; - if (setjmp(pbi->common.error.jmp)) - { -#if HAVE_ARMV7 -#if CONFIG_RUNTIME_CPU_DETECT - if (cm->rtcd.flags & HAS_NEON) -#endif - { - vp8_pop_neon(dx_store_reg); - } -#endif - pbi->common.error.setjmp = 0; - - pbi->num_partitions = 0; - - /* We do not know if the missing frame(s) was supposed to update - * any of the reference buffers, but we act conservative and - * mark only the last buffer as corrupted. - */ - cm->yv12_fb[cm->lst_fb_idx].corrupted = 1; - - if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0) - cm->fb_idx_ref_cnt[cm->new_fb_idx]--; - return -1; - } - - pbi->common.error.setjmp = 1; + if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0) + cm->fb_idx_ref_cnt[cm->new_fb_idx]--; + return -1; } + pbi->common.error.setjmp = 1; + retcode = vp8_decode_frame(pbi); if (retcode < 0) @@ -442,14 +438,11 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign #endif pbi->common.error.error_code = VPX_CODEC_ERROR; pbi->common.error.setjmp = 0; - pbi->num_partitions = 0; if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0) cm->fb_idx_ref_cnt[cm->new_fb_idx]--; return retcode; } -#if CONFIG_MULTITHREAD - if (pbi->b_multithreaded_rd && cm->multi_token_partition != ONE_PARTITION) { if (swap_frame_buffers (cm)) { @@ -463,27 +456,17 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign #endif pbi->common.error.error_code = VPX_CODEC_ERROR; pbi->common.error.setjmp = 0; - pbi->num_partitions = 0; return -1; } - } else + +#if WRITE_RECON_BUFFER + if(cm->show_frame) + write_dx_frame_to_file(cm->frame_to_show, + cm->current_video_frame); + else + write_dx_frame_to_file(cm->frame_to_show, + cm->current_video_frame+1000); #endif - { - if (swap_frame_buffers (cm)) - { -#if HAVE_ARMV7 -#if CONFIG_RUNTIME_CPU_DETECT - if (cm->rtcd.flags & HAS_NEON) -#endif - { - vp8_pop_neon(dx_store_reg); - } -#endif - pbi->common.error.error_code = VPX_CODEC_ERROR; - pbi->common.error.setjmp = 0; - pbi->num_partitions = 0; - return -1; - } if(cm->filter_level) { @@ -493,30 +476,22 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign vp8_yv12_extend_frame_borders_ptr(cm->frame_to_show); } +#if CONFIG_DEBUG + vp8_recon_write_yuv_frame("recon.yuv", cm->frame_to_show); +#endif vp8_clear_system_state(); -#if CONFIG_ERROR_CONCEALMENT - /* swap the mode infos to storage for future error concealment */ - if (pbi->ec_enabled && pbi->common.prev_mi) + if(cm->show_frame) { - const MODE_INFO* tmp = pbi->common.prev_mi; - int row, col; - pbi->common.prev_mi = pbi->common.mi; - pbi->common.mi = tmp; - - /* Propagate the segment_ids to the next frame */ - for (row = 0; row < pbi->common.mb_rows; ++row) - { - for (col = 0; col < pbi->common.mb_cols; ++col) - { - const int i = row*pbi->common.mode_info_stride + col; - pbi->common.mi[i].mbmi.segment_id = - pbi->common.prev_mi[i].mbmi.segment_id; - } - } + vpx_memcpy(cm->prev_mip, cm->mip, + (cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO)); + } + else + { + vpx_memset(cm->prev_mip, 0, + (cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO)); } -#endif /*vp8_print_modes_and_motion_vectors( cm->mi, cm->mb_rows,cm->mb_cols, cm->current_video_frame);*/ @@ -525,7 +500,6 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign pbi->ready_for_new_data = 0; pbi->last_time_stamp = time_stamp; - pbi->num_partitions = 0; pbi->source_sz = 0; #if 0 diff --git a/vp8/decoder/onyxd_int.h b/vp8/decoder/onyxd_int.h index a84f16914..289808e28 100644 --- a/vp8/decoder/onyxd_int.h +++ b/vp8/decoder/onyxd_int.h @@ -11,15 +11,13 @@ #ifndef __INC_VP8D_INT_H #define __INC_VP8D_INT_H -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/onyxd.h" #include "treereader.h" #include "vp8/common/onyxc_int.h" -#include "vp8/common/threading.h" #include "dequantize.h" -#if CONFIG_ERROR_CONCEALMENT -#include "ec_types.h" -#endif + +//#define DEC_DEBUG typedef struct { @@ -45,10 +43,12 @@ typedef struct typedef struct { int const *scan; + int const *scan_8x8; UINT8 const *ptr_block2leftabove; vp8_tree_index const *vp8_coef_tree_ptr; unsigned char *norm_ptr; UINT8 *ptr_coef_bands_x; + UINT8 *ptr_coef_bands_x_8x8; ENTROPY_CONTEXT_PLANES *A; ENTROPY_CONTEXT_PLANES *L; @@ -57,6 +57,7 @@ typedef struct BOOL_DECODER *current_bc; vp8_prob const *coef_probs[4]; + vp8_prob const *coef_probs_8x8[4]; UINT8 eob[25]; @@ -75,38 +76,6 @@ typedef struct VP8Decompressor const unsigned char *Source; unsigned int source_sz; - const unsigned char *partitions[MAX_PARTITIONS]; - unsigned int partition_sizes[MAX_PARTITIONS]; - unsigned int num_partitions; - -#if CONFIG_MULTITHREAD - /* variable for threading */ - - volatile int b_multithreaded_rd; - int max_threads; - int current_mb_col_main; - int decoding_thread_count; - int allocated_decoding_thread_count; - - int mt_baseline_filter_level[MAX_MB_SEGMENTS]; - int sync_range; - int *mt_current_mb_col; /* Each row remembers its already decoded column. */ - - unsigned char **mt_yabove_row; /* mb_rows x width */ - unsigned char **mt_uabove_row; - unsigned char **mt_vabove_row; - unsigned char **mt_yleft_col; /* mb_rows x 16 */ - unsigned char **mt_uleft_col; /* mb_rows x 8 */ - unsigned char **mt_vleft_col; /* mb_rows x 8 */ - - MB_ROW_DEC *mb_row_di; - DECODETHREAD_DATA *de_thread_data; - - pthread_t *h_decoding_thread; - sem_t *h_event_start_decoding; - sem_t h_event_end_decoding; - /* end of threading data */ -#endif vp8_reader *mbc; int64_t last_time_stamp; @@ -120,23 +89,9 @@ typedef struct VP8Decompressor vp8_dequant_rtcd_vtable_t dequant; #endif - - vp8_prob prob_intra; - vp8_prob prob_last; - vp8_prob prob_gf; vp8_prob prob_skip_false; -#if CONFIG_ERROR_CONCEALMENT - MB_OVERLAP *overlaps; - /* the mb num from which modes and mvs (first partition) are corrupt */ - unsigned int mvs_corrupt_from_mb; -#endif - int ec_enabled; - int ec_active; - int input_partition; int decoded_key_frame; - int independent_partitions; - int frame_corrupt_residual; } VP8D_COMP; diff --git a/vp8/decoder/reconintra_mt.c b/vp8/decoder/reconintra_mt.c index 9bba5b75f..b9d2b3703 100644 --- a/vp8/decoder/reconintra_mt.c +++ b/vp8/decoder/reconintra_mt.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/recon.h" #include "vp8/common/reconintra.h" #include "vpx_mem/vpx_mem.h" diff --git a/vp8/decoder/reconintra_mt.h b/vp8/decoder/reconintra_mt.h index d401295b2..b04537956 100644 --- a/vp8/decoder/reconintra_mt.h +++ b/vp8/decoder/reconintra_mt.h @@ -12,15 +12,4 @@ #ifndef __INC_RECONINTRA_MT_H #define __INC_RECONINTRA_MT_H -/* reconintra functions used in multi-threaded decoder */ -#if CONFIG_MULTITHREAD -extern void vp8mt_build_intra_predictors_mby(VP8D_COMP *pbi, MACROBLOCKD *x, int mb_row, int mb_col); -extern void vp8mt_build_intra_predictors_mby_s(VP8D_COMP *pbi, MACROBLOCKD *x, int mb_row, int mb_col); -extern void vp8mt_build_intra_predictors_mbuv(VP8D_COMP *pbi, MACROBLOCKD *x, int mb_row, int mb_col); -extern void vp8mt_build_intra_predictors_mbuv_s(VP8D_COMP *pbi, MACROBLOCKD *x, int mb_row, int mb_col); - -extern void vp8mt_predict_intra4x4(VP8D_COMP *pbi, MACROBLOCKD *x, int b_mode, unsigned char *predictor, int mb_row, int mb_col, int num); -extern void vp8mt_intra_prediction_down_copy(VP8D_COMP *pbi, MACROBLOCKD *x, int mb_row, int mb_col); -#endif - #endif diff --git a/vp8/decoder/threading.c b/vp8/decoder/threading.c deleted file mode 100644 index bfe09735c..000000000 --- a/vp8/decoder/threading.c +++ /dev/null @@ -1,1003 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -#if !defined(WIN32) && CONFIG_OS_SUPPORT == 1 -# include -#endif -#include "onyxd_int.h" -#include "vpx_mem/vpx_mem.h" -#include "vp8/common/threading.h" - -#include "vp8/common/loopfilter.h" -#include "vp8/common/extend.h" -#include "vpx_ports/vpx_timer.h" -#include "detokenize.h" -#include "vp8/common/reconinter.h" -#include "reconintra_mt.h" -#if CONFIG_ERROR_CONCEALMENT -#include "error_concealment.h" -#endif - -extern void mb_init_dequantizer(VP8D_COMP *pbi, MACROBLOCKD *xd); - -#if CONFIG_RUNTIME_CPU_DETECT -#define RTCD_VTABLE(x) (&(pbi)->common.rtcd.x) -#else -#define RTCD_VTABLE(x) NULL -#endif - -static void setup_decoding_thread_data(VP8D_COMP *pbi, MACROBLOCKD *xd, MB_ROW_DEC *mbrd, int count) -{ - VP8_COMMON *const pc = & pbi->common; - int i, j; - - for (i = 0; i < count; i++) - { - MACROBLOCKD *mbd = &mbrd[i].mbd; -#if CONFIG_RUNTIME_CPU_DETECT - mbd->rtcd = xd->rtcd; -#endif - mbd->subpixel_predict = xd->subpixel_predict; - mbd->subpixel_predict8x4 = xd->subpixel_predict8x4; - mbd->subpixel_predict8x8 = xd->subpixel_predict8x8; - mbd->subpixel_predict16x16 = xd->subpixel_predict16x16; - - mbd->mode_info_context = pc->mi + pc->mode_info_stride * (i + 1); - mbd->mode_info_stride = pc->mode_info_stride; - - mbd->frame_type = pc->frame_type; - mbd->frames_since_golden = pc->frames_since_golden; - mbd->frames_till_alt_ref_frame = pc->frames_till_alt_ref_frame; - - mbd->pre = pc->yv12_fb[pc->lst_fb_idx]; - mbd->dst = pc->yv12_fb[pc->new_fb_idx]; - - vp8_setup_block_dptrs(mbd); - vp8_build_block_doffsets(mbd); - mbd->segmentation_enabled = xd->segmentation_enabled; - mbd->mb_segement_abs_delta = xd->mb_segement_abs_delta; - vpx_memcpy(mbd->segment_feature_data, xd->segment_feature_data, sizeof(xd->segment_feature_data)); - - /*signed char ref_lf_deltas[MAX_REF_LF_DELTAS];*/ - vpx_memcpy(mbd->ref_lf_deltas, xd->ref_lf_deltas, sizeof(xd->ref_lf_deltas)); - /*signed char mode_lf_deltas[MAX_MODE_LF_DELTAS];*/ - vpx_memcpy(mbd->mode_lf_deltas, xd->mode_lf_deltas, sizeof(xd->mode_lf_deltas)); - /*unsigned char mode_ref_lf_delta_enabled; - unsigned char mode_ref_lf_delta_update;*/ - mbd->mode_ref_lf_delta_enabled = xd->mode_ref_lf_delta_enabled; - mbd->mode_ref_lf_delta_update = xd->mode_ref_lf_delta_update; - - mbd->current_bc = &pbi->bc2; - - for (j = 0; j < 25; j++) - { - mbd->block[j].dequant = xd->block[j].dequant; - } - - mbd->fullpixel_mask = 0xffffffff; - if(pc->full_pixel) - mbd->fullpixel_mask = 0xfffffff8; - - } - - for (i=0; i< pc->mb_rows; i++) - pbi->mt_current_mb_col[i]=-1; -} - - -static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, int mb_row, int mb_col) -{ - int eobtotal = 0; - int throw_residual = 0; - int i; - - if (xd->mode_info_context->mbmi.mb_skip_coeff) - { - vp8_reset_mb_tokens_context(xd); - } - else if (!vp8dx_bool_error(xd->current_bc)) - { - eobtotal = vp8_decode_mb_tokens(pbi, xd); - } - - eobtotal |= (xd->mode_info_context->mbmi.mode == B_PRED || - xd->mode_info_context->mbmi.mode == SPLITMV); - if (!eobtotal && !vp8dx_bool_error(xd->current_bc)) - { - /* Special case: Force the loopfilter to skip when eobtotal and - * mb_skip_coeff are zero. - * */ - xd->mode_info_context->mbmi.mb_skip_coeff = 1; - - /*mt_skip_recon_mb(pbi, xd, mb_row, mb_col);*/ - if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) - { - vp8mt_build_intra_predictors_mbuv_s(pbi, xd, mb_row, mb_col); - vp8mt_build_intra_predictors_mby_s(pbi, xd, mb_row, mb_col); - } - else - { - vp8_build_inter16x16_predictors_mb(xd, xd->dst.y_buffer, - xd->dst.u_buffer, xd->dst.v_buffer, - xd->dst.y_stride, xd->dst.uv_stride); - } - return; - } - - if (xd->segmentation_enabled) - mb_init_dequantizer(pbi, xd); - - /* do prediction */ - if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) - { - vp8mt_build_intra_predictors_mbuv(pbi, xd, mb_row, mb_col); - - if (xd->mode_info_context->mbmi.mode != B_PRED) - { - vp8mt_build_intra_predictors_mby(pbi, xd, mb_row, mb_col); - } else { - vp8mt_intra_prediction_down_copy(pbi, xd, mb_row, mb_col); - } - } - else - { - vp8_build_inter_predictors_mb(xd); - } - - /* When we have independent partitions we can apply residual even - * though other partitions within the frame are corrupt. - */ - throw_residual = (!pbi->independent_partitions && - pbi->frame_corrupt_residual); - throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc)); - -#if CONFIG_ERROR_CONCEALMENT - if (pbi->ec_active && - (mb_row * pbi->common.mb_cols + mb_col >= pbi->mvs_corrupt_from_mb || - throw_residual)) - { - /* MB with corrupt residuals or corrupt mode/motion vectors. - * Better to use the predictor as reconstruction. - */ - pbi->frame_corrupt_residual = 1; - vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff)); - vp8_conceal_corrupt_mb(xd); - return; - } -#endif - - /* dequantization and idct */ - if (xd->mode_info_context->mbmi.mode != B_PRED && xd->mode_info_context->mbmi.mode != SPLITMV) - { - BLOCKD *b = &xd->block[24]; - DEQUANT_INVOKE(&pbi->dequant, block)(b); - - /* do 2nd order transform on the dc block */ - if (xd->eobs[24] > 1) - { - IDCT_INVOKE(RTCD_VTABLE(idct), iwalsh16)(&b->dqcoeff[0], b->diff); - ((int *)b->qcoeff)[0] = 0; - ((int *)b->qcoeff)[1] = 0; - ((int *)b->qcoeff)[2] = 0; - ((int *)b->qcoeff)[3] = 0; - ((int *)b->qcoeff)[4] = 0; - ((int *)b->qcoeff)[5] = 0; - ((int *)b->qcoeff)[6] = 0; - ((int *)b->qcoeff)[7] = 0; - } - else - { - IDCT_INVOKE(RTCD_VTABLE(idct), iwalsh1)(&b->dqcoeff[0], b->diff); - ((int *)b->qcoeff)[0] = 0; - } - - DEQUANT_INVOKE (&pbi->dequant, dc_idct_add_y_block) - (xd->qcoeff, xd->block[0].dequant, - xd->predictor, xd->dst.y_buffer, - xd->dst.y_stride, xd->eobs, xd->block[24].diff); - } - else if (xd->mode_info_context->mbmi.mode == B_PRED) - { - for (i = 0; i < 16; i++) - { - BLOCKD *b = &xd->block[i]; - int b_mode = xd->mode_info_context->bmi[i].as_mode; - - vp8mt_predict_intra4x4(pbi, xd, b_mode, b->predictor, mb_row, mb_col, i); - - if (xd->eobs[i] > 1) - { - DEQUANT_INVOKE(&pbi->dequant, idct_add) - (b->qcoeff, b->dequant, b->predictor, - *(b->base_dst) + b->dst, 16, b->dst_stride); - } - else - { - IDCT_INVOKE(RTCD_VTABLE(idct), idct1_scalar_add) - (b->qcoeff[0] * b->dequant[0], b->predictor, - *(b->base_dst) + b->dst, 16, b->dst_stride); - ((int *)b->qcoeff)[0] = 0; - } - } - } - else - { - DEQUANT_INVOKE (&pbi->dequant, idct_add_y_block) - (xd->qcoeff, xd->block[0].dequant, - xd->predictor, xd->dst.y_buffer, - xd->dst.y_stride, xd->eobs); - } - - DEQUANT_INVOKE (&pbi->dequant, idct_add_uv_block) - (xd->qcoeff+16*16, xd->block[16].dequant, - xd->predictor+16*16, xd->dst.u_buffer, xd->dst.v_buffer, - xd->dst.uv_stride, xd->eobs+16); -} - - -static THREAD_FUNCTION thread_decoding_proc(void *p_data) -{ - int ithread = ((DECODETHREAD_DATA *)p_data)->ithread; - VP8D_COMP *pbi = (VP8D_COMP *)(((DECODETHREAD_DATA *)p_data)->ptr1); - MB_ROW_DEC *mbrd = (MB_ROW_DEC *)(((DECODETHREAD_DATA *)p_data)->ptr2); - ENTROPY_CONTEXT_PLANES mb_row_left_context; - - while (1) - { - if (pbi->b_multithreaded_rd == 0) - break; - - /*if(WaitForSingleObject(pbi->h_event_start_decoding[ithread], INFINITE) == WAIT_OBJECT_0)*/ - if (sem_wait(&pbi->h_event_start_decoding[ithread]) == 0) - { - if (pbi->b_multithreaded_rd == 0) - break; - else - { - VP8_COMMON *pc = &pbi->common; - MACROBLOCKD *xd = &mbrd->mbd; - - int mb_row; - int num_part = 1 << pbi->common.multi_token_partition; - volatile int *last_row_current_mb_col; - int nsync = pbi->sync_range; - - for (mb_row = ithread+1; mb_row < pc->mb_rows; mb_row += (pbi->decoding_thread_count + 1)) - { - int i; - int recon_yoffset, recon_uvoffset; - int mb_col; - int ref_fb_idx = pc->lst_fb_idx; - int dst_fb_idx = pc->new_fb_idx; - int recon_y_stride = pc->yv12_fb[ref_fb_idx].y_stride; - int recon_uv_stride = pc->yv12_fb[ref_fb_idx].uv_stride; - - int filter_level; - loop_filter_info_n *lfi_n = &pc->lf_info; - - pbi->mb_row_di[ithread].mb_row = mb_row; - pbi->mb_row_di[ithread].mbd.current_bc = &pbi->mbc[mb_row%num_part]; - - last_row_current_mb_col = &pbi->mt_current_mb_col[mb_row -1]; - - recon_yoffset = mb_row * recon_y_stride * 16; - recon_uvoffset = mb_row * recon_uv_stride * 8; - /* reset above block coeffs */ - - xd->above_context = pc->above_context; - xd->left_context = &mb_row_left_context; - vpx_memset(&mb_row_left_context, 0, sizeof(mb_row_left_context)); - xd->up_available = (mb_row != 0); - - xd->mb_to_top_edge = -((mb_row * 16)) << 3; - xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; - - for (mb_col = 0; mb_col < pc->mb_cols; mb_col++) - { - if ((mb_col & (nsync-1)) == 0) - { - while (mb_col > (*last_row_current_mb_col - nsync) && *last_row_current_mb_col != pc->mb_cols - 1) - { - x86_pause_hint(); - thread_sleep(0); - } - } - - /* Distance of MB to the various image edges. - * These are specified to 8th pel as they are always - * compared to values that are in 1/8th pel units. - */ - xd->mb_to_left_edge = -((mb_col * 16) << 3); - xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; - -#if CONFIG_ERROR_CONCEALMENT - { - int corrupt_residual = - (!pbi->independent_partitions && - pbi->frame_corrupt_residual) || - vp8dx_bool_error(xd->current_bc); - if (pbi->ec_active && - (xd->mode_info_context->mbmi.ref_frame == - INTRA_FRAME) && - corrupt_residual) - { - /* We have an intra block with corrupt - * coefficients, better to conceal with an inter - * block. - * Interpolate MVs from neighboring MBs - * - * Note that for the first mb with corrupt - * residual in a frame, we might not discover - * that before decoding the residual. That - * happens after this check, and therefore no - * inter concealment will be done. - */ - vp8_interpolate_motion(xd, - mb_row, mb_col, - pc->mb_rows, pc->mb_cols, - pc->mode_info_stride); - } - } -#endif - - - xd->dst.y_buffer = pc->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset; - xd->dst.u_buffer = pc->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset; - xd->dst.v_buffer = pc->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset; - - xd->left_available = (mb_col != 0); - - /* Select the appropriate reference frame for this MB */ - if (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME) - ref_fb_idx = pc->lst_fb_idx; - else if (xd->mode_info_context->mbmi.ref_frame == GOLDEN_FRAME) - ref_fb_idx = pc->gld_fb_idx; - else - ref_fb_idx = pc->alt_fb_idx; - - xd->pre.y_buffer = pc->yv12_fb[ref_fb_idx].y_buffer + recon_yoffset; - xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset; - xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset; - - if (xd->mode_info_context->mbmi.ref_frame != - INTRA_FRAME) - { - /* propagate errors from reference frames */ - xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted; - } - - decode_macroblock(pbi, xd, mb_row, mb_col); - - /* check if the boolean decoder has suffered an error */ - xd->corrupted |= vp8dx_bool_error(xd->current_bc); - - if (pbi->common.filter_level) - { - int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED && - xd->mode_info_context->mbmi.mode != SPLITMV && - xd->mode_info_context->mbmi.mb_skip_coeff); - - const int mode_index = lfi_n->mode_lf_lut[xd->mode_info_context->mbmi.mode]; - const int seg = xd->mode_info_context->mbmi.segment_id; - const int ref_frame = xd->mode_info_context->mbmi.ref_frame; - - filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; - - if( mb_row != pc->mb_rows-1 ) - { - /* Save decoded MB last row data for next-row decoding */ - vpx_memcpy((pbi->mt_yabove_row[mb_row + 1] + 32 + mb_col*16), (xd->dst.y_buffer + 15 * recon_y_stride), 16); - vpx_memcpy((pbi->mt_uabove_row[mb_row + 1] + 16 + mb_col*8), (xd->dst.u_buffer + 7 * recon_uv_stride), 8); - vpx_memcpy((pbi->mt_vabove_row[mb_row + 1] + 16 + mb_col*8), (xd->dst.v_buffer + 7 * recon_uv_stride), 8); - } - - /* save left_col for next MB decoding */ - if(mb_col != pc->mb_cols-1) - { - MODE_INFO *next = xd->mode_info_context +1; - - if (next->mbmi.ref_frame == INTRA_FRAME) - { - for (i = 0; i < 16; i++) - pbi->mt_yleft_col[mb_row][i] = xd->dst.y_buffer [i* recon_y_stride + 15]; - for (i = 0; i < 8; i++) - { - pbi->mt_uleft_col[mb_row][i] = xd->dst.u_buffer [i* recon_uv_stride + 7]; - pbi->mt_vleft_col[mb_row][i] = xd->dst.v_buffer [i* recon_uv_stride + 7]; - } - } - } - - /* loopfilter on this macroblock. */ - if (filter_level) - { - if(pc->filter_type == NORMAL_LOOPFILTER) - { - loop_filter_info lfi; - FRAME_TYPE frame_type = pc->frame_type; - const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level]; - lfi.mblim = lfi_n->mblim[filter_level]; - lfi.blim = lfi_n->blim[filter_level]; - lfi.lim = lfi_n->lim[filter_level]; - lfi.hev_thr = lfi_n->hev_thr[hev_index]; - - if (mb_col > 0) - LF_INVOKE(&pc->rtcd.loopfilter, normal_mb_v) - (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); - - if (!skip_lf) - LF_INVOKE(&pc->rtcd.loopfilter, normal_b_v) - (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); - - /* don't apply across umv border */ - if (mb_row > 0) - LF_INVOKE(&pc->rtcd.loopfilter, normal_mb_h) - (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); - - if (!skip_lf) - LF_INVOKE(&pc->rtcd.loopfilter, normal_b_h) - (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); - } - else - { - if (mb_col > 0) - LF_INVOKE(&pc->rtcd.loopfilter, simple_mb_v) - (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]); - - if (!skip_lf) - LF_INVOKE(&pc->rtcd.loopfilter, simple_b_v) - (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]); - - /* don't apply across umv border */ - if (mb_row > 0) - LF_INVOKE(&pc->rtcd.loopfilter, simple_mb_h) - (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]); - - if (!skip_lf) - LF_INVOKE(&pc->rtcd.loopfilter, simple_b_h) - (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]); - } - } - - } - - recon_yoffset += 16; - recon_uvoffset += 8; - - ++xd->mode_info_context; /* next mb */ - - xd->above_context++; - - /*pbi->mb_row_di[ithread].current_mb_col = mb_col;*/ - pbi->mt_current_mb_col[mb_row] = mb_col; - } - - /* adjust to the next row of mbs */ - if (pbi->common.filter_level) - { - if(mb_row != pc->mb_rows-1) - { - int lasty = pc->yv12_fb[ref_fb_idx].y_width + VP8BORDERINPIXELS; - int lastuv = (pc->yv12_fb[ref_fb_idx].y_width>>1) + (VP8BORDERINPIXELS>>1); - - for (i = 0; i < 4; i++) - { - pbi->mt_yabove_row[mb_row +1][lasty + i] = pbi->mt_yabove_row[mb_row +1][lasty -1]; - pbi->mt_uabove_row[mb_row +1][lastuv + i] = pbi->mt_uabove_row[mb_row +1][lastuv -1]; - pbi->mt_vabove_row[mb_row +1][lastuv + i] = pbi->mt_vabove_row[mb_row +1][lastuv -1]; - } - } - } else - vp8_extend_mb_row(&pc->yv12_fb[dst_fb_idx], xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8); - - ++xd->mode_info_context; /* skip prediction column */ - - /* since we have multithread */ - xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count; - } - } - } - /* add this to each frame */ - if ((mbrd->mb_row == pbi->common.mb_rows-1) || ((mbrd->mb_row == pbi->common.mb_rows-2) && (pbi->common.mb_rows % (pbi->decoding_thread_count+1))==1)) - { - /*SetEvent(pbi->h_event_end_decoding);*/ - sem_post(&pbi->h_event_end_decoding); - } - } - - return 0 ; -} - - -void vp8_decoder_create_threads(VP8D_COMP *pbi) -{ - int core_count = 0; - int ithread; - - pbi->b_multithreaded_rd = 0; - pbi->allocated_decoding_thread_count = 0; - - /* limit decoding threads to the max number of token partitions */ - core_count = (pbi->max_threads > 8) ? 8 : pbi->max_threads; - - /* limit decoding threads to the available cores */ - if (core_count > pbi->common.processor_core_count) - core_count = pbi->common.processor_core_count; - - if (core_count > 1) - { - pbi->b_multithreaded_rd = 1; - pbi->decoding_thread_count = core_count - 1; - - CHECK_MEM_ERROR(pbi->h_decoding_thread, vpx_malloc(sizeof(pthread_t) * pbi->decoding_thread_count)); - CHECK_MEM_ERROR(pbi->h_event_start_decoding, vpx_malloc(sizeof(sem_t) * pbi->decoding_thread_count)); - CHECK_MEM_ERROR(pbi->mb_row_di, vpx_memalign(32, sizeof(MB_ROW_DEC) * pbi->decoding_thread_count)); - vpx_memset(pbi->mb_row_di, 0, sizeof(MB_ROW_DEC) * pbi->decoding_thread_count); - CHECK_MEM_ERROR(pbi->de_thread_data, vpx_malloc(sizeof(DECODETHREAD_DATA) * pbi->decoding_thread_count)); - - for (ithread = 0; ithread < pbi->decoding_thread_count; ithread++) - { - sem_init(&pbi->h_event_start_decoding[ithread], 0, 0); - - pbi->de_thread_data[ithread].ithread = ithread; - pbi->de_thread_data[ithread].ptr1 = (void *)pbi; - pbi->de_thread_data[ithread].ptr2 = (void *) &pbi->mb_row_di[ithread]; - - pthread_create(&pbi->h_decoding_thread[ithread], 0, thread_decoding_proc, (&pbi->de_thread_data[ithread])); - } - - sem_init(&pbi->h_event_end_decoding, 0, 0); - - pbi->allocated_decoding_thread_count = pbi->decoding_thread_count; - } -} - - -void vp8mt_de_alloc_temp_buffers(VP8D_COMP *pbi, int mb_rows) -{ - int i; - - if (pbi->b_multithreaded_rd) - { - vpx_free(pbi->mt_current_mb_col); - pbi->mt_current_mb_col = NULL ; - - /* Free above_row buffers. */ - if (pbi->mt_yabove_row) - { - for (i=0; i< mb_rows; i++) - { - vpx_free(pbi->mt_yabove_row[i]); - pbi->mt_yabove_row[i] = NULL ; - } - vpx_free(pbi->mt_yabove_row); - pbi->mt_yabove_row = NULL ; - } - - if (pbi->mt_uabove_row) - { - for (i=0; i< mb_rows; i++) - { - vpx_free(pbi->mt_uabove_row[i]); - pbi->mt_uabove_row[i] = NULL ; - } - vpx_free(pbi->mt_uabove_row); - pbi->mt_uabove_row = NULL ; - } - - if (pbi->mt_vabove_row) - { - for (i=0; i< mb_rows; i++) - { - vpx_free(pbi->mt_vabove_row[i]); - pbi->mt_vabove_row[i] = NULL ; - } - vpx_free(pbi->mt_vabove_row); - pbi->mt_vabove_row = NULL ; - } - - /* Free left_col buffers. */ - if (pbi->mt_yleft_col) - { - for (i=0; i< mb_rows; i++) - { - vpx_free(pbi->mt_yleft_col[i]); - pbi->mt_yleft_col[i] = NULL ; - } - vpx_free(pbi->mt_yleft_col); - pbi->mt_yleft_col = NULL ; - } - - if (pbi->mt_uleft_col) - { - for (i=0; i< mb_rows; i++) - { - vpx_free(pbi->mt_uleft_col[i]); - pbi->mt_uleft_col[i] = NULL ; - } - vpx_free(pbi->mt_uleft_col); - pbi->mt_uleft_col = NULL ; - } - - if (pbi->mt_vleft_col) - { - for (i=0; i< mb_rows; i++) - { - vpx_free(pbi->mt_vleft_col[i]); - pbi->mt_vleft_col[i] = NULL ; - } - vpx_free(pbi->mt_vleft_col); - pbi->mt_vleft_col = NULL ; - } - } -} - - -void vp8mt_alloc_temp_buffers(VP8D_COMP *pbi, int width, int prev_mb_rows) -{ - VP8_COMMON *const pc = & pbi->common; - int i; - int uv_width; - - if (pbi->b_multithreaded_rd) - { - vp8mt_de_alloc_temp_buffers(pbi, prev_mb_rows); - - /* our internal buffers are always multiples of 16 */ - if ((width & 0xf) != 0) - width += 16 - (width & 0xf); - - if (width < 640) pbi->sync_range = 1; - else if (width <= 1280) pbi->sync_range = 8; - else if (width <= 2560) pbi->sync_range =16; - else pbi->sync_range = 32; - - uv_width = width >>1; - - /* Allocate an int for each mb row. */ - CHECK_MEM_ERROR(pbi->mt_current_mb_col, vpx_malloc(sizeof(int) * pc->mb_rows)); - - /* Allocate memory for above_row buffers. */ - CHECK_MEM_ERROR(pbi->mt_yabove_row, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); - for (i=0; i< pc->mb_rows; i++) - CHECK_MEM_ERROR(pbi->mt_yabove_row[i], vpx_calloc(sizeof(unsigned char) * (width + (VP8BORDERINPIXELS<<1)), 1)); - - CHECK_MEM_ERROR(pbi->mt_uabove_row, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); - for (i=0; i< pc->mb_rows; i++) - CHECK_MEM_ERROR(pbi->mt_uabove_row[i], vpx_calloc(sizeof(unsigned char) * (uv_width + VP8BORDERINPIXELS), 1)); - - CHECK_MEM_ERROR(pbi->mt_vabove_row, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); - for (i=0; i< pc->mb_rows; i++) - CHECK_MEM_ERROR(pbi->mt_vabove_row[i], vpx_calloc(sizeof(unsigned char) * (uv_width + VP8BORDERINPIXELS), 1)); - - /* Allocate memory for left_col buffers. */ - CHECK_MEM_ERROR(pbi->mt_yleft_col, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); - for (i=0; i< pc->mb_rows; i++) - CHECK_MEM_ERROR(pbi->mt_yleft_col[i], vpx_calloc(sizeof(unsigned char) * 16, 1)); - - CHECK_MEM_ERROR(pbi->mt_uleft_col, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); - for (i=0; i< pc->mb_rows; i++) - CHECK_MEM_ERROR(pbi->mt_uleft_col[i], vpx_calloc(sizeof(unsigned char) * 8, 1)); - - CHECK_MEM_ERROR(pbi->mt_vleft_col, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); - for (i=0; i< pc->mb_rows; i++) - CHECK_MEM_ERROR(pbi->mt_vleft_col[i], vpx_calloc(sizeof(unsigned char) * 8, 1)); - } -} - - -void vp8_decoder_remove_threads(VP8D_COMP *pbi) -{ - /* shutdown MB Decoding thread; */ - if (pbi->b_multithreaded_rd) - { - int i; - - pbi->b_multithreaded_rd = 0; - - /* allow all threads to exit */ - for (i = 0; i < pbi->allocated_decoding_thread_count; i++) - { - sem_post(&pbi->h_event_start_decoding[i]); - pthread_join(pbi->h_decoding_thread[i], NULL); - } - - for (i = 0; i < pbi->allocated_decoding_thread_count; i++) - { - sem_destroy(&pbi->h_event_start_decoding[i]); - } - - sem_destroy(&pbi->h_event_end_decoding); - - vpx_free(pbi->h_decoding_thread); - pbi->h_decoding_thread = NULL; - - vpx_free(pbi->h_event_start_decoding); - pbi->h_event_start_decoding = NULL; - - vpx_free(pbi->mb_row_di); - pbi->mb_row_di = NULL ; - - vpx_free(pbi->de_thread_data); - pbi->de_thread_data = NULL; - } -} - -void vp8mt_decode_mb_rows( VP8D_COMP *pbi, MACROBLOCKD *xd) -{ - int mb_row; - VP8_COMMON *pc = &pbi->common; - - int num_part = 1 << pbi->common.multi_token_partition; - int i; - volatile int *last_row_current_mb_col = NULL; - int nsync = pbi->sync_range; - - int filter_level = pc->filter_level; - loop_filter_info_n *lfi_n = &pc->lf_info; - - if (filter_level) - { - /* Set above_row buffer to 127 for decoding first MB row */ - vpx_memset(pbi->mt_yabove_row[0] + VP8BORDERINPIXELS-1, 127, pc->yv12_fb[pc->lst_fb_idx].y_width + 5); - vpx_memset(pbi->mt_uabove_row[0] + (VP8BORDERINPIXELS>>1)-1, 127, (pc->yv12_fb[pc->lst_fb_idx].y_width>>1) +5); - vpx_memset(pbi->mt_vabove_row[0] + (VP8BORDERINPIXELS>>1)-1, 127, (pc->yv12_fb[pc->lst_fb_idx].y_width>>1) +5); - - for (i=1; imb_rows; i++) - { - vpx_memset(pbi->mt_yabove_row[i] + VP8BORDERINPIXELS-1, (unsigned char)129, 1); - vpx_memset(pbi->mt_uabove_row[i] + (VP8BORDERINPIXELS>>1)-1, (unsigned char)129, 1); - vpx_memset(pbi->mt_vabove_row[i] + (VP8BORDERINPIXELS>>1)-1, (unsigned char)129, 1); - } - - /* Set left_col to 129 initially */ - for (i=0; imb_rows; i++) - { - vpx_memset(pbi->mt_yleft_col[i], (unsigned char)129, 16); - vpx_memset(pbi->mt_uleft_col[i], (unsigned char)129, 8); - vpx_memset(pbi->mt_vleft_col[i], (unsigned char)129, 8); - } - - /* Initialize the loop filter for this frame. */ - vp8_loop_filter_frame_init(pc, &pbi->mb, filter_level); - } - - setup_decoding_thread_data(pbi, xd, pbi->mb_row_di, pbi->decoding_thread_count); - - for (i = 0; i < pbi->decoding_thread_count; i++) - sem_post(&pbi->h_event_start_decoding[i]); - - for (mb_row = 0; mb_row < pc->mb_rows; mb_row += (pbi->decoding_thread_count + 1)) - { - xd->current_bc = &pbi->mbc[mb_row%num_part]; - - /* vp8_decode_mb_row(pbi, pc, mb_row, xd); */ - { - int i; - int recon_yoffset, recon_uvoffset; - int mb_col; - int ref_fb_idx = pc->lst_fb_idx; - int dst_fb_idx = pc->new_fb_idx; - int recon_y_stride = pc->yv12_fb[ref_fb_idx].y_stride; - int recon_uv_stride = pc->yv12_fb[ref_fb_idx].uv_stride; - - /* volatile int *last_row_current_mb_col = NULL; */ - if (mb_row > 0) - last_row_current_mb_col = &pbi->mt_current_mb_col[mb_row -1]; - - vpx_memset(&pc->left_context, 0, sizeof(pc->left_context)); - recon_yoffset = mb_row * recon_y_stride * 16; - recon_uvoffset = mb_row * recon_uv_stride * 8; - /* reset above block coeffs */ - - xd->above_context = pc->above_context; - xd->up_available = (mb_row != 0); - - xd->mb_to_top_edge = -((mb_row * 16)) << 3; - xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; - - for (mb_col = 0; mb_col < pc->mb_cols; mb_col++) - { - if ( mb_row > 0 && (mb_col & (nsync-1)) == 0){ - while (mb_col > (*last_row_current_mb_col - nsync) && *last_row_current_mb_col != pc->mb_cols - 1) - { - x86_pause_hint(); - thread_sleep(0); - } - } - - /* Distance of MB to the various image edges. - * These are specified to 8th pel as they are always compared to - * values that are in 1/8th pel units. - */ - xd->mb_to_left_edge = -((mb_col * 16) << 3); - xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; - -#if CONFIG_ERROR_CONCEALMENT - { - int corrupt_residual = (!pbi->independent_partitions && - pbi->frame_corrupt_residual) || - vp8dx_bool_error(xd->current_bc); - if (pbi->ec_active && - (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) && - corrupt_residual) - { - /* We have an intra block with corrupt coefficients, - * better to conceal with an inter block. Interpolate - * MVs from neighboring MBs - * - * Note that for the first mb with corrupt residual in a - * frame, we might not discover that before decoding the - * residual. That happens after this check, and - * therefore no inter concealment will be done. - */ - vp8_interpolate_motion(xd, - mb_row, mb_col, - pc->mb_rows, pc->mb_cols, - pc->mode_info_stride); - } - } -#endif - - - xd->dst.y_buffer = pc->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset; - xd->dst.u_buffer = pc->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset; - xd->dst.v_buffer = pc->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset; - - xd->left_available = (mb_col != 0); - - /* Select the appropriate reference frame for this MB */ - if (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME) - ref_fb_idx = pc->lst_fb_idx; - else if (xd->mode_info_context->mbmi.ref_frame == GOLDEN_FRAME) - ref_fb_idx = pc->gld_fb_idx; - else - ref_fb_idx = pc->alt_fb_idx; - - xd->pre.y_buffer = pc->yv12_fb[ref_fb_idx].y_buffer + recon_yoffset; - xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset; - xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset; - - if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME) - { - /* propagate errors from reference frames */ - xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted; - } - - decode_macroblock(pbi, xd, mb_row, mb_col); - - /* check if the boolean decoder has suffered an error */ - xd->corrupted |= vp8dx_bool_error(xd->current_bc); - - if (pbi->common.filter_level) - { - int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED && - xd->mode_info_context->mbmi.mode != SPLITMV && - xd->mode_info_context->mbmi.mb_skip_coeff); - - const int mode_index = lfi_n->mode_lf_lut[xd->mode_info_context->mbmi.mode]; - const int seg = xd->mode_info_context->mbmi.segment_id; - const int ref_frame = xd->mode_info_context->mbmi.ref_frame; - - filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; - - /* Save decoded MB last row data for next-row decoding */ - if(mb_row != pc->mb_rows-1) - { - vpx_memcpy((pbi->mt_yabove_row[mb_row +1] + 32 + mb_col*16), (xd->dst.y_buffer + 15 * recon_y_stride), 16); - vpx_memcpy((pbi->mt_uabove_row[mb_row +1] + 16 + mb_col*8), (xd->dst.u_buffer + 7 * recon_uv_stride), 8); - vpx_memcpy((pbi->mt_vabove_row[mb_row +1] + 16 + mb_col*8), (xd->dst.v_buffer + 7 * recon_uv_stride), 8); - } - - /* save left_col for next MB decoding */ - if(mb_col != pc->mb_cols-1) - { - MODE_INFO *next = xd->mode_info_context +1; - - if (next->mbmi.ref_frame == INTRA_FRAME) - { - for (i = 0; i < 16; i++) - pbi->mt_yleft_col[mb_row][i] = xd->dst.y_buffer [i* recon_y_stride + 15]; - for (i = 0; i < 8; i++) - { - pbi->mt_uleft_col[mb_row][i] = xd->dst.u_buffer [i* recon_uv_stride + 7]; - pbi->mt_vleft_col[mb_row][i] = xd->dst.v_buffer [i* recon_uv_stride + 7]; - } - } - } - - /* loopfilter on this macroblock. */ - if (filter_level) - { - if(pc->filter_type == NORMAL_LOOPFILTER) - { - loop_filter_info lfi; - FRAME_TYPE frame_type = pc->frame_type; - const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level]; - lfi.mblim = lfi_n->mblim[filter_level]; - lfi.blim = lfi_n->blim[filter_level]; - lfi.lim = lfi_n->lim[filter_level]; - lfi.hev_thr = lfi_n->hev_thr[hev_index]; - - if (mb_col > 0) - LF_INVOKE(&pc->rtcd.loopfilter, normal_mb_v) - (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); - - if (!skip_lf) - LF_INVOKE(&pc->rtcd.loopfilter, normal_b_v) - (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); - - /* don't apply across umv border */ - if (mb_row > 0) - LF_INVOKE(&pc->rtcd.loopfilter, normal_mb_h) - (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); - - if (!skip_lf) - LF_INVOKE(&pc->rtcd.loopfilter, normal_b_h) - (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); - } - else - { - if (mb_col > 0) - LF_INVOKE(&pc->rtcd.loopfilter, simple_mb_v) - (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]); - - if (!skip_lf) - LF_INVOKE(&pc->rtcd.loopfilter, simple_b_v) - (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]); - - /* don't apply across umv border */ - if (mb_row > 0) - LF_INVOKE(&pc->rtcd.loopfilter, simple_mb_h) - (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]); - - if (!skip_lf) - LF_INVOKE(&pc->rtcd.loopfilter, simple_b_h) - (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]); - } - } - - } - recon_yoffset += 16; - recon_uvoffset += 8; - - ++xd->mode_info_context; /* next mb */ - - xd->above_context++; - - pbi->mt_current_mb_col[mb_row] = mb_col; - } - - /* adjust to the next row of mbs */ - if (pbi->common.filter_level) - { - if(mb_row != pc->mb_rows-1) - { - int lasty = pc->yv12_fb[ref_fb_idx].y_width + VP8BORDERINPIXELS; - int lastuv = (pc->yv12_fb[ref_fb_idx].y_width>>1) + (VP8BORDERINPIXELS>>1); - - for (i = 0; i < 4; i++) - { - pbi->mt_yabove_row[mb_row +1][lasty + i] = pbi->mt_yabove_row[mb_row +1][lasty -1]; - pbi->mt_uabove_row[mb_row +1][lastuv + i] = pbi->mt_uabove_row[mb_row +1][lastuv -1]; - pbi->mt_vabove_row[mb_row +1][lastuv + i] = pbi->mt_vabove_row[mb_row +1][lastuv -1]; - } - } - }else - vp8_extend_mb_row(&pc->yv12_fb[dst_fb_idx], xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8); - - ++xd->mode_info_context; /* skip prediction column */ - } - xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count; - } - - sem_wait(&pbi->h_event_end_decoding); /* add back for each frame */ -} diff --git a/vp8/decoder/x86/idct_blk_mmx.c b/vp8/decoder/x86/idct_blk_mmx.c index 558dbaf7e..8f1a363cd 100644 --- a/vp8/decoder/x86/idct_blk_mmx.c +++ b/vp8/decoder/x86/idct_blk_mmx.c @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/idct.h" #include "vp8/decoder/dequantize.h" diff --git a/vp8/decoder/x86/idct_blk_sse2.c b/vp8/decoder/x86/idct_blk_sse2.c index a6a720639..3a4806862 100644 --- a/vp8/decoder/x86/idct_blk_sse2.c +++ b/vp8/decoder/x86/idct_blk_sse2.c @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/idct.h" #include "vp8/decoder/dequantize.h" diff --git a/vp8/decoder/x86/x86_dsystemdependent.c b/vp8/decoder/x86/x86_dsystemdependent.c index 443150483..a244a3a98 100644 --- a/vp8/decoder/x86/x86_dsystemdependent.c +++ b/vp8/decoder/x86/x86_dsystemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_ports/x86.h" #include "vp8/decoder/onyxd_int.h" diff --git a/vp8/encoder/arm/arm_csystemdependent.c b/vp8/encoder/arm/arm_csystemdependent.c index 210a5a5c5..e66835ae0 100644 --- a/vp8/encoder/arm/arm_csystemdependent.c +++ b/vp8/encoder/arm/arm_csystemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_ports/arm.h" #include "vp8/encoder/variance.h" #include "vp8/encoder/onyx_int.h" @@ -56,8 +56,6 @@ void vp8_arch_arm_encoder_init(VP8_COMP *cpi) cpi->rtcd.variance.mse16x16 = vp8_mse16x16_armv6; /*cpi->rtcd.variance.getmbss = vp8_get_mb_ss_c;*/ - /*cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_c;*/ - cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_armv6; cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_armv6; cpi->rtcd.fdct.fast4x4 = vp8_short_fdct4x4_armv6; @@ -103,8 +101,6 @@ void vp8_arch_arm_encoder_init(VP8_COMP *cpi) cpi->rtcd.variance.mse16x16 = vp8_mse16x16_neon; /*cpi->rtcd.variance.getmbss = vp8_get_mb_ss_c;*/ - cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_neon; - cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_neon; cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_neon; cpi->rtcd.fdct.fast4x4 = vp8_short_fdct4x4_neon; diff --git a/vp8/encoder/arm/variance_arm.c b/vp8/encoder/arm/variance_arm.c index e77be9f73..6e83c6e7b 100644 --- a/vp8/encoder/arm/variance_arm.c +++ b/vp8/encoder/arm/variance_arm.c @@ -13,6 +13,12 @@ #include "vp8/common/filter.h" #include "vp8/common/arm/bilinearfilter_arm.h" +#if CONFIG_SIXTEENTH_SUBPEL_UV +#define HALFNDX 8 +#else +#define HALFNDX 4 +#endif + #if HAVE_ARMV6 unsigned int vp8_sub_pixel_variance8x8_armv6 @@ -59,17 +65,17 @@ unsigned int vp8_sub_pixel_variance16x16_armv6 const short *HFilter, *VFilter; unsigned int var; - if (xoffset == 4 && yoffset == 0) + if (xoffset == HALFNDX && yoffset == 0) { var = vp8_variance_halfpixvar16x16_h_armv6(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); } - else if (xoffset == 0 && yoffset == 4) + else if (xoffset == 0 && yoffset == HALFNDX) { var = vp8_variance_halfpixvar16x16_v_armv6(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); } - else if (xoffset == 4 && yoffset == 4) + else if (xoffset == HALFNDX && yoffset == HALFNDX) { var = vp8_variance_halfpixvar16x16_hv_armv6(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); @@ -107,11 +113,11 @@ unsigned int vp8_sub_pixel_variance16x16_neon unsigned int *sse ) { - if (xoffset == 4 && yoffset == 0) + if (xoffset == HALFNDX && yoffset == 0) return vp8_variance_halfpixvar16x16_h_neon(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); - else if (xoffset == 0 && yoffset == 4) + else if (xoffset == 0 && yoffset == HALFNDX) return vp8_variance_halfpixvar16x16_v_neon(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); - else if (xoffset == 4 && yoffset == 4) + else if (xoffset == HALFNDX && yoffset == HALFNDX) return vp8_variance_halfpixvar16x16_hv_neon(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); else return vp8_sub_pixel_variance16x16_neon_func(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); diff --git a/vp8/encoder/arm/variance_arm.h b/vp8/encoder/arm/variance_arm.h index f2f761f9e..fdb7289b1 100644 --- a/vp8/encoder/arm/variance_arm.h +++ b/vp8/encoder/arm/variance_arm.h @@ -83,7 +83,6 @@ extern prototype_variance(vp8_variance_halfpixvar16x16_hv_neon); //extern prototype_getmbss(vp8_get_mb_ss_c); extern prototype_variance(vp8_mse16x16_neon); -extern prototype_get16x16prederror(vp8_get4x4sse_cs_neon); #if !CONFIG_RUNTIME_CPU_DETECT #undef vp8_variance_sad4x4 @@ -146,8 +145,6 @@ extern prototype_get16x16prederror(vp8_get4x4sse_cs_neon); #undef vp8_variance_mse16x16 #define vp8_variance_mse16x16 vp8_mse16x16_neon -#undef vp8_variance_get4x4sse_cs -#define vp8_variance_get4x4sse_cs vp8_get4x4sse_cs_neon #endif #endif diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c index cea8e1232..8906f93fd 100644 --- a/vp8/encoder/bitstream.c +++ b/vp8/encoder/bitstream.c @@ -23,27 +23,10 @@ #include "vpx_mem/vpx_mem.h" #include "bitstream.h" -#include "defaultcoefcounts.h" +#include "vp8/common/defaultcoefcounts.h" -const int vp8cx_base_skip_false_prob[128] = -{ - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 251, 248, 244, 240, 236, 232, 229, 225, - 221, 217, 213, 208, 204, 199, 194, 190, - 187, 183, 179, 175, 172, 168, 164, 160, - 157, 153, 149, 145, 142, 138, 134, 130, - 127, 124, 120, 117, 114, 110, 107, 104, - 101, 98, 95, 92, 89, 86, 83, 80, - 77, 74, 71, 68, 65, 62, 59, 56, - 53, 50, 47, 44, 41, 38, 35, 32, - 30, 28, 26, 24, 22, 20, 18, 16, -}; +#include "vp8/common/seg_common.h" +#include "vp8/common/pred_common.h" #if defined(SECTIONBITS_OUTPUT) unsigned __int64 Sectionbits[500]; @@ -52,6 +35,8 @@ unsigned __int64 Sectionbits[500]; #ifdef ENTROPY_STATS int intra_mode_stats[10][10][10]; static unsigned int tree_update_hist [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES] [2]; +static unsigned int tree_update_hist_8x8 [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES] [2]; + extern unsigned int active_section; #endif @@ -59,7 +44,6 @@ extern unsigned int active_section; int count_mb_seg[4] = { 0, 0, 0, 0 }; #endif - static void update_mode( vp8_writer *const w, int n, @@ -121,13 +105,16 @@ static void update_mbintra_mode_probs(VP8_COMP *cpi) ); } { +#if CONFIG_UVINTRA + //vp8_write_bit(w, 0); +#else vp8_prob Pnew [VP8_UV_MODES-1]; unsigned int bct [VP8_UV_MODES-1] [2]; - update_mode( w, VP8_UV_MODES, vp8_uv_mode_encodings, vp8_uv_mode_tree, Pnew, x->fc.uv_mode_prob, bct, (unsigned int *)cpi->uv_mode_count ); +#endif } } @@ -141,6 +128,11 @@ static void kfwrite_ymode(vp8_writer *bc, int m, const vp8_prob *p) vp8_write_token(bc, vp8_kf_ymode_tree, p, vp8_kf_ymode_encodings + m); } +static void write_i8x8_mode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc,vp8_i8x8_mode_tree, p, vp8_i8x8_mode_encodings + m); +} + static void write_uv_mode(vp8_writer *bc, int m, const vp8_prob *p) { vp8_write_token(bc, vp8_uv_mode_tree, p, vp8_uv_mode_encodings + m); @@ -358,415 +350,6 @@ static void write_partition_size(unsigned char *cx_data, int size) } -static void pack_tokens_into_partitions_c(VP8_COMP *cpi, unsigned char *cx_data, int num_part, int *size) -{ - - int i; - unsigned char *ptr = cx_data; - unsigned int shift; - vp8_writer *w = &cpi->bc2; - *size = 3 * (num_part - 1); - cpi->partition_sz[0] += *size; - ptr = cx_data + (*size); - - for (i = 0; i < num_part; i++) - { - vp8_start_encode(w, ptr); - { - unsigned int split; - int count = w->count; - unsigned int range = w->range; - unsigned int lowvalue = w->lowvalue; - int mb_row; - - for (mb_row = i; mb_row < cpi->common.mb_rows; mb_row += num_part) - { - TOKENEXTRA *p = cpi->tplist[mb_row].start; - TOKENEXTRA *stop = cpi->tplist[mb_row].stop; - - while (p < stop) - { - const int t = p->Token; - vp8_token *const a = vp8_coef_encodings + t; - const vp8_extra_bit_struct *const b = vp8_extra_bits + t; - int i = 0; - const unsigned char *pp = p->context_tree; - int v = a->value; - int n = a->Len; - - if (p->skip_eob_node) - { - n--; - i = 2; - } - - do - { - const int bb = (v >> --n) & 1; - split = 1 + (((range - 1) * pp[i>>1]) >> 8); - i = vp8_coef_tree[i+bb]; - - if (bb) - { - lowvalue += split; - range = range - split; - } - else - { - range = split; - } - - shift = vp8_norm[range]; - range <<= shift; - count += shift; - - if (count >= 0) - { - int offset = shift - count; - - if ((lowvalue << (offset - 1)) & 0x80000000) - { - int x = w->pos - 1; - - while (x >= 0 && w->buffer[x] == 0xff) - { - w->buffer[x] = (unsigned char)0; - x--; - } - - w->buffer[x] += 1; - } - - w->buffer[w->pos++] = (lowvalue >> (24 - offset)); - lowvalue <<= offset; - shift = count; - lowvalue &= 0xffffff; - count -= 8 ; - } - - lowvalue <<= shift; - } - while (n); - - - if (b->base_val) - { - const int e = p->Extra, L = b->Len; - - if (L) - { - const unsigned char *pp = b->prob; - int v = e >> 1; - int n = L; /* number of bits in v, assumed nonzero */ - int i = 0; - - do - { - const int bb = (v >> --n) & 1; - split = 1 + (((range - 1) * pp[i>>1]) >> 8); - i = b->tree[i+bb]; - - if (bb) - { - lowvalue += split; - range = range - split; - } - else - { - range = split; - } - - shift = vp8_norm[range]; - range <<= shift; - count += shift; - - if (count >= 0) - { - int offset = shift - count; - - if ((lowvalue << (offset - 1)) & 0x80000000) - { - int x = w->pos - 1; - - while (x >= 0 && w->buffer[x] == 0xff) - { - w->buffer[x] = (unsigned char)0; - x--; - } - - w->buffer[x] += 1; - } - - w->buffer[w->pos++] = (lowvalue >> (24 - offset)); - lowvalue <<= offset; - shift = count; - lowvalue &= 0xffffff; - count -= 8 ; - } - - lowvalue <<= shift; - } - while (n); - } - - { - split = (range + 1) >> 1; - - if (e & 1) - { - lowvalue += split; - range = range - split; - } - else - { - range = split; - } - - range <<= 1; - - if ((lowvalue & 0x80000000)) - { - int x = w->pos - 1; - - while (x >= 0 && w->buffer[x] == 0xff) - { - w->buffer[x] = (unsigned char)0; - x--; - } - - w->buffer[x] += 1; - - } - - lowvalue <<= 1; - - if (!++count) - { - count = -8; - w->buffer[w->pos++] = (lowvalue >> 24); - lowvalue &= 0xffffff; - } - } - - } - - ++p; - } - } - - w->count = count; - w->lowvalue = lowvalue; - w->range = range; - - } - - vp8_stop_encode(w); - *size += w->pos; - - /* The first partition size is set earlier */ - cpi->partition_sz[i + 1] = w->pos; - - if (i < (num_part - 1)) - { - write_partition_size(cx_data, w->pos); - cx_data += 3; - ptr += w->pos; - } - } -} - - -static void pack_mb_row_tokens_c(VP8_COMP *cpi, vp8_writer *w) -{ - - unsigned int split; - int count = w->count; - unsigned int range = w->range; - unsigned int lowvalue = w->lowvalue; - unsigned int shift; - int mb_row; - - for (mb_row = 0; mb_row < cpi->common.mb_rows; mb_row++) - { - TOKENEXTRA *p = cpi->tplist[mb_row].start; - TOKENEXTRA *stop = cpi->tplist[mb_row].stop; - - while (p < stop) - { - const int t = p->Token; - vp8_token *const a = vp8_coef_encodings + t; - const vp8_extra_bit_struct *const b = vp8_extra_bits + t; - int i = 0; - const unsigned char *pp = p->context_tree; - int v = a->value; - int n = a->Len; - - if (p->skip_eob_node) - { - n--; - i = 2; - } - - do - { - const int bb = (v >> --n) & 1; - split = 1 + (((range - 1) * pp[i>>1]) >> 8); - i = vp8_coef_tree[i+bb]; - - if (bb) - { - lowvalue += split; - range = range - split; - } - else - { - range = split; - } - - shift = vp8_norm[range]; - range <<= shift; - count += shift; - - if (count >= 0) - { - int offset = shift - count; - - if ((lowvalue << (offset - 1)) & 0x80000000) - { - int x = w->pos - 1; - - while (x >= 0 && w->buffer[x] == 0xff) - { - w->buffer[x] = (unsigned char)0; - x--; - } - - w->buffer[x] += 1; - } - - w->buffer[w->pos++] = (lowvalue >> (24 - offset)); - lowvalue <<= offset; - shift = count; - lowvalue &= 0xffffff; - count -= 8 ; - } - - lowvalue <<= shift; - } - while (n); - - - if (b->base_val) - { - const int e = p->Extra, L = b->Len; - - if (L) - { - const unsigned char *pp = b->prob; - int v = e >> 1; - int n = L; /* number of bits in v, assumed nonzero */ - int i = 0; - - do - { - const int bb = (v >> --n) & 1; - split = 1 + (((range - 1) * pp[i>>1]) >> 8); - i = b->tree[i+bb]; - - if (bb) - { - lowvalue += split; - range = range - split; - } - else - { - range = split; - } - - shift = vp8_norm[range]; - range <<= shift; - count += shift; - - if (count >= 0) - { - int offset = shift - count; - - if ((lowvalue << (offset - 1)) & 0x80000000) - { - int x = w->pos - 1; - - while (x >= 0 && w->buffer[x] == 0xff) - { - w->buffer[x] = (unsigned char)0; - x--; - } - - w->buffer[x] += 1; - } - - w->buffer[w->pos++] = (lowvalue >> (24 - offset)); - lowvalue <<= offset; - shift = count; - lowvalue &= 0xffffff; - count -= 8 ; - } - - lowvalue <<= shift; - } - while (n); - } - - { - split = (range + 1) >> 1; - - if (e & 1) - { - lowvalue += split; - range = range - split; - } - else - { - range = split; - } - - range <<= 1; - - if ((lowvalue & 0x80000000)) - { - int x = w->pos - 1; - - while (x >= 0 && w->buffer[x] == 0xff) - { - w->buffer[x] = (unsigned char)0; - x--; - } - - w->buffer[x] += 1; - - } - - lowvalue <<= 1; - - if (!++count) - { - count = -8; - w->buffer[w->pos++] = (lowvalue >> 24); - lowvalue &= 0xffffff; - } - } - - } - - ++p; - } - } - - w->count = count; - w->lowvalue = lowvalue; - w->range = range; - -} - static void write_mv_ref ( vp8_writer *w, MB_PREDICTION_MODE m, const vp8_prob *p @@ -803,7 +386,24 @@ static void write_mv vp8_encode_motion_vector(w, &e, mvc); } -static void write_mb_features(vp8_writer *w, const MB_MODE_INFO *mi, const MACROBLOCKD *x) +#if CONFIG_HIGH_PRECISION_MV +static void write_mv_hp +( + vp8_writer *w, const MV *mv, const int_mv *ref, const MV_CONTEXT_HP *mvc +) +{ + MV e; + e.row = mv->row - ref->as_mv.row; + e.col = mv->col - ref->as_mv.col; + + vp8_encode_motion_vector_hp(w, &e, mvc); +} +#endif + +// This function writes the current macro block's segnment id to the bitstream +// It should only be called if a segment map update is indicated. +static void write_mb_segid(vp8_writer *w, + const MB_MODE_INFO *mi, const MACROBLOCKD *x) { // Encode the MB segment id. if (x->segmentation_enabled && x->update_mb_segmentation_map) @@ -836,43 +436,161 @@ static void write_mb_features(vp8_writer *w, const MB_MODE_INFO *mi, const MACRO } } +// This function encodes the reference frame +static void encode_ref_frame( vp8_writer *const w, + VP8_COMMON *const cm, + MACROBLOCKD *xd, + int segment_id, + MV_REFERENCE_FRAME rf ) +{ + int seg_ref_active; + int seg_ref_count = 0; + seg_ref_active = segfeature_active( xd, + segment_id, + SEG_LVL_REF_FRAME ); + + if ( seg_ref_active ) + { + seg_ref_count = check_segref( xd, segment_id, INTRA_FRAME ) + + check_segref( xd, segment_id, LAST_FRAME ) + + check_segref( xd, segment_id, GOLDEN_FRAME ) + + check_segref( xd, segment_id, ALTREF_FRAME ); + } + + // If segment level coding of this signal is disabled... + // or the segment allows multiple reference frame options + if ( !seg_ref_active || (seg_ref_count > 1) ) + { + // Values used in prediction model coding + unsigned char prediction_flag; + vp8_prob pred_prob; + MV_REFERENCE_FRAME pred_rf; + + // Get the context probability the prediction flag + pred_prob = get_pred_prob( cm, xd, PRED_REF ); + + // Get the predicted value. + pred_rf = get_pred_ref( cm, xd ); + + // Did the chosen reference frame match its predicted value. + prediction_flag = + ( xd->mode_info_context->mbmi.ref_frame == pred_rf ); + + set_pred_flag( xd, PRED_REF, prediction_flag ); + vp8_write( w, prediction_flag, pred_prob ); + + // If not predicted correctly then code value explicitly + if ( !prediction_flag ) + { + vp8_prob mod_refprobs[PREDICTION_PROBS]; + + vpx_memcpy( mod_refprobs, + cm->mod_refprobs[pred_rf], sizeof(mod_refprobs) ); + + // If segment coding enabled blank out options that cant occur by + // setting the branch probability to 0. + if ( seg_ref_active ) + { + mod_refprobs[INTRA_FRAME] *= + check_segref( xd, segment_id, INTRA_FRAME ); + mod_refprobs[LAST_FRAME] *= + check_segref( xd, segment_id, LAST_FRAME ); + mod_refprobs[GOLDEN_FRAME] *= + ( check_segref( xd, segment_id, GOLDEN_FRAME ) * + check_segref( xd, segment_id, ALTREF_FRAME ) ); + } + + if ( mod_refprobs[0] ) + { + vp8_write(w, (rf != INTRA_FRAME), mod_refprobs[0] ); + } + + // Inter coded + if (rf != INTRA_FRAME) + { + if ( mod_refprobs[1] ) + { + vp8_write(w, (rf != LAST_FRAME), mod_refprobs[1] ); + } + + if (rf != LAST_FRAME) + { + if ( mod_refprobs[2] ) + { + vp8_write(w, (rf != GOLDEN_FRAME), mod_refprobs[2] ); + } + } + } + } + } + + // if using the prediction mdoel we have nothing further to do because + // the reference frame is fully coded by the segment +} + +// Update the probabilities used to encode reference frame data +static void update_ref_probs( VP8_COMP *const cpi ) +{ + VP8_COMMON *const cm = & cpi->common; + + const int *const rfct = cpi->count_mb_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + + cm->prob_intra_coded = (rf_intra + rf_inter) + ? rf_intra * 255 / (rf_intra + rf_inter) : 1; + + if (!cm->prob_intra_coded) + cm->prob_intra_coded = 1; + + cm->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + + if (!cm->prob_last_coded) + cm->prob_last_coded = 1; + + cm->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / + (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + + if (!cm->prob_gf_coded) + cm->prob_gf_coded = 1; + + // Compute a modified set of probabilities to use when prediction of the + // reference frame fails + compute_mod_refprobs( cm ); +} static void pack_inter_mode_mvs(VP8_COMP *const cpi) { VP8_COMMON *const pc = & cpi->common; vp8_writer *const w = & cpi->bc; const MV_CONTEXT *mvc = pc->fc.mvc; +#if CONFIG_HIGH_PRECISION_MV + const MV_CONTEXT_HP *mvc_hp = pc->fc.mvc_hp; +#endif + MACROBLOCKD *xd = &cpi->mb.e_mbd; - const int *const rfct = cpi->count_mb_ref_frame_usage; - const int rf_intra = rfct[INTRA_FRAME]; - const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + int i; + int pred_context; + + + MODE_INFO *m = pc->mi; + MODE_INFO *prev_m = pc->prev_mi; - MODE_INFO *m = pc->mi, *ms; const int mis = pc->mode_info_stride; int mb_row = -1; - int prob_last_coded; - int prob_gf_coded; int prob_skip_false = 0; - ms = pc->mi - 1; + + // Values used in prediction model coding + vp8_prob pred_prob; + unsigned char prediction_flag; cpi->mb.partition_info = cpi->mb.pi; - // Calculate the probabilities to be used to code the reference frame based on actual useage this frame - if (!(cpi->prob_intra_coded = rf_intra * 255 / (rf_intra + rf_inter))) - cpi->prob_intra_coded = 1; - - prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; - - if (!prob_last_coded) - prob_last_coded = 1; - - prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) - ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; - - if (!prob_gf_coded) - prob_gf_coded = 1; - + // Update the probabilities used to encode reference frame data + update_ref_probs( cpi ); #ifdef ENTROPY_STATS active_section = 1; @@ -880,24 +598,66 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) if (pc->mb_no_coeff_skip) { - prob_skip_false = cpi->skip_false_count * 256 / (cpi->skip_false_count + cpi->skip_true_count); + // Divide by 0 check. 0 case possible with segment features + if ( (cpi->skip_false_count + cpi->skip_true_count) ) + { + prob_skip_false = cpi->skip_false_count * 256 / + (cpi->skip_false_count + cpi->skip_true_count); - if (prob_skip_false <= 1) - prob_skip_false = 1; + if (prob_skip_false <= 1) + prob_skip_false = 1; - if (prob_skip_false > 255) + if (prob_skip_false > 255) + prob_skip_false = 255; + } + else prob_skip_false = 255; cpi->prob_skip_false = prob_skip_false; vp8_write_literal(w, prob_skip_false, 8); } - vp8_write_literal(w, cpi->prob_intra_coded, 8); - vp8_write_literal(w, prob_last_coded, 8); - vp8_write_literal(w, prob_gf_coded, 8); + vp8_write_literal(w, pc->prob_intra_coded, 8); + vp8_write_literal(w, pc->prob_last_coded, 8); + vp8_write_literal(w, pc->prob_gf_coded, 8); + + if (cpi->common.comp_pred_mode == HYBRID_PREDICTION) + { + vp8_write(w, 1, 128); + vp8_write(w, 1, 128); + for (i = 0; i < COMP_PRED_CONTEXTS; i++) + { + if (cpi->single_pred_count[i] + cpi->comp_pred_count[i]) + { + pc->prob_comppred[i] = cpi->single_pred_count[i] * 255 / + (cpi->single_pred_count[i] + cpi->comp_pred_count[i]); + if (pc->prob_comppred[i] < 1) + pc->prob_comppred[i] = 1; + } + else + { + pc->prob_comppred[i] = 128; + } + vp8_write_literal(w, pc->prob_comppred[i], 8); + } + } + else if (cpi->common.comp_pred_mode == SINGLE_PREDICTION_ONLY) + { + vp8_write(w, 0, 128); + } + else /* compound prediction only */ + { + vp8_write(w, 1, 128); + vp8_write(w, 0, 128); + } update_mbintra_mode_probs(cpi); +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + vp8_write_mvprobs_hp(cpi); + else +#endif vp8_write_mvprobs(cpi); while (++mb_row < pc->mb_rows) @@ -909,8 +669,7 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) const MB_MODE_INFO *const mi = & m->mbmi; const MV_REFERENCE_FRAME rf = mi->ref_frame; const MB_PREDICTION_MODE mode = mi->mode; - - MACROBLOCKD *xd = &cpi->mb.e_mbd; + const int segment_id = mi->segment_id; // Distance of Mb to the various image edges. // These specified to 8th pel as they are always compared to MV values that are in 1/8th pel units @@ -919,164 +678,284 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) xd->mb_to_top_edge = -((mb_row * 16)) << 3; xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; + // Make sure the MacroBlockD mode info pointer is set correctly + xd->mode_info_context = m; + + xd->prev_mode_info_context = prev_m; + #ifdef ENTROPY_STATS active_section = 9; #endif if (cpi->mb.e_mbd.update_mb_segmentation_map) - write_mb_features(w, mi, &cpi->mb.e_mbd); + { + // Is temporal coding of the segment map enabled + if (pc->temporal_update) + { + prediction_flag = + get_pred_flag( xd, PRED_SEG_ID ); + pred_prob = + get_pred_prob( pc, xd, PRED_SEG_ID); - if (pc->mb_no_coeff_skip) - vp8_encode_bool(w, m->mbmi.mb_skip_coeff, prob_skip_false); + // Code the segment id prediction flag for this mb + vp8_write( w, prediction_flag, pred_prob ); + + // If the mbs segment id was not predicted code explicitly + if (!prediction_flag) + write_mb_segid(w, mi, &cpi->mb.e_mbd); + } + else + { + // Normal undpredicted coding + write_mb_segid(w, mi, &cpi->mb.e_mbd); + } + } + + if ( pc->mb_no_coeff_skip && + ( !segfeature_active( xd, segment_id, SEG_LVL_EOB ) || + ( get_segdata( xd, segment_id, SEG_LVL_EOB ) != 0 ) ) ) + { + vp8_encode_bool(w, mi->mb_skip_coeff, prob_skip_false); + } + + // Encode the reference frame. + encode_ref_frame( w, pc, xd, + segment_id, rf ); if (rf == INTRA_FRAME) { - vp8_write(w, 0, cpi->prob_intra_coded); #ifdef ENTROPY_STATS active_section = 6; #endif - write_ymode(w, mode, pc->fc.ymode_prob); + + if ( !segfeature_active( xd, segment_id, SEG_LVL_MODE ) ) + write_ymode(w, mode, pc->fc.ymode_prob); if (mode == B_PRED) { int j = 0; - - do - write_bmode(w, m->bmi[j].as_mode, pc->fc.bmode_prob); - while (++j < 16); +#if CONFIG_COMP_INTRA_PRED + int uses_second = m->bmi[0].as_mode.second != (B_PREDICTION_MODE) (B_DC_PRED - 1); + vp8_write(w, uses_second, 128); +#endif + do { +#if CONFIG_COMP_INTRA_PRED + B_PREDICTION_MODE mode2 = m->bmi[j].as_mode.second; +#endif + write_bmode(w, m->bmi[j].as_mode.first, pc->fc.bmode_prob); +#if CONFIG_COMP_INTRA_PRED + if (uses_second) + { + write_bmode(w, mode2, pc->fc.bmode_prob); + } +#endif + } while (++j < 16); + } + if(mode == I8X8_PRED) + { + write_i8x8_mode(w, m->bmi[0].as_mode.first, pc->i8x8_mode_prob); + write_i8x8_mode(w, m->bmi[2].as_mode.first, pc->i8x8_mode_prob); + write_i8x8_mode(w, m->bmi[8].as_mode.first, pc->i8x8_mode_prob); + write_i8x8_mode(w, m->bmi[10].as_mode.first, pc->i8x8_mode_prob); } - - write_uv_mode(w, mi->uv_mode, pc->fc.uv_mode_prob); - } - else /* inter coded */ - { - int_mv best_mv; - vp8_prob mv_ref_p [VP8_MVREFS-1]; - - vp8_write(w, 1, cpi->prob_intra_coded); - - if (rf == LAST_FRAME) - vp8_write(w, 0, prob_last_coded); else { - vp8_write(w, 1, prob_last_coded); - vp8_write(w, (rf == GOLDEN_FRAME) ? 0 : 1, prob_gf_coded); +#if CONFIG_UVINTRA + write_uv_mode(w, mi->uv_mode, pc->fc.uv_mode_prob[mode]); +#ifdef MODE_STATS + if(mode!=B_PRED) + ++cpi->y_uv_mode_count[mode][mi->uv_mode]; +#endif + +#else + write_uv_mode(w, mi->uv_mode, pc->fc.uv_mode_prob); +#endif /*CONFIG_UVINTRA*/ + } + } + else + { + int_mv best_mv; + int ct[4]; + + vp8_prob mv_ref_p [VP8_MVREFS-1]; { int_mv n1, n2; - int ct[4]; - vp8_find_near_mvs(xd, m, &n1, &n2, &best_mv, ct, rf, cpi->common.ref_frame_sign_bias); - vp8_mv_ref_probs(mv_ref_p, ct); + vp8_find_near_mvs(xd, m, + prev_m, + &n1, &n2, &best_mv, ct, rf, cpi->common.ref_frame_sign_bias); + vp8_mv_ref_probs(&cpi->common, mv_ref_p, ct); + #ifdef ENTROPY_STATS accum_mv_refs(mode, ct); #endif - } #ifdef ENTROPY_STATS active_section = 3; #endif - write_mv_ref(w, mode, mv_ref_p); - - switch (mode) /* new, split require MVs */ + // Is the segment coding of mode enabled + if ( !segfeature_active( xd, segment_id, SEG_LVL_MODE ) ) { - case NEWMV: + write_mv_ref(w, mode, mv_ref_p); + vp8_accum_mv_refs(&cpi->common, mode, ct); + } + { + switch (mode) /* new, split require MVs */ + { + case NEWMV: #ifdef ENTROPY_STATS - active_section = 5; + active_section = 5; #endif - write_mv(w, &mi->mv.as_mv, &best_mv, mvc); - break; +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + write_mv_hp(w, &mi->mv.as_mv, &best_mv, mvc_hp); + else +#endif + write_mv(w, &mi->mv.as_mv, &best_mv, mvc); - case SPLITMV: - { - int j = 0; + if (cpi->common.comp_pred_mode == HYBRID_PREDICTION) + { + vp8_write(w, mi->second_ref_frame != INTRA_FRAME, + get_pred_prob( pc, xd, PRED_COMP ) ); + } + if (mi->second_ref_frame) + { + const int second_rf = mi->second_ref_frame; + int_mv n1, n2; + int ct[4]; + vp8_find_near_mvs(xd, m, + prev_m, + &n1, &n2, &best_mv, + ct, second_rf, + cpi->common.ref_frame_sign_bias); +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + write_mv_hp(w, &mi->second_mv.as_mv, &best_mv, mvc_hp); + else +#endif + write_mv(w, &mi->second_mv.as_mv, &best_mv, mvc); + } + break; + case SPLITMV: + { + int j = 0; #ifdef MODE_STATS - ++count_mb_seg [mi->partitioning]; + ++count_mb_seg [mi->partitioning]; #endif - write_split(w, mi->partitioning); + write_split(w, mi->partitioning); - do - { - B_PREDICTION_MODE blockmode; - int_mv blockmv; - const int *const L = vp8_mbsplits [mi->partitioning]; - int k = -1; /* first block in subset j */ - int mv_contz; - int_mv leftmv, abovemv; - - blockmode = cpi->mb.partition_info->bmi[j].mode; - blockmv = cpi->mb.partition_info->bmi[j].mv; -#if CONFIG_DEBUG - while (j != L[++k]) - if (k >= 16) - assert(0); -#else - while (j != L[++k]); -#endif - leftmv.as_int = left_block_mv(m, k); - abovemv.as_int = above_block_mv(m, k, mis); - mv_contz = vp8_mv_cont(&leftmv, &abovemv); - - write_sub_mv_ref(w, blockmode, vp8_sub_mv_ref_prob2 [mv_contz]); - - if (blockmode == NEW4X4) + do { -#ifdef ENTROPY_STATS - active_section = 11; + B_PREDICTION_MODE blockmode; + int_mv blockmv; + const int *const L = vp8_mbsplits [mi->partitioning]; + int k = -1; /* first block in subset j */ + int mv_contz; + int_mv leftmv, abovemv; + + blockmode = cpi->mb.partition_info->bmi[j].mode; + blockmv = cpi->mb.partition_info->bmi[j].mv; +#if CONFIG_DEBUG + while (j != L[++k]) + if (k >= 16) + assert(0); +#else + while (j != L[++k]); #endif - write_mv(w, &blockmv.as_mv, &best_mv, (const MV_CONTEXT *) mvc); + leftmv.as_int = left_block_mv(m, k); + abovemv.as_int = above_block_mv(m, k, mis); + mv_contz = vp8_mv_cont(&leftmv, &abovemv); + + write_sub_mv_ref(w, blockmode, vp8_sub_mv_ref_prob2 [mv_contz]); + + if (blockmode == NEW4X4) + { +#ifdef ENTROPY_STATS + active_section = 11; +#endif +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + write_mv_hp(w, &blockmv.as_mv, &best_mv, (const MV_CONTEXT_HP *) mvc_hp); + else +#endif + write_mv(w, &blockmv.as_mv, &best_mv, (const MV_CONTEXT *) mvc); + } } + while (++j < cpi->mb.partition_info->count); } - while (++j < cpi->mb.partition_info->count); - } - break; - default: break; + default: + if (cpi->common.comp_pred_mode == HYBRID_PREDICTION) + { + vp8_write(w, mi->second_ref_frame != INTRA_FRAME, + get_pred_prob( pc, xd, PRED_COMP ) ); + } + break; + } } } ++m; + ++prev_m; + assert((prev_m-cpi->common.prev_mip)==(m-cpi->common.mip)); + assert((prev_m-cpi->common.prev_mi)==(m-cpi->common.mi)); cpi->mb.partition_info++; } ++m; /* skip L prediction border */ + ++prev_m; cpi->mb.partition_info++; } } - static void write_kfmodes(VP8_COMP *cpi) { vp8_writer *const bc = & cpi->bc; const VP8_COMMON *const c = & cpi->common; /* const */ MODE_INFO *m = c->mi; - int mb_row = -1; int prob_skip_false = 0; + MACROBLOCKD *xd = &cpi->mb.e_mbd; + if (c->mb_no_coeff_skip) { - prob_skip_false = cpi->skip_false_count * 256 / (cpi->skip_false_count + cpi->skip_true_count); + // Divide by 0 check. 0 case possible with segment features + if ( (cpi->skip_false_count + cpi->skip_true_count) ) + { + prob_skip_false = cpi->skip_false_count * 256 / + (cpi->skip_false_count + cpi->skip_true_count); - if (prob_skip_false <= 1) - prob_skip_false = 1; + if (prob_skip_false <= 1) + prob_skip_false = 1; - if (prob_skip_false >= 255) + if (prob_skip_false > 255) + prob_skip_false = 255; + } + else prob_skip_false = 255; cpi->prob_skip_false = prob_skip_false; vp8_write_literal(bc, prob_skip_false, 8); } +#if CONFIG_QIMODE + if(!c->kf_ymode_probs_update) + { + vp8_write_literal(bc, c->kf_ymode_probs_index, 3); + } +#endif + while (++mb_row < c->mb_rows) { int mb_col = -1; @@ -1084,42 +963,76 @@ static void write_kfmodes(VP8_COMP *cpi) while (++mb_col < c->mb_cols) { const int ym = m->mbmi.mode; + int segment_id = m->mbmi.segment_id; if (cpi->mb.e_mbd.update_mb_segmentation_map) - write_mb_features(bc, &m->mbmi, &cpi->mb.e_mbd); + { + write_mb_segid(bc, &m->mbmi, &cpi->mb.e_mbd); + } - if (c->mb_no_coeff_skip) + if ( c->mb_no_coeff_skip && + ( !segfeature_active( xd, segment_id, SEG_LVL_EOB ) || + (get_segdata( xd, segment_id, SEG_LVL_EOB ) != 0) ) ) + { vp8_encode_bool(bc, m->mbmi.mb_skip_coeff, prob_skip_false); - + } +#if CONFIG_QIMODE + kfwrite_ymode(bc, ym, c->kf_ymode_prob[c->kf_ymode_probs_index]); +#else kfwrite_ymode(bc, ym, c->kf_ymode_prob); - +#endif if (ym == B_PRED) { const int mis = c->mode_info_stride; int i = 0; - +#if CONFIG_COMP_INTRA_PRED + int uses_second = m->bmi[0].as_mode.second != (B_PREDICTION_MODE) (B_DC_PRED - 1); + vp8_write(bc, uses_second, 128); +#endif do { const B_PREDICTION_MODE A = above_block_mode(m, i, mis); const B_PREDICTION_MODE L = left_block_mode(m, i); - const int bm = m->bmi[i].as_mode; + const int bm = m->bmi[i].as_mode.first; +#if CONFIG_COMP_INTRA_PRED + const int bm2 = m->bmi[i].as_mode.second; +#endif #ifdef ENTROPY_STATS ++intra_mode_stats [A] [L] [bm]; #endif write_bmode(bc, bm, c->kf_bmode_prob [A] [L]); +#if CONFIG_COMP_INTRA_PRED + if (uses_second) + { + write_bmode(bc, bm2, c->kf_bmode_prob [A] [L]); + } +#endif } while (++i < 16); } - - write_uv_mode(bc, (m++)->mbmi.uv_mode, c->kf_uv_mode_prob); + if(ym == I8X8_PRED) + { + write_i8x8_mode(bc, m->bmi[0].as_mode.first, c->i8x8_mode_prob); + write_i8x8_mode(bc, m->bmi[2].as_mode.first, c->i8x8_mode_prob); + write_i8x8_mode(bc, m->bmi[8].as_mode.first, c->i8x8_mode_prob); + write_i8x8_mode(bc, m->bmi[10].as_mode.first, c->i8x8_mode_prob); + m++; + } + else +#if CONFIG_UVINTRA + write_uv_mode(bc, (m++)->mbmi.uv_mode, c->kf_uv_mode_prob[ym]); +#else + write_uv_mode(bc, (m++)->mbmi.uv_mode, c->kf_uv_mode_prob); +#endif } - + //printf("\n"); m++; // skip L prediction border } } + /* This function is used for debugging probability trees. */ static void print_prob_tree(vp8_prob coef_probs[BLOCK_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS][ENTROPY_NODES]) @@ -1182,84 +1095,6 @@ static int prob_update_savings(const unsigned int *ct, return old_b - new_b - update_b; } -static int independent_coef_context_savings(VP8_COMP *cpi) -{ - int savings = 0; - int i = 0; - do - { - int j = 0; - do - { - int k = 0; - unsigned int prev_coef_count_sum[MAX_ENTROPY_TOKENS] = {0}; - int prev_coef_savings[MAX_ENTROPY_TOKENS] = {0}; - /* Calculate new probabilities given the constraint that - * they must be equal over the prev coef contexts - */ - if (cpi->common.frame_type == KEY_FRAME) - { - /* Reset to default probabilities at key frames */ - sum_probs_over_prev_coef_context(default_coef_counts[i][j], - prev_coef_count_sum); - } - else - { - sum_probs_over_prev_coef_context(cpi->coef_counts[i][j], - prev_coef_count_sum); - } - do - { - /* at every context */ - - /* calc probs and branch cts for this frame only */ - //vp8_prob new_p [ENTROPY_NODES]; - //unsigned int branch_ct [ENTROPY_NODES] [2]; - - int t = 0; /* token/prob index */ - - vp8_tree_probs_from_distribution( - MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, - cpi->frame_coef_probs[i][j][k], - cpi->frame_branch_ct [i][j][k], - prev_coef_count_sum, - 256, 1); - - do - { - const unsigned int *ct = cpi->frame_branch_ct [i][j][k][t]; - const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t]; - const vp8_prob oldp = cpi->common.fc.coef_probs [i][j][k][t]; - const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; - const int s = prob_update_savings(ct, oldp, newp, upd); - - if (cpi->common.frame_type != KEY_FRAME || - (cpi->common.frame_type == KEY_FRAME && newp != oldp)) - prev_coef_savings[t] += s; - } - while (++t < ENTROPY_NODES); - } - while (++k < PREV_COEF_CONTEXTS); - k = 0; - do - { - /* We only update probabilities if we can save bits, except - * for key frames where we have to update all probabilities - * to get the equal probabilities across the prev coef - * contexts. - */ - if (prev_coef_savings[k] > 0 || - cpi->common.frame_type == KEY_FRAME) - savings += prev_coef_savings[k]; - } - while (++k < ENTROPY_NODES); - } - while (++j < COEF_BANDS); - } - while (++i < BLOCK_TYPES); - return savings; -} - static int default_coef_context_savings(VP8_COMP *cpi) { int savings = 0; @@ -1315,24 +1150,32 @@ static int default_coef_context_savings(VP8_COMP *cpi) int vp8_estimate_entropy_savings(VP8_COMP *cpi) { int savings = 0; - + int i=0; + VP8_COMMON *const cm = & cpi->common; const int *const rfct = cpi->count_mb_ref_frame_usage; const int rf_intra = rfct[INTRA_FRAME]; const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; - int new_intra, new_last, gf_last, oldtotal, newtotal; + int new_intra, new_last, new_gf_alt, oldtotal, newtotal; int ref_frame_cost[MAX_REF_FRAMES]; vp8_clear_system_state(); //__asm emms; + // Estimate reference frame cost savings. + // For now this is just based on projected overall frequency of + // each reference frame coded using an unpredicted coding tree. if (cpi->common.frame_type != KEY_FRAME) { - if (!(new_intra = rf_intra * 255 / (rf_intra + rf_inter))) - new_intra = 1; + new_intra = (rf_intra + rf_inter) + ? rf_intra * 255 / (rf_intra + rf_inter) : 1; + new_intra += !new_intra; new_last = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + new_last += !new_last; - gf_last = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) - ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + new_gf_alt = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / + (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + new_gf_alt += !new_gf_alt; // new costs ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(new_intra); @@ -1340,10 +1183,10 @@ int vp8_estimate_entropy_savings(VP8_COMP *cpi) + vp8_cost_zero(new_last); ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(new_intra) + vp8_cost_one(new_last) - + vp8_cost_zero(gf_last); + + vp8_cost_zero(new_gf_alt); ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(new_intra) + vp8_cost_one(new_last) - + vp8_cost_one(gf_last); + + vp8_cost_one(new_gf_alt); newtotal = rfct[INTRA_FRAME] * ref_frame_cost[INTRA_FRAME] + @@ -1351,17 +1194,16 @@ int vp8_estimate_entropy_savings(VP8_COMP *cpi) rfct[GOLDEN_FRAME] * ref_frame_cost[GOLDEN_FRAME] + rfct[ALTREF_FRAME] * ref_frame_cost[ALTREF_FRAME]; - // old costs - ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(cpi->prob_intra_coded); - ref_frame_cost[LAST_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_zero(cpi->prob_last_coded); - ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_one(cpi->prob_last_coded) - + vp8_cost_zero(cpi->prob_gf_coded); - ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_one(cpi->prob_last_coded) - + vp8_cost_one(cpi->prob_gf_coded); + ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(cm->prob_intra_coded); + ref_frame_cost[LAST_FRAME] = vp8_cost_one(cm->prob_intra_coded) + + vp8_cost_zero(cm->prob_last_coded); + ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cm->prob_intra_coded) + + vp8_cost_one(cm->prob_last_coded) + + vp8_cost_zero(cm->prob_gf_coded); + ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cm->prob_intra_coded) + + vp8_cost_one(cm->prob_last_coded) + + vp8_cost_one(cm->prob_gf_coded); oldtotal = rfct[INTRA_FRAME] * ref_frame_cost[INTRA_FRAME] + @@ -1370,14 +1212,77 @@ int vp8_estimate_entropy_savings(VP8_COMP *cpi) rfct[ALTREF_FRAME] * ref_frame_cost[ALTREF_FRAME]; savings += (oldtotal - newtotal) / 256; + + // Update the reference frame probability numbers to reflect + // the observed counts in this frame. Doing this here insures + // that if there are multiple recode iterations the baseline + // probabilities used are updated in each iteration. + cm->prob_intra_coded = new_intra; + cm->prob_last_coded = new_last; + cm->prob_gf_coded = new_gf_alt; } + savings += default_coef_context_savings(cpi); - if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS) - savings += independent_coef_context_savings(cpi); - else - savings += default_coef_context_savings(cpi); + /* do not do this if not evena allowed */ + if(cpi->common.txfm_mode == ALLOW_8X8) + { + int savings8x8 = 0; + do + { + int j = 0; + do + { + int k = 0; + do + { + /* at every context */ + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [ENTROPY_NODES]; + //unsigned int branch_ct [ENTROPY_NODES] [2]; + int t = 0; /* token/prob index */ + vp8_tree_probs_from_distribution( + MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, + cpi->frame_coef_probs_8x8 [i][j][k], + cpi->frame_branch_ct_8x8 [i][j][k], + cpi->coef_counts_8x8 [i][j][k], + 256, 1 + ); + + do + { + const unsigned int *ct = cpi->frame_branch_ct_8x8 [i][j][k][t]; + const vp8_prob newp = cpi->frame_coef_probs_8x8 [i][j][k][t]; + + const vp8_prob old = cpi->common.fc.coef_probs_8x8 [i][j][k][t]; + const vp8_prob upd = vp8_coef_update_probs_8x8 [i][j][k][t]; + + const int old_b = vp8_cost_branch(ct, old); + const int new_b = vp8_cost_branch(ct, newp); + + const int update_b = 8 + + ((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8); + + const int s = old_b - new_b - update_b; + + if (s > 0) + savings8x8 += s; + + + } + while (++t < MAX_ENTROPY_TOKENS - 1); + + + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + + savings += savings8x8 >> 8; + } return savings; } @@ -1386,125 +1291,265 @@ static void update_coef_probs(VP8_COMP *cpi) { int i = 0; vp8_writer *const w = & cpi->bc; - int savings = 0; + int update = 0; vp8_clear_system_state(); //__asm emms; - + /* dry run to see if there is any udpate at all needed */ do { int j = 0; - do { int k = 0; int prev_coef_savings[ENTROPY_NODES] = {0}; - if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS) - { - for (k = 0; k < PREV_COEF_CONTEXTS; ++k) - { - int t; /* token/prob index */ - for (t = 0; t < ENTROPY_NODES; ++t) - { - const unsigned int *ct = cpi->frame_branch_ct [i][j] - [k][t]; - const vp8_prob newp = cpi->frame_coef_probs[i][j][k][t]; - const vp8_prob oldp = cpi->common.fc.coef_probs[i][j] - [k][t]; - const vp8_prob upd = vp8_coef_update_probs[i][j][k][t]; - - prev_coef_savings[t] += - prob_update_savings(ct, oldp, newp, upd); - } - } - k = 0; - } do { //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here. /* at every context */ - /* calc probs and branch cts for this frame only */ //vp8_prob new_p [ENTROPY_NODES]; //unsigned int branch_ct [ENTROPY_NODES] [2]; - int t = 0; /* token/prob index */ - //vp8_tree_probs_from_distribution( // MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, // new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k], // 256, 1 // ); - do { const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t]; - vp8_prob *Pold = cpi->common.fc.coef_probs [i][j][k] + t; const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; - int s = prev_coef_savings[t]; int u = 0; - if (!(cpi->oxcf.error_resilient_mode & - VPX_ERROR_RESILIENT_PARTITIONS)) - { - s = prob_update_savings( - cpi->frame_branch_ct [i][j][k][t], - *Pold, newp, upd); - } + s = prob_update_savings( + cpi->frame_branch_ct [i][j][k][t], + *Pold, newp, upd); if (s > 0) u = 1; - /* Force updates on key frames if the new is different, - * so that we can be sure we end up with equal probabilities - * over the prev coef contexts. - */ - if ((cpi->oxcf.error_resilient_mode & - VPX_ERROR_RESILIENT_PARTITIONS) && - cpi->common.frame_type == KEY_FRAME && newp != *Pold) - u = 1; - - vp8_write(w, u, upd); - - -#ifdef ENTROPY_STATS - ++ tree_update_hist [i][j][k][t] [u]; -#endif - - if (u) - { - /* send/use new probability */ - - *Pold = newp; - vp8_write_literal(w, newp, 8); - - savings += s; - - } - + update += u; } while (++t < ENTROPY_NODES); - /* Accum token counts for generation of default statistics */ -#ifdef ENTROPY_STATS - t = 0; - - do - { - context_counters [i][j][k][t] += cpi->coef_counts [i][j][k][t]; - } - while (++t < MAX_ENTROPY_TOKENS); - -#endif - } while (++k < PREV_COEF_CONTEXTS); } while (++j < COEF_BANDS); } while (++i < BLOCK_TYPES); + /* Is coef updated at all */ + if(update==0) + { + vp8_write_bit(w, 0); + } + else + { + vp8_write_bit(w, 1); + i=0; + do + { + int j = 0; + do + { + int k = 0; + int prev_coef_savings[ENTROPY_NODES] = {0}; + do + { + //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here. + /* at every context */ + + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [ENTROPY_NODES]; + //unsigned int branch_ct [ENTROPY_NODES] [2]; + int t = 0; /* token/prob index */ + //vp8_tree_probs_from_distribution( + // MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, + // new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k], + // 256, 1 + // ); + do + { + const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t]; + vp8_prob *Pold = cpi->common.fc.coef_probs [i][j][k] + t; + const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; + int s = prev_coef_savings[t]; + int u = 0; + + s = prob_update_savings( + cpi->frame_branch_ct [i][j][k][t], + *Pold, newp, upd); + + if (s > 0) + u = 1; + + vp8_write(w, u, upd); +#ifdef ENTROPY_STATS + ++ tree_update_hist [i][j][k][t] [u]; +#endif + if (u) + { + /* send/use new probability */ + *Pold = newp; + vp8_write_literal(w, newp, 8); + } + } + while (++t < ENTROPY_NODES); + /* Accum token counts for generation of default statistics */ +#ifdef ENTROPY_STATS + t = 0; + do + { + context_counters [i][j][k][t] += cpi->coef_counts [i][j][k][t]; + } + while (++t < MAX_ENTROPY_TOKENS); +#endif + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + } + + + /* do not do this if not evena allowed */ + if(cpi->common.txfm_mode == ALLOW_8X8) + { + /* dry run to see if update is necessary */ + update = 0; + i = 0; + do + { + int j = 0; + do + { + int k = 0; + do + { + //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here. + /* at every context */ + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [ENTROPY_NODES]; + //unsigned int branch_ct [ENTROPY_NODES] [2]; + int t = 0; /* token/prob index */ + //vp8_tree_probs_from_distribution( + // MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, + // new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k], + // 256, 1 + // ); + do + { + const unsigned int *ct = cpi->frame_branch_ct_8x8 [i][j][k][t]; + const vp8_prob newp = cpi->frame_coef_probs_8x8 [i][j][k][t]; + vp8_prob *Pold = cpi->common.fc.coef_probs_8x8 [i][j][k] + t; + const vp8_prob old = *Pold; + const vp8_prob upd = vp8_coef_update_probs_8x8 [i][j][k][t]; + const int old_b = vp8_cost_branch(ct, old); + const int new_b = vp8_cost_branch(ct, newp); + const int update_b = 8 + + ((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8); + const int s = old_b - new_b - update_b; + const int u = s > 0 ? 1 : 0; + +#ifdef ENTROPY_STATS + ++ tree_update_hist_8x8 [i][j][k][t] [u]; +#endif + update += u; + } + while (++t < MAX_ENTROPY_TOKENS - 1); + + /* Accum token counts for generation of default statistics */ +#ifdef ENTROPY_STATS + t = 0; + + do + { + context_counters_8x8 [i][j][k][t] += cpi->coef_counts_8x8 [i][j][k][t]; + } + while (++t < MAX_ENTROPY_TOKENS); + +#endif + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + + if(update == 0) + { + vp8_write_bit(w, 0); + + } + else + { + vp8_write_bit(w, 1); + i = 0; + do + { + int j = 0; + do + { + int k = 0; + do + { + //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here. + /* at every context */ + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [ENTROPY_NODES]; + //unsigned int branch_ct [ENTROPY_NODES] [2]; + int t = 0; /* token/prob index */ + //vp8_tree_probs_from_distribution( + // MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, + // new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k], + // 256, 1 + // ); + do + { + const unsigned int *ct = cpi->frame_branch_ct_8x8 [i][j][k][t]; + const vp8_prob newp = cpi->frame_coef_probs_8x8 [i][j][k][t]; + vp8_prob *Pold = cpi->common.fc.coef_probs_8x8 [i][j][k] + t; + const vp8_prob old = *Pold; + const vp8_prob upd = vp8_coef_update_probs_8x8 [i][j][k][t]; + const int old_b = vp8_cost_branch(ct, old); + const int new_b = vp8_cost_branch(ct, newp); + const int update_b = 8 + + ((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8); + const int s = old_b - new_b - update_b; + const int u = s > 0 ? 1 : 0; + vp8_write(w, u, upd); +#ifdef ENTROPY_STATS + ++ tree_update_hist_8x8 [i][j][k][t] [u]; +#endif + if (u) + { + /* send/use new probability */ + *Pold = newp; + vp8_write_literal(w, newp, 8); + } + } + while (++t < MAX_ENTROPY_TOKENS - 1); + /* Accum token counts for generation of default statistics */ +#ifdef ENTROPY_STATS + t = 0; + do + { + context_counters_8x8 [i][j][k][t] += cpi->coef_counts_8x8 [i][j][k][t]; + } + while (++t < MAX_ENTROPY_TOKENS); +#endif + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + } + } } #ifdef PACKET_TESTING FILE *vpxlogc = 0; @@ -1525,7 +1570,60 @@ static void put_delta_q(vp8_writer *bc, int delta_q) else vp8_write_bit(bc, 0); } +#if CONFIG_QIMODE +extern const unsigned int kf_y_mode_cts[8][VP8_YMODES]; +static void decide_kf_ymode_entropy(VP8_COMP *cpi) +{ + int mode_cost[MB_MODE_COUNT]; + int cost; + int bestcost = INT_MAX; + int bestindex = 0; + int i, j; + + for(i=0; i<8; i++) + { + vp8_cost_tokens(mode_cost, cpi->common.kf_ymode_prob[i], vp8_kf_ymode_tree); + cost = 0; + for(j=0;jymode_count[j]; + } + if(cost < bestcost) + { + bestindex = i; + bestcost = cost; + } + } + cpi->common.kf_ymode_probs_index = bestindex; + +} +#endif +static segment_reference_frames(VP8_COMP *cpi) +{ + VP8_COMMON *oci = &cpi->common; + MODE_INFO *mi = oci->mi; + int ref[MAX_MB_SEGMENTS]={0}; + int i,j; + int mb_index=0; + MACROBLOCKD *const xd = & cpi->mb.e_mbd; + + for (i = 0; i < oci->mb_rows; i++) + { + for (j = 0; j < oci->mb_cols; j++, mb_index++) + { + ref[mi[mb_index].mbmi.segment_id]|=(1<show_frame; oh.type = (int)pc->frame_type; oh.version = pc->version; oh.first_partition_length_in_bytes = 0; - mb_feature_data_bits = vp8_mb_feature_data_bits; cx_data += 3; #if defined(SECTIONBITS_OUTPUT) @@ -1586,57 +1682,133 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) else vp8_start_encode(bc, cx_data); - // Signal whether or not Segmentation is enabled vp8_write_bit(bc, (xd->segmentation_enabled) ? 1 : 0); // Indicate which features are enabled - if (xd->segmentation_enabled) + if ( xd->segmentation_enabled ) { - // Signal whether or not the segmentation map is being updated. + // Indicate whether or not the segmentation map is being updated. vp8_write_bit(bc, (xd->update_mb_segmentation_map) ? 1 : 0); + + // If it is, then indicate the method that will be used. + if ( xd->update_mb_segmentation_map ) + vp8_write_bit(bc, (pc->temporal_update) ? 1:0); + vp8_write_bit(bc, (xd->update_mb_segmentation_data) ? 1 : 0); + //segment_reference_frames(cpi); + if (xd->update_mb_segmentation_data) { signed char Data; - vp8_write_bit(bc, (xd->mb_segement_abs_delta) ? 1 : 0); + vp8_write_bit(bc, (xd->mb_segment_abs_delta) ? 1 : 0); - // For each segmentation feature (Quant and loop filter level) - for (i = 0; i < MB_LVL_MAX; i++) + // For each segments id... + for (i = 0; i < MAX_MB_SEGMENTS; i++) { - // For each of the segments - for (j = 0; j < MAX_MB_SEGMENTS; j++) + // For each segmentation codable feature... + for (j = 0; j < SEG_LVL_MAX; j++) { - Data = xd->segment_feature_data[i][j]; + Data = get_segdata( xd, i, j ); - // Frame level data - if (Data) + +#if CONFIG_FEATUREUPDATES + + // check if there's an update + if(segfeature_changed( xd,i,j) ) { vp8_write_bit(bc, 1); - if (Data < 0) + if ( segfeature_active( xd, i, j ) ) { - Data = - Data; - vp8_write_literal(bc, Data, mb_feature_data_bits[i]); - vp8_write_bit(bc, 1); + // this bit is to say we are still + // active/ if we were inactive + // this is unnecessary + if ( old_segfeature_active( xd, i, j )) + { + vp8_write_bit(bc, 1); + } + // Is the segment data signed.. + if ( is_segfeature_signed(j) ) + { + // Encode the relevant feature data + if (Data < 0) + { + Data = - Data; + vp8_write_literal(bc, Data, + seg_feature_data_bits(j)); + vp8_write_bit(bc, 1); + } + else + { + vp8_write_literal(bc, Data, + seg_feature_data_bits(j)); + vp8_write_bit(bc, 0); + } + } + // Unsigned data element so no sign bit needed + else + vp8_write_literal(bc, Data, + seg_feature_data_bits(j)); } - else + // feature is inactive now + else if ( old_segfeature_active( xd, i, j )) { - vp8_write_literal(bc, Data, mb_feature_data_bits[i]); - vp8_write_bit(bc, 0); + vp8_write_bit(bc, 0); } } + else + { + vp8_write_bit(bc,0); + } +#else + + // If the feature is enabled... + if ( segfeature_active( xd, i, j ) ) + { + vp8_write_bit(bc, 1); + + // Is the segment data signed.. + if ( is_segfeature_signed(j) ) + { + // Encode the relevant feature data + if (Data < 0) + { + Data = - Data; + vp8_write_literal(bc, Data, + seg_feature_data_bits(j)); + vp8_write_bit(bc, 1); + } + else + { + vp8_write_literal(bc, Data, + seg_feature_data_bits(j)); + vp8_write_bit(bc, 0); + } + } + // Unsigned data element so no sign bit needed + else + vp8_write_literal(bc, Data, + seg_feature_data_bits(j)); + } else vp8_write_bit(bc, 0); +#endif } } } +#if CONFIG_FEATUREUPDATES + // save the segment info for updates next frame + save_segment_info ( xd ); +#endif + if (xd->update_mb_segmentation_map) { - // Write the probs used to decode the segment id for each macro block. + // Send the tree probabilities used to decode unpredicted + // macro-block segments for (i = 0; i < MB_FEATURE_TREE_PROBS; i++) { int Data = xd->mb_segment_tree_probs[i]; @@ -1649,10 +1821,46 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) else vp8_write_bit(bc, 0); } + + // If predictive coding of segment map is enabled send the + // prediction probabilities. + if ( pc->temporal_update ) + { + for (i = 0; i < PREDICTION_PROBS; i++) + { + int Data = pc->segment_pred_probs[i]; + + if (Data != 255) + { + vp8_write_bit(bc, 1); + vp8_write_literal(bc, Data, 8); + } + else + vp8_write_bit(bc, 0); + } + } } } - // Code to determine whether or not to update the scan order. + // Encode the common prediction model status flag probability updates for + // the reference frame + if ( pc->frame_type != KEY_FRAME ) + { + for (i = 0; i < PREDICTION_PROBS; i++) + { + if ( cpi->ref_pred_probs_update[i] ) + { + vp8_write_bit(bc, 1); + vp8_write_literal(bc, pc->ref_pred_probs[i], 8); + } + else + vp8_write_bit(bc, 0); + } + } + + vp8_write_bit(bc, pc->txfm_mode); + + // Encode the loop filter level and type vp8_write_bit(bc, pc->filter_type); vp8_write_literal(bc, pc->filter_level, 6); vp8_write_literal(bc, pc->sharpness_level, 3); @@ -1663,8 +1871,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) if (xd->mode_ref_lf_delta_enabled) { // Do the deltas need to be updated - int send_update = xd->mode_ref_lf_delta_update - || cpi->oxcf.error_resilient_mode; + int send_update = xd->mode_ref_lf_delta_update; vp8_write_bit(bc, send_update); if (send_update) @@ -1677,8 +1884,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) Data = xd->ref_lf_deltas[i]; // Frame level data - if (xd->ref_lf_deltas[i] != xd->last_ref_lf_deltas[i] - || cpi->oxcf.error_resilient_mode) + if (xd->ref_lf_deltas[i] != xd->last_ref_lf_deltas[i]) { xd->last_ref_lf_deltas[i] = xd->ref_lf_deltas[i]; vp8_write_bit(bc, 1); @@ -1704,8 +1910,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) { Data = xd->mode_lf_deltas[i]; - if (xd->mode_lf_deltas[i] != xd->last_mode_lf_deltas[i] - || cpi->oxcf.error_resilient_mode) + if (xd->mode_lf_deltas[i] != xd->last_mode_lf_deltas[i]) { xd->last_mode_lf_deltas[i] = xd->mode_lf_deltas[i]; vp8_write_bit(bc, 1); @@ -1729,10 +1934,11 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) } //signal here is multi token partition is enabled - vp8_write_literal(bc, pc->multi_token_partition, 2); + //vp8_write_literal(bc, pc->multi_token_partition, 2); + vp8_write_literal(bc, 0, 2); - // Frame Qbaseline quantizer index - vp8_write_literal(bc, pc->base_qindex, 7); + // Frame Q baseline quantizer index + vp8_write_literal(bc, pc->base_qindex, QINDEX_BITS); // Transmit Dc, Second order and Uv quantizer delta information put_delta_q(bc, pc->y1dc_delta_q); @@ -1758,14 +1964,11 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) // Indicate reference frame sign bias for Golden and ARF frames (always 0 for last frame buffer) vp8_write_bit(bc, pc->ref_frame_sign_bias[GOLDEN_FRAME]); vp8_write_bit(bc, pc->ref_frame_sign_bias[ALTREF_FRAME]); - } - if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS) - { - if (pc->frame_type == KEY_FRAME) - pc->refresh_entropy_probs = 1; - else - pc->refresh_entropy_probs = 0; +#if CONFIG_HIGH_PRECISION_MV + // Signal whether to allow high MV precision + vp8_write_bit(bc, (xd->allow_high_precision_mv) ? 1 : 0); +#endif } vp8_write_bit(bc, pc->refresh_entropy_probs); @@ -1784,12 +1987,6 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) vp8_clear_system_state(); //__asm emms; - //************************************************ - // save a copy for later refresh - { - vpx_memcpy(&cpi->common.lfc, &cpi->common.fc, sizeof(cpi->common.fc)); - } - update_coef_probs(cpi); #ifdef ENTROPY_STATS @@ -1801,6 +1998,9 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) if (pc->frame_type == KEY_FRAME) { +#if CONFIG_QIMODE + decide_kf_ymode_entropy(cpi); +#endif write_kfmodes(cpi); #ifdef ENTROPY_STATS @@ -1811,6 +2011,8 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) { pack_inter_mode_mvs(cpi); + vp8_update_mode_context(&cpi->common); + #ifdef ENTROPY_STATS active_section = 1; #endif @@ -1833,34 +2035,14 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) } *size = VP8_HEADER_SIZE + extra_bytes_packed + cpi->bc.pos; - cpi->partition_sz[0] = *size; - if (pc->multi_token_partition != ONE_PARTITION) - { - int num_part; - int asize; - num_part = 1 << pc->multi_token_partition; + vp8_start_encode(&cpi->bc2, cx_data + bc->pos); - pack_tokens_into_partitions(cpi, cx_data + bc->pos, num_part, &asize); + pack_tokens(&cpi->bc2, cpi->tok, cpi->tok_count); - *size += asize; - } - else - { - vp8_start_encode(&cpi->bc2, cx_data + bc->pos); + vp8_stop_encode(&cpi->bc2); -#if CONFIG_MULTITHREAD - if (cpi->b_multi_threaded) - pack_mb_row_tokens(cpi, &cpi->bc2); - else -#endif - pack_tokens(&cpi->bc2, cpi->tok, cpi->tok_count); - - vp8_stop_encode(&cpi->bc2); - - *size += cpi->bc2.pos; - cpi->partition_sz[1] = cpi->bc2.pos; - } + *size += cpi->bc2.pos; } #ifdef ENTROPY_STATS @@ -1909,6 +2091,44 @@ void print_tree_update_probs() } fprintf(f, "};\n"); + + fprintf(f, "const vp8_prob tree_update_probs_8x8[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES] = {\n"); + + for (i = 0; i < BLOCK_TYPES; i++) + { + fprintf(f, " { \n"); + + for (j = 0; j < COEF_BANDS; j++) + { + fprintf(f, " {\n"); + + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + { + fprintf(f, " {"); + + for (l = 0; l < MAX_ENTROPY_TOKENS - 1; l++) + { + Sum = tree_update_hist_8x8[i][j][k][l][0] + tree_update_hist_8x8[i][j][k][l][1]; + + if (Sum > 0) + { + if (((tree_update_hist_8x8[i][j][k][l][0] * 255) / Sum) > 0) + fprintf(f, "%3ld, ", (tree_update_hist_8x8[i][j][k][l][0] * 255) / Sum); + else + fprintf(f, "%3ld, ", 1); + } + else + fprintf(f, "%3ld, ", 128); + } + + fprintf(f, "},\n"); + } + + fprintf(f, " },\n"); + } + + fprintf(f, " },\n"); + } fclose(f); } #endif diff --git a/vp8/encoder/bitstream.h b/vp8/encoder/bitstream.h index f5d148ea4..39fa642a5 100644 --- a/vp8/encoder/bitstream.h +++ b/vp8/encoder/bitstream.h @@ -17,23 +17,9 @@ void vp8cx_pack_tokens_armv5(vp8_writer *w, const TOKENEXTRA *p, int xcount, vp8_token *, vp8_extra_bit_struct *, const vp8_tree_index *); -void vp8cx_pack_tokens_into_partitions_armv5(VP8_COMP *, unsigned char *, int , int *, - vp8_token *, - vp8_extra_bit_struct *, - const vp8_tree_index *); -void vp8cx_pack_mb_row_tokens_armv5(VP8_COMP *cpi, vp8_writer *w, - vp8_token *, - vp8_extra_bit_struct *, - const vp8_tree_index *); # define pack_tokens(a,b,c) \ vp8cx_pack_tokens_armv5(a,b,c,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) -# define pack_tokens_into_partitions(a,b,c,d) \ - vp8cx_pack_tokens_into_partitions_armv5(a,b,c,d,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) -# define pack_mb_row_tokens(a,b) \ - vp8cx_pack_mb_row_tokens_armv5(a,b,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) #else # define pack_tokens(a,b,c) pack_tokens_c(a,b,c) -# define pack_tokens_into_partitions(a,b,c,d) pack_tokens_into_partitions_c(a,b,c,d) -# define pack_mb_row_tokens(a,b) pack_mb_row_tokens_c(a,b) #endif #endif diff --git a/vp8/encoder/block.h b/vp8/encoder/block.h index 0d14b545c..25d2398ce 100644 --- a/vp8/encoder/block.h +++ b/vp8/encoder/block.h @@ -46,8 +46,8 @@ typedef struct int src; int src_stride; -// MV enc_mv; - int force_empty; + int eob_max_offset; + int eob_max_offset_8x8; } BLOCK; @@ -95,9 +95,16 @@ typedef struct int *mvcost[2]; int mvsadcosts[2][MVfpvals+1]; int *mvsadcost[2]; +#if CONFIG_HIGH_PRECISION_MV + int mvcosts_hp[2][MVvals_hp+1]; + int *mvcost_hp[2]; + int mvsadcosts_hp[2][MVfpvals_hp+1]; + int *mvsadcost_hp[2]; +#endif int mbmode_cost[2][MB_MODE_COUNT]; int intra_uv_mode_cost[2][MB_MODE_COUNT]; unsigned int bmode_costs[10][10][10]; + unsigned int i8x8_mode_costs[MB_MODE_COUNT]; unsigned int inter_bmode_costs[B_MODE_COUNT]; // These define limits to motion vector components to prevent them from extending outside the UMV borders @@ -116,8 +123,15 @@ typedef struct unsigned char *active_ptr; MV_CONTEXT *mvc; +#if CONFIG_HIGH_PRECISION_MV + MV_CONTEXT_HP *mvc_hp; +#endif + + unsigned int token_costs[BLOCK_TYPES] [COEF_BANDS] + [PREV_COEF_CONTEXTS][MAX_ENTROPY_TOKENS]; + unsigned int token_costs_8x8[BLOCK_TYPES] [COEF_BANDS] + [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; - unsigned int token_costs[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; int optimize; int q_index; @@ -126,6 +140,10 @@ typedef struct void (*short_walsh4x4)(short *input, short *output, int pitch); void (*quantize_b)(BLOCK *b, BLOCKD *d); void (*quantize_b_pair)(BLOCK *b1, BLOCK *b2, BLOCKD *d0, BLOCKD *d1); + void (*vp8_short_fdct8x8)(short *input, short *output, int pitch); + void (*short_fhaar2x2)(short *input, short *output, int pitch); + void (*quantize_b_8x8)(BLOCK *b, BLOCKD *d); + void (*quantize_b_2x2)(BLOCK *b, BLOCKD *d); } MACROBLOCK; diff --git a/vp8/encoder/dct.c b/vp8/encoder/dct.c index c15437f3e..c2f2d1117 100644 --- a/vp8/encoder/dct.c +++ b/vp8/encoder/dct.c @@ -10,7 +10,123 @@ #include -#include "vpx_config.h" +#include "vpx_ports/config.h" + + + + + + +void vp8_short_fdct8x8_c(short *block, short *coefs, int pitch) +{ + int j1, i, j, k; + float b[8]; + float b1[8]; + float d[8][8]; + float f0 = (float) .7071068; + float f1 = (float) .4903926; + float f2 = (float) .4619398; + float f3 = (float) .4157348; + float f4 = (float) .3535534; + float f5 = (float) .2777851; + float f6 = (float) .1913417; + float f7 = (float) .0975452; + pitch = pitch / 2; + for (i = 0, k = 0; i < 8; i++, k += pitch) + { + for (j = 0; j < 8; j++) + { + b[j] = (float)( block[k + j]<<3); + } + /* Horizontal transform */ + for (j = 0; j < 4; j++) + { + j1 = 7 - j; + b1[j] = b[j] + b[j1]; + b1[j1] = b[j] - b[j1]; + } + b[0] = b1[0] + b1[3]; + b[1] = b1[1] + b1[2]; + b[2] = b1[1] - b1[2]; + b[3] = b1[0] - b1[3]; + b[4] = b1[4]; + b[5] = (b1[6] - b1[5]) * f0; + b[6] = (b1[6] + b1[5]) * f0; + b[7] = b1[7]; + d[i][0] = (b[0] + b[1]) * f4; + d[i][4] = (b[0] - b[1]) * f4; + d[i][2] = b[2] * f6 + b[3] * f2; + d[i][6] = b[3] * f6 - b[2] * f2; + b1[4] = b[4] + b[5]; + b1[7] = b[7] + b[6]; + b1[5] = b[4] - b[5]; + b1[6] = b[7] - b[6]; + d[i][1] = b1[4] * f7 + b1[7] * f1; + d[i][5] = b1[5] * f3 + b1[6] * f5; + d[i][7] = b1[7] * f7 - b1[4] * f1; + d[i][3] = b1[6] * f3 - b1[5] * f5; + } + /* Vertical transform */ + for (i = 0; i < 8; i++) + { + for (j = 0; j < 4; j++) + { + j1 = 7 - j; + b1[j] = d[j][i] + d[j1][i]; + b1[j1] = d[j][i] - d[j1][i]; + } + b[0] = b1[0] + b1[3]; + b[1] = b1[1] + b1[2]; + b[2] = b1[1] - b1[2]; + b[3] = b1[0] - b1[3]; + b[4] = b1[4]; + b[5] = (b1[6] - b1[5]) * f0; + b[6] = (b1[6] + b1[5]) * f0; + b[7] = b1[7]; + d[0][i] = (b[0] + b[1]) * f4; + d[4][i] = (b[0] - b[1]) * f4; + d[2][i] = b[2] * f6 + b[3] * f2; + d[6][i] = b[3] * f6 - b[2] * f2; + b1[4] = b[4] + b[5]; + b1[7] = b[7] + b[6]; + b1[5] = b[4] - b[5]; + b1[6] = b[7] - b[6]; + d[1][i] = b1[4] * f7 + b1[7] * f1; + d[5][i] = b1[5] * f3 + b1[6] * f5; + d[7][i] = b1[7] * f7 - b1[4] * f1; + d[3][i] = b1[6] * f3 - b1[5] * f5; + } + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + *(coefs + j + i * 8) = (short) floor(d[i][j] +0.5); + } + } + return; +} + + + +void vp8_short_fhaar2x2_c(short *input, short *output, int pitch) //pitch = 8 +{ + /* [1 1 ; 1 -1] orthogonal transform */ + /* use position: 0,1, 4, 8 */ + int i; + short *ip1 = input; + short *op1 = output; + for (i = 0; i < 16; i++) + { + op1[i] = 0; + } + + op1[0]=(ip1[0] + ip1[1] + ip1[4] + ip1[8] + 1)>>1; + op1[1]=(ip1[0] - ip1[1] + ip1[4] - ip1[8])>>1; + op1[4]=(ip1[0] + ip1[1] - ip1[4] - ip1[8])>>1; + op1[8]=(ip1[0] - ip1[1] - ip1[4] + ip1[8])>>1; + +} + void vp8_short_fdct4x4_c(short *input, short *output, int pitch) { int i; @@ -20,17 +136,11 @@ void vp8_short_fdct4x4_c(short *input, short *output, int pitch) for (i = 0; i < 4; i++) { -#if CONFIG_EXTEND_QRANGE a1 = ((ip[0] + ip[3])<<5); b1 = ((ip[1] + ip[2])<<5); c1 = ((ip[1] - ip[2])<<5); d1 = ((ip[0] - ip[3])<<5); -#else - a1 = ((ip[0] + ip[3])<<3); - b1 = ((ip[1] + ip[2])<<3); - c1 = ((ip[1] - ip[2])<<3); - d1 = ((ip[0] - ip[3])<<3); -#endif + op[0] = a1 + b1; op[2] = a1 - b1; @@ -78,22 +188,12 @@ void vp8_short_walsh4x4_c(short *input, short *output, int pitch) for (i = 0; i < 4; i++) { -#if !CONFIG_EXTEND_QRANGE - a1 = ((ip[0] + ip[2])<<2); - d1 = ((ip[1] + ip[3])<<2); - c1 = ((ip[1] - ip[3])<<2); - b1 = ((ip[0] - ip[2])<<2); - - op[0] = a1 + d1 + (a1!=0); -#else a1 = ((ip[0] + ip[2])); d1 = ((ip[1] + ip[3])); c1 = ((ip[1] - ip[3])); b1 = ((ip[0] - ip[2])); - op[0] = a1 + d1; -#endif op[1] = b1 + c1; op[2] = b1 - c1; op[3] = a1 - d1; @@ -121,17 +221,11 @@ void vp8_short_walsh4x4_c(short *input, short *output, int pitch) c2 += c2<0; d2 += d2<0; -#if !CONFIG_EXTEND_QRANGE - op[0] = (a2+3) >> 3; - op[4] = (b2+3) >> 3; - op[8] = (c2+3) >> 3; - op[12]= (d2+3) >> 3; -#else op[0] = (a2+1) >> 2; op[4] = (b2+1) >> 2; op[8] = (c2+1) >> 2; op[12]= (d2+1) >> 2; -#endif + ip++; op++; } diff --git a/vp8/encoder/dct.h b/vp8/encoder/dct.h index fec3b4c37..7ab525c0b 100644 --- a/vp8/encoder/dct.h +++ b/vp8/encoder/dct.h @@ -22,6 +22,19 @@ #include "arm/dct_arm.h" #endif + + +#ifndef vp8_fdct_short8x8 +#define vp8_fdct_short8x8 vp8_short_fdct8x8_c +#endif +extern prototype_fdct(vp8_fdct_short8x8); + +#ifndef vp8_fhaar_short2x2 +#define vp8_fhaar_short2x2 vp8_short_fhaar2x2_c +#endif +extern prototype_fdct(vp8_fhaar_short2x2); + + #ifndef vp8_fdct_short4x4 #define vp8_fdct_short4x4 vp8_short_fdct4x4_c #endif @@ -49,6 +62,8 @@ extern prototype_fdct(vp8_fdct_walsh_short4x4); typedef prototype_fdct(*vp8_fdct_fn_t); typedef struct { + vp8_fdct_fn_t short8x8; + vp8_fdct_fn_t haar_short2x2; vp8_fdct_fn_t short4x4; vp8_fdct_fn_t short8x4; vp8_fdct_fn_t fast4x4; diff --git a/vp8/encoder/defaultcoefcounts.h b/vp8/encoder/defaultcoefcounts.h deleted file mode 100644 index 2c0f3ddf3..000000000 --- a/vp8/encoder/defaultcoefcounts.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -/* Generated file, included by entropy.c */ - -static const unsigned int default_coef_counts[BLOCK_TYPES] - [COEF_BANDS] - [PREV_COEF_CONTEXTS] - [MAX_ENTROPY_TOKENS] = -{ - - { - /* Block Type ( 0 ) */ - { - /* Coeff Band ( 0 ) */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - }, - { - /* Coeff Band ( 1 ) */ - {30190, 26544, 225, 24, 4, 0, 0, 0, 0, 0, 0, 4171593,}, - {26846, 25157, 1241, 130, 26, 6, 1, 0, 0, 0, 0, 149987,}, - {10484, 9538, 1006, 160, 36, 18, 0, 0, 0, 0, 0, 15104,}, - }, - { - /* Coeff Band ( 2 ) */ - {25842, 40456, 1126, 83, 11, 2, 0, 0, 0, 0, 0, 0,}, - {9338, 8010, 512, 73, 7, 3, 2, 0, 0, 0, 0, 43294,}, - {1047, 751, 149, 31, 13, 6, 1, 0, 0, 0, 0, 879,}, - }, - { - /* Coeff Band ( 3 ) */ - {26136, 9826, 252, 13, 0, 0, 0, 0, 0, 0, 0, 0,}, - {8134, 5574, 191, 14, 2, 0, 0, 0, 0, 0, 0, 35302,}, - { 605, 677, 116, 9, 1, 0, 0, 0, 0, 0, 0, 611,}, - }, - { - /* Coeff Band ( 4 ) */ - {10263, 15463, 283, 17, 0, 0, 0, 0, 0, 0, 0, 0,}, - {2773, 2191, 128, 9, 2, 2, 0, 0, 0, 0, 0, 10073,}, - { 134, 125, 32, 4, 0, 2, 0, 0, 0, 0, 0, 50,}, - }, - { - /* Coeff Band ( 5 ) */ - {10483, 2663, 23, 1, 0, 0, 0, 0, 0, 0, 0, 0,}, - {2137, 1251, 27, 1, 1, 0, 0, 0, 0, 0, 0, 14362,}, - { 116, 156, 14, 2, 1, 0, 0, 0, 0, 0, 0, 190,}, - }, - { - /* Coeff Band ( 6 ) */ - {40977, 27614, 412, 28, 0, 0, 0, 0, 0, 0, 0, 0,}, - {6113, 5213, 261, 22, 3, 0, 0, 0, 0, 0, 0, 26164,}, - { 382, 312, 50, 14, 2, 0, 0, 0, 0, 0, 0, 345,}, - }, - { - /* Coeff Band ( 7 ) */ - { 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319,}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,}, - }, - }, - { - /* Block Type ( 1 ) */ - { - /* Coeff Band ( 0 ) */ - {3268, 19382, 1043, 250, 93, 82, 49, 26, 17, 8, 25, 82289,}, - {8758, 32110, 5436, 1832, 827, 668, 420, 153, 24, 0, 3, 52914,}, - {9337, 23725, 8487, 3954, 2107, 1836, 1069, 399, 59, 0, 0, 18620,}, - }, - { - /* Coeff Band ( 1 ) */ - {12419, 8420, 452, 62, 9, 1, 0, 0, 0, 0, 0, 0,}, - {11715, 8705, 693, 92, 15, 7, 2, 0, 0, 0, 0, 53988,}, - {7603, 8585, 2306, 778, 270, 145, 39, 5, 0, 0, 0, 9136,}, - }, - { - /* Coeff Band ( 2 ) */ - {15938, 14335, 1207, 184, 55, 13, 4, 1, 0, 0, 0, 0,}, - {7415, 6829, 1138, 244, 71, 26, 7, 0, 0, 0, 0, 9980,}, - {1580, 1824, 655, 241, 89, 46, 10, 2, 0, 0, 0, 429,}, - }, - { - /* Coeff Band ( 3 ) */ - {19453, 5260, 201, 19, 0, 0, 0, 0, 0, 0, 0, 0,}, - {9173, 3758, 213, 22, 1, 1, 0, 0, 0, 0, 0, 9820,}, - {1689, 1277, 276, 51, 17, 4, 0, 0, 0, 0, 0, 679,}, - }, - { - /* Coeff Band ( 4 ) */ - {12076, 10667, 620, 85, 19, 9, 5, 0, 0, 0, 0, 0,}, - {4665, 3625, 423, 55, 19, 9, 0, 0, 0, 0, 0, 5127,}, - { 415, 440, 143, 34, 20, 7, 2, 0, 0, 0, 0, 101,}, - }, - { - /* Coeff Band ( 5 ) */ - {12183, 4846, 115, 11, 1, 0, 0, 0, 0, 0, 0, 0,}, - {4226, 3149, 177, 21, 2, 0, 0, 0, 0, 0, 0, 7157,}, - { 375, 621, 189, 51, 11, 4, 1, 0, 0, 0, 0, 198,}, - }, - { - /* Coeff Band ( 6 ) */ - {61658, 37743, 1203, 94, 10, 3, 0, 0, 0, 0, 0, 0,}, - {15514, 11563, 903, 111, 14, 5, 0, 0, 0, 0, 0, 25195,}, - { 929, 1077, 291, 78, 14, 7, 1, 0, 0, 0, 0, 507,}, - }, - { - /* Coeff Band ( 7 ) */ - { 0, 990, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 0, 412, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1641,}, - { 0, 18, 7, 1, 0, 0, 0, 0, 0, 0, 0, 30,}, - }, - }, - { - /* Block Type ( 2 ) */ - { - /* Coeff Band ( 0 ) */ - { 953, 24519, 628, 120, 28, 12, 4, 0, 0, 0, 0, 2248798,}, - {1525, 25654, 2647, 617, 239, 143, 42, 5, 0, 0, 0, 66837,}, - {1180, 11011, 3001, 1237, 532, 448, 239, 54, 5, 0, 0, 7122,}, - }, - { - /* Coeff Band ( 1 ) */ - {1356, 2220, 67, 10, 4, 1, 0, 0, 0, 0, 0, 0,}, - {1450, 2544, 102, 18, 4, 3, 0, 0, 0, 0, 0, 57063,}, - {1182, 2110, 470, 130, 41, 21, 0, 0, 0, 0, 0, 6047,}, - }, - { - /* Coeff Band ( 2 ) */ - { 370, 3378, 200, 30, 5, 4, 1, 0, 0, 0, 0, 0,}, - { 293, 1006, 131, 29, 11, 0, 0, 0, 0, 0, 0, 5404,}, - { 114, 387, 98, 23, 4, 8, 1, 0, 0, 0, 0, 236,}, - }, - { - /* Coeff Band ( 3 ) */ - { 579, 194, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 395, 213, 5, 1, 0, 0, 0, 0, 0, 0, 0, 4157,}, - { 119, 122, 4, 0, 0, 0, 0, 0, 0, 0, 0, 300,}, - }, - { - /* Coeff Band ( 4 ) */ - { 38, 557, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 21, 114, 12, 1, 0, 0, 0, 0, 0, 0, 0, 427,}, - { 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,}, - }, - { - /* Coeff Band ( 5 ) */ - { 52, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 652,}, - { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,}, - }, - { - /* Coeff Band ( 6 ) */ - { 640, 569, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 25, 77, 2, 0, 0, 0, 0, 0, 0, 0, 0, 517,}, - { 4, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,}, - }, - { - /* Coeff Band ( 7 ) */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - }, - }, - { - /* Block Type ( 3 ) */ - { - /* Coeff Band ( 0 ) */ - {2506, 20161, 2707, 767, 261, 178, 107, 30, 14, 3, 0, 100694,}, - {8806, 36478, 8817, 3268, 1280, 850, 401, 114, 42, 0, 0, 58572,}, - {11003, 27214, 11798, 5716, 2482, 2072, 1048, 175, 32, 0, 0, 19284,}, - }, - { - /* Coeff Band ( 1 ) */ - {9738, 11313, 959, 205, 70, 18, 11, 1, 0, 0, 0, 0,}, - {12628, 15085, 1507, 273, 52, 19, 9, 0, 0, 0, 0, 54280,}, - {10701, 15846, 5561, 1926, 813, 570, 249, 36, 0, 0, 0, 6460,}, - }, - { - /* Coeff Band ( 2 ) */ - {6781, 22539, 2784, 634, 182, 123, 20, 4, 0, 0, 0, 0,}, - {6263, 11544, 2649, 790, 259, 168, 27, 5, 0, 0, 0, 20539,}, - {3109, 4075, 2031, 896, 457, 386, 158, 29, 0, 0, 0, 1138,}, - }, - { - /* Coeff Band ( 3 ) */ - {11515, 4079, 465, 73, 5, 14, 2, 0, 0, 0, 0, 0,}, - {9361, 5834, 650, 96, 24, 8, 4, 0, 0, 0, 0, 22181,}, - {4343, 3974, 1360, 415, 132, 96, 14, 1, 0, 0, 0, 1267,}, - }, - { - /* Coeff Band ( 4 ) */ - {4787, 9297, 823, 168, 44, 12, 4, 0, 0, 0, 0, 0,}, - {3619, 4472, 719, 198, 60, 31, 3, 0, 0, 0, 0, 8401,}, - {1157, 1175, 483, 182, 88, 31, 8, 0, 0, 0, 0, 268,}, - }, - { - /* Coeff Band ( 5 ) */ - {8299, 1226, 32, 5, 1, 0, 0, 0, 0, 0, 0, 0,}, - {3502, 1568, 57, 4, 1, 1, 0, 0, 0, 0, 0, 9811,}, - {1055, 1070, 166, 29, 6, 1, 0, 0, 0, 0, 0, 527,}, - }, - { - /* Coeff Band ( 6 ) */ - {27414, 27927, 1989, 347, 69, 26, 0, 0, 0, 0, 0, 0,}, - {5876, 10074, 1574, 341, 91, 24, 4, 0, 0, 0, 0, 21954,}, - {1571, 2171, 778, 324, 124, 65, 16, 0, 0, 0, 0, 979,}, - }, - { - /* Coeff Band ( 7 ) */ - { 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - { 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 459,}, - { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,}, - }, - }, -}; diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index 46e6c7645..a59dd6324 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "encodemb.h" #include "encodemv.h" #include "vp8/common/common.h" @@ -22,13 +22,17 @@ #include "encodeintra.h" #include "vp8/common/reconinter.h" #include "rdopt.h" -#include "pickinter.h" #include "vp8/common/findnearmv.h" #include "vp8/common/reconintra.h" +#include "vp8/common/seg_common.h" #include +#include #include #include "vp8/common/subpixel.h" #include "vpx_ports/vpx_timer.h" +#include "vp8/common/pred_common.h" + +//#define DBG_PRNT_SEGMAP 1 #if CONFIG_RUNTIME_CPU_DETECT #define RTCD(x) &cpi->common.rtcd.x @@ -37,6 +41,12 @@ #define RTCD(x) NULL #define IF_RTCD(x) NULL #endif + +#ifdef ENC_DEBUG +int enc_debug=0; +int mb_row_debug, mb_col_debug; +#endif + extern void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) ; extern void vp8cx_initialize_me_consts(VP8_COMP *cpi, int QIndex); @@ -52,13 +62,25 @@ int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t); static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x ); + + #ifdef MODE_STATS -unsigned int inter_y_modes[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -unsigned int inter_uv_modes[4] = {0, 0, 0, 0}; -unsigned int inter_b_modes[15] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -unsigned int y_modes[5] = {0, 0, 0, 0, 0}; -unsigned int uv_modes[4] = {0, 0, 0, 0}; -unsigned int b_modes[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int inter_y_modes[MB_MODE_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int inter_uv_modes[VP8_UV_MODES] = {0, 0, 0, 0}; +unsigned int inter_b_modes[B_MODE_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int y_modes[VP8_YMODES] = {0, 0, 0, 0, 0, 0}; +unsigned int i8x8_modes[VP8_I8X8_MODES]={0 }; +unsigned int uv_modes[VP8_UV_MODES] = {0, 0, 0, 0}; +unsigned int uv_modes_y[VP8_YMODES][VP8_UV_MODES]= +{ +{0, 0, 0, 0}, +{0, 0, 0, 0}, +{0, 0, 0, 0}, +{0, 0, 0, 0}, +{0, 0, 0, 0}, +{0, 0, 0, 0} +}; +unsigned int b_modes[B_MODE_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; #endif @@ -365,7 +387,6 @@ void encode_mb_row(VP8_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd, TOKENEXTRA **tp, - int *segment_counts, int *totalrate) { int recon_yoffset, recon_uvoffset; @@ -376,16 +397,8 @@ void encode_mb_row(VP8_COMP *cpi, int recon_uv_stride = cm->yv12_fb[ref_fb_idx].uv_stride; int map_index = (mb_row * cpi->common.mb_cols); -#if CONFIG_MULTITHREAD - const int nsync = cpi->mt_sync_range; - const int rightmost_col = cm->mb_cols - 1; - volatile const int *last_row_current_mb_col; - - if ((cpi->b_multi_threaded != 0) && (mb_row != 0)) - last_row_current_mb_col = &cpi->mt_current_mb_col[mb_row - 1]; - else - last_row_current_mb_col = &rightmost_col; -#endif + // Reset the left context + vp8_zero(cm->left_context) // reset above block coeffs xd->above_context = cm->above_context; @@ -414,6 +427,11 @@ void encode_mb_row(VP8_COMP *cpi, // for each macroblock col in image for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) { +#ifdef ENC_DEBUG + enc_debug = (cpi->common.current_video_frame ==1 && mb_row==4 && mb_col==0); + mb_col_debug=mb_col; + mb_row_debug=mb_row; +#endif // Distance of Mb to the left & right edges, specified in // 1/8th pel units as they are always compared to values // that are in 1/8th pel units @@ -437,29 +455,13 @@ void encode_mb_row(VP8_COMP *cpi, //Copy current mb to a buffer RECON_INVOKE(&xd->rtcd->recon, copy16x16)(x->src.y_buffer, x->src.y_stride, x->thismb, 16); -#if CONFIG_MULTITHREAD - if ((cpi->b_multi_threaded != 0) && (mb_row != 0)) - { - if ((mb_col & (nsync - 1)) == 0) - { - while (mb_col > (*last_row_current_mb_col - nsync) - && (*last_row_current_mb_col) != (cm->mb_cols - 1)) - { - x86_pause_hint(); - thread_sleep(0); - } - } - } -#endif - if(cpi->oxcf.tuning == VP8_TUNE_SSIM) vp8_activity_masking(cpi, x); // Is segmentation enabled - // MB level adjutment to quantizer if (xd->segmentation_enabled) { - // Code to set segment id in xd->mbmi.segment_id for current MB (with range checking) + // Code to set segment id in xd->mbmi.segment_id if (cpi->segmentation_map[map_index+mb_col] <= 3) xd->mode_info_context->mbmi.segment_id = cpi->segmentation_map[map_index+mb_col]; else @@ -468,66 +470,51 @@ void encode_mb_row(VP8_COMP *cpi, vp8cx_mb_init_quantizer(cpi, x); } else - xd->mode_info_context->mbmi.segment_id = 0; // Set to Segment 0 by default + // Set to Segment 0 by default + xd->mode_info_context->mbmi.segment_id = 0; x->active_ptr = cpi->active_map + map_index + mb_col; + /* force 4x4 transform for mode selection */ + xd->mode_info_context->mbmi.txfm_size = TX_4X4; + if (cm->frame_type == KEY_FRAME) { *totalrate += vp8cx_encode_intra_macro_block(cpi, x, tp); + //Note the encoder may have changed the segment_id + #ifdef MODE_STATS - y_modes[xd->mbmi.mode] ++; + y_modes[xd->mode_info_context->mbmi.mode] ++; #endif } else { *totalrate += vp8cx_encode_inter_macroblock(cpi, x, tp, recon_yoffset, recon_uvoffset); + //Note the encoder may have changed the segment_id #ifdef MODE_STATS - inter_y_modes[xd->mbmi.mode] ++; + inter_y_modes[xd->mode_info_context->mbmi.mode] ++; - if (xd->mbmi.mode == SPLITMV) + if (xd->mode_info_context->mbmi.mode == SPLITMV) { int b; - for (b = 0; b < xd->mbmi.partition_count; b++) + for (b = 0; b < x->partition_info->count; b++) { - inter_b_modes[x->partition->bmi[b].mode] ++; + inter_b_modes[x->partition_info->bmi[b].mode] ++; } } #endif - // Count of last ref frame 0,0 useage + // Count of last ref frame 0,0 usage if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)) cpi->inter_zz_count ++; - - // Special case code for cyclic refresh - // If cyclic update enabled then copy xd->mbmi.segment_id; (which may have been updated based on mode - // during vp8cx_encode_inter_macroblock()) back into the global sgmentation map - if (cpi->cyclic_refresh_mode_enabled && xd->segmentation_enabled) - { - cpi->segmentation_map[map_index+mb_col] = xd->mode_info_context->mbmi.segment_id; - - // If the block has been refreshed mark it as clean (the magnitude of the -ve influences how long it will be before we consider another refresh): - // Else if it was coded (last frame 0,0) and has not already been refreshed then mark it as a candidate for cleanup next time (marked 0) - // else mark it as dirty (1). - if (xd->mode_info_context->mbmi.segment_id) - cpi->cyclic_refresh_map[map_index+mb_col] = -1; - else if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)) - { - if (cpi->cyclic_refresh_map[map_index+mb_col] == 1) - cpi->cyclic_refresh_map[map_index+mb_col] = 0; - } - else - cpi->cyclic_refresh_map[map_index+mb_col] = 1; - - } } cpi->tplist[mb_row].stop = *tp; - // Increment pointer into gf useage flags structure. + // Increment pointer into gf usage flags structure. x->gf_active_ptr++; // Increment the activity mask pointers. @@ -541,20 +528,15 @@ void encode_mb_row(VP8_COMP *cpi, recon_yoffset += 16; recon_uvoffset += 8; - // Keep track of segment useage - segment_counts[xd->mode_info_context->mbmi.segment_id] ++; - // skip to next mb xd->mode_info_context++; + + xd->prev_mode_info_context++; + assert((xd->prev_mode_info_context - cpi->common.prev_mip) + ==(xd->mode_info_context - cpi->common.mip)); x->partition_info++; xd->above_context++; -#if CONFIG_MULTITHREAD - if (cpi->b_multi_threaded != 0) - { - cpi->mt_current_mb_col[mb_row] = mb_col; - } -#endif } //extend the recon for intra prediction @@ -565,13 +547,17 @@ void encode_mb_row(VP8_COMP *cpi, xd->dst.v_buffer + 8); // this is to account for the border + xd->prev_mode_info_context++; xd->mode_info_context++; x->partition_info++; -#if CONFIG_MULTITHREAD - if ((cpi->b_multi_threaded != 0) && (mb_row == cm->mb_rows - 1)) +// debug output +#if DBG_PRNT_SEGMAP { - sem_post(&cpi->h_event_end_encoding); /* signal frame encoding end */ + FILE *statsfile; + statsfile = fopen("segmap2.stt", "a"); + fprintf(statsfile, "\n" ); + fclose(statsfile); } #endif } @@ -596,6 +582,7 @@ void init_encode_frame_mb_context(VP8_COMP *cpi) xd->mode_info_context = cm->mi; xd->mode_info_stride = cm->mode_info_stride; + xd->prev_mode_info_context = cm->prev_mi; xd->frame_type = cm->frame_type; @@ -630,42 +617,19 @@ void init_encode_frame_mb_context(VP8_COMP *cpi) vp8_zero(cpi->uv_mode_count) x->mvc = cm->fc.mvc; +#if CONFIG_HIGH_PRECISION_MV + x->mvc_hp = cm->fc.mvc_hp; +#endif vpx_memset(cm->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES) * cm->mb_cols); - xd->ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(cpi->prob_intra_coded); - - // Special case treatment when GF and ARF are not sensible options for reference - if (cpi->ref_frame_flags == VP8_LAST_FLAG) - { - xd->ref_frame_cost[LAST_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_zero(255); - xd->ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_one(255) - + vp8_cost_zero(128); - xd->ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_one(255) - + vp8_cost_one(128); - } - else - { - xd->ref_frame_cost[LAST_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_zero(cpi->prob_last_coded); - xd->ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_one(cpi->prob_last_coded) - + vp8_cost_zero(cpi->prob_gf_coded); - xd->ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cpi->prob_intra_coded) - + vp8_cost_one(cpi->prob_last_coded) - + vp8_cost_one(cpi->prob_gf_coded); - } - xd->fullpixel_mask = 0xffffffff; if(cm->full_pixel) xd->fullpixel_mask = 0xfffffff8; } -void vp8_encode_frame(VP8_COMP *cpi) +static void encode_frame_internal(VP8_COMP *cpi) { int mb_row; MACROBLOCK *const x = & cpi->mb; @@ -673,19 +637,24 @@ void vp8_encode_frame(VP8_COMP *cpi) MACROBLOCKD *const xd = & x->e_mbd; TOKENEXTRA *tp = cpi->tok; - int segment_counts[MAX_MB_SEGMENTS]; int totalrate; - vpx_memset(segment_counts, 0, sizeof(segment_counts)); - totalrate = 0; + // Compute a modified set of reference frame probabilities to use when + // prediction fails. These are based on the current genreal estimates for + // this frame which may be updated with each itteration of the recode loop. + compute_mod_refprobs( cm ); - if (cpi->compressor_speed == 2) +// debug output +#if DBG_PRNT_SEGMAP { - if (cpi->oxcf.cpu_used < 0) - cpi->Speed = -(cpi->oxcf.cpu_used); - else - vp8_auto_select_speed(cpi); + FILE *statsfile; + statsfile = fopen("segmap2.stt", "a"); + fprintf(statsfile, "\n" ); + fclose(statsfile); } +#endif + + totalrate = 0; // Functions setup for all frame types so we can use MC in AltRef if (cm->mcomp_filter_type == SIXTAP) @@ -698,6 +667,10 @@ void vp8_encode_frame(VP8_COMP *cpi) &cpi->common.rtcd.subpix, sixtap8x8); xd->subpixel_predict16x16 = SUBPIX_INVOKE( &cpi->common.rtcd.subpix, sixtap16x16); + xd->subpixel_predict_avg8x8 = SUBPIX_INVOKE( + &cpi->common.rtcd.subpix, sixtap_avg8x8); + xd->subpixel_predict_avg16x16 = SUBPIX_INVOKE( + &cpi->common.rtcd.subpix, sixtap_avg16x16); } else { @@ -709,13 +682,15 @@ void vp8_encode_frame(VP8_COMP *cpi) &cpi->common.rtcd.subpix, bilinear8x8); xd->subpixel_predict16x16 = SUBPIX_INVOKE( &cpi->common.rtcd.subpix, bilinear16x16); + xd->subpixel_predict_avg8x8 = SUBPIX_INVOKE( + &cpi->common.rtcd.subpix, bilinear_avg8x8); + xd->subpixel_predict_avg16x16 = SUBPIX_INVOKE( + &cpi->common.rtcd.subpix, bilinear_avg16x16); } - // Reset frame count of inter 0,0 motion vector useage. + // Reset frame count of inter 0,0 motion vector usage. cpi->inter_zz_count = 0; - vpx_memset(segment_counts, 0, sizeof(segment_counts)); - cpi->prediction_error = 0; cpi->intra_error = 0; cpi->skip_true_count = 0; @@ -729,7 +704,12 @@ void vp8_encode_frame(VP8_COMP *cpi) xd->mode_info_context = cm->mi; + xd->prev_mode_info_context = cm->prev_mi; + vp8_zero(cpi->MVcount); +#if CONFIG_HIGH_PRECISION_MV + vp8_zero(cpi->MVcount_hp); +#endif vp8_zero(cpi->coef_counts); vp8cx_frame_init_quantizer(cpi); @@ -749,86 +729,21 @@ void vp8_encode_frame(VP8_COMP *cpi) // re-initencode frame context. init_encode_frame_mb_context(cpi); + cpi->rd_single_diff = cpi->rd_comp_diff = cpi->rd_hybrid_diff = 0; + vpx_memset(cpi->single_pred_count, 0, sizeof(cpi->single_pred_count)); + vpx_memset(cpi->comp_pred_count, 0, sizeof(cpi->comp_pred_count)); + { struct vpx_usec_timer emr_timer; vpx_usec_timer_start(&emr_timer); -#if CONFIG_MULTITHREAD - if (cpi->b_multi_threaded) { - int i; - - vp8cx_init_mbrthread_data(cpi, x, cpi->mb_row_ei, 1, cpi->encoding_thread_count); - - for (i = 0; i < cm->mb_rows; i++) - cpi->mt_current_mb_col[i] = -1; - - for (i = 0; i < cpi->encoding_thread_count; i++) - { - sem_post(&cpi->h_event_start_encoding[i]); - } - - for (mb_row = 0; mb_row < cm->mb_rows; mb_row += (cpi->encoding_thread_count + 1)) - { - vp8_zero(cm->left_context) - - tp = cpi->tok + mb_row * (cm->mb_cols * 16 * 24); - - encode_mb_row(cpi, cm, mb_row, x, xd, &tp, segment_counts, &totalrate); - - // adjust to the next row of mbs - x->src.y_buffer += 16 * x->src.y_stride * (cpi->encoding_thread_count + 1) - 16 * cm->mb_cols; - x->src.u_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; - x->src.v_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; - - xd->mode_info_context += xd->mode_info_stride * cpi->encoding_thread_count; - x->partition_info += xd->mode_info_stride * cpi->encoding_thread_count; - x->gf_active_ptr += cm->mb_cols * cpi->encoding_thread_count; - - } - - sem_wait(&cpi->h_event_end_encoding); /* wait for other threads to finish */ - - cpi->tok_count = 0; - - for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++) - { - cpi->tok_count += cpi->tplist[mb_row].stop - cpi->tplist[mb_row].start; - } - - if (xd->segmentation_enabled) - { - int i, j; - - if (xd->segmentation_enabled) - { - - for (i = 0; i < cpi->encoding_thread_count; i++) - { - for (j = 0; j < 4; j++) - segment_counts[j] += cpi->mb_row_ei[i].segment_counts[j]; - } - } - } - - for (i = 0; i < cpi->encoding_thread_count; i++) - { - totalrate += cpi->mb_row_ei[i].totalrate; - } - - } - else -#endif - { - // for each macroblock row in image + // for each macroblock row in the image for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) { + encode_mb_row(cpi, cm, mb_row, x, xd, &tp, &totalrate); - vp8_zero(cm->left_context) - - encode_mb_row(cpi, cm, mb_row, x, xd, &tp, segment_counts, &totalrate); - - // adjust to the next row of mbs + // adjust to the next row of MBs x->src.y_buffer += 16 * x->src.y_stride - 16 * cm->mb_cols; x->src.u_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; x->src.v_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; @@ -843,43 +758,6 @@ void vp8_encode_frame(VP8_COMP *cpi) } - - // Work out the segment probabilites if segmentation is enabled - if (xd->segmentation_enabled) - { - int tot_count; - int i; - - // Set to defaults - vpx_memset(xd->mb_segment_tree_probs, 255 , sizeof(xd->mb_segment_tree_probs)); - - tot_count = segment_counts[0] + segment_counts[1] + segment_counts[2] + segment_counts[3]; - - if (tot_count) - { - xd->mb_segment_tree_probs[0] = ((segment_counts[0] + segment_counts[1]) * 255) / tot_count; - - tot_count = segment_counts[0] + segment_counts[1]; - - if (tot_count > 0) - { - xd->mb_segment_tree_probs[1] = (segment_counts[0] * 255) / tot_count; - } - - tot_count = segment_counts[2] + segment_counts[3]; - - if (tot_count > 0) - xd->mb_segment_tree_probs[2] = (segment_counts[2] * 255) / tot_count; - - // Zero probabilities not allowed - for (i = 0; i < MB_FEATURE_TREE_PROBS; i ++) - { - if (xd->mb_segment_tree_probs[i] == 0) - xd->mb_segment_tree_probs[i] = 1; - } - } - } - // 256 rate units to the bit cpi->projected_frame_size = totalrate >> 8; // projected_frame_size in units of BYTES @@ -932,44 +810,95 @@ void vp8_encode_frame(VP8_COMP *cpi) } #endif - // Adjust the projected reference frame useage probability numbers to reflect - // what we have just seen. This may be usefull when we make multiple itterations - // of the recode loop rather than continuing to use values from the previous frame. - if ((cm->frame_type != KEY_FRAME) && !cm->refresh_alt_ref_frame && !cm->refresh_golden_frame) - { - const int *const rfct = cpi->count_mb_ref_frame_usage; - const int rf_intra = rfct[INTRA_FRAME]; - const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; - - if ((rf_intra + rf_inter) > 0) - { - cpi->prob_intra_coded = (rf_intra * 255) / (rf_intra + rf_inter); - - if (cpi->prob_intra_coded < 1) - cpi->prob_intra_coded = 1; - - if ((cm->frames_since_golden > 0) || cpi->source_alt_ref_active) - { - cpi->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; - - if (cpi->prob_last_coded < 1) - cpi->prob_last_coded = 1; - - cpi->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) - ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; - - if (cpi->prob_gf_coded < 1) - cpi->prob_gf_coded = 1; - } - } - } - #if 0 // Keep record of the total distortion this time around for future use cpi->last_frame_distortion = cpi->frame_distortion; #endif } + +void vp8_encode_frame(VP8_COMP *cpi) +{ + if (cpi->sf.RD) + { + int frame_type, pred_type; + int redo = 0; + int single_diff, comp_diff, hybrid_diff; + + /* + * This code does a single RD pass over the whole frame assuming + * either compound, single or hybrid prediction as per whatever has + * worked best for that type of frame in the past. + * It also predicts whether another coding mode would have worked + * better that this coding mode. If that is the case, it remembers + * that for subsequent frames. If the difference is above a certain + * threshold, it will actually re-encode the current frame using + * that different coding mode. + */ + if (cpi->common.frame_type == KEY_FRAME) + frame_type = 0; + else if (cpi->is_src_frame_alt_ref && cpi->common.refresh_golden_frame) + frame_type = 3; + else if (cpi->common.refresh_golden_frame || cpi->common.refresh_alt_ref_frame) + frame_type = 1; + else + frame_type = 2; + + if (cpi->rd_prediction_type_threshes[frame_type][1] > + cpi->rd_prediction_type_threshes[frame_type][0] && + cpi->rd_prediction_type_threshes[frame_type][1] > + cpi->rd_prediction_type_threshes[frame_type][2]) + pred_type = COMP_PREDICTION_ONLY; + else if (cpi->rd_prediction_type_threshes[frame_type][0] > + cpi->rd_prediction_type_threshes[frame_type][1] && + cpi->rd_prediction_type_threshes[frame_type][0] > + cpi->rd_prediction_type_threshes[frame_type][2]) + pred_type = SINGLE_PREDICTION_ONLY; + else + pred_type = HYBRID_PREDICTION; + + cpi->common.comp_pred_mode = pred_type; + encode_frame_internal(cpi); + + single_diff = cpi->rd_single_diff / cpi->common.MBs; + cpi->rd_prediction_type_threshes[frame_type][0] += single_diff; + cpi->rd_prediction_type_threshes[frame_type][0] >>= 1; + comp_diff = cpi->rd_comp_diff / cpi->common.MBs; + cpi->rd_prediction_type_threshes[frame_type][1] += comp_diff; + cpi->rd_prediction_type_threshes[frame_type][1] >>= 1; + hybrid_diff = cpi->rd_hybrid_diff / cpi->common.MBs; + cpi->rd_prediction_type_threshes[frame_type][2] += hybrid_diff; + cpi->rd_prediction_type_threshes[frame_type][2] >>= 1; + + if (cpi->common.comp_pred_mode == HYBRID_PREDICTION) + { + int single_count_zero = 0; + int comp_count_zero = 0; + int i; + + for ( i = 0; i < COMP_PRED_CONTEXTS; i++ ) + { + single_count_zero += cpi->single_pred_count[i]; + comp_count_zero += cpi->comp_pred_count[i]; + } + + if (comp_count_zero == 0) + { + cpi->common.comp_pred_mode = SINGLE_PREDICTION_ONLY; + } + else if (single_count_zero == 0) + { + cpi->common.comp_pred_mode = COMP_PREDICTION_ONLY; + } + } + } + else + { + encode_frame_internal(cpi); + } + +} + void vp8_setup_block_ptrs(MACROBLOCK *x) { int r, c; @@ -1070,6 +999,7 @@ static void sum_intra_stats(VP8_COMP *cpi, MACROBLOCK *x) const int is_key = cpi->common.frame_type == KEY_FRAME; ++ (is_key ? uv_modes : inter_uv_modes)[uvm]; + ++ uv_modes_y[m][uvm]; if (m == B_PRED) { @@ -1079,11 +1009,18 @@ static void sum_intra_stats(VP8_COMP *cpi, MACROBLOCK *x) do { - ++ bct[xd->block[b].bmi.mode]; + ++ bct[xd->block[b].bmi.as_mode.first]; } while (++b < 16); } + if(m==I8X8_PRED) + { + i8x8_modes[xd->block[0].bmi.as_mode.first]++; + i8x8_modes[xd->block[2].bmi.as_mode.first]++; + i8x8_modes[xd->block[8].bmi.as_mode.first]++; + i8x8_modes[xd->block[10].bmi.as_mode.first]++; + } #endif ++cpi->ymode_count[m]; @@ -1117,10 +1054,11 @@ int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) { int rate; - if (cpi->sf.RD && cpi->compressor_speed != 2) - vp8_rd_pick_intra_mode(cpi, x, &rate); - else - vp8_pick_intra_mode(cpi, x, &rate); + // Non rd path deprecated in test code base + //if (cpi->sf.RD && cpi->compressor_speed != 2) + vp8_rd_pick_intra_mode(cpi, x, &rate); + //else + // vp8_pick_intra_mode(cpi, x, &rate); if(cpi->oxcf.tuning == VP8_TUNE_SSIM) { @@ -1128,12 +1066,32 @@ int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) vp8_update_zbin_extra(cpi, x); } - if (x->e_mbd.mode_info_context->mbmi.mode == B_PRED) + /* test code: set transform size based on mode selection */ + if(cpi->common.txfm_mode == ALLOW_8X8 + && x->e_mbd.mode_info_context->mbmi.mode != I8X8_PRED + && x->e_mbd.mode_info_context->mbmi.mode != B_PRED) + { + x->e_mbd.mode_info_context->mbmi.txfm_size = TX_8X8; + cpi->t8x8_count++; + } + else + { + x->e_mbd.mode_info_context->mbmi.txfm_size = TX_4X4; + cpi->t4x4_count ++; + } + + if(x->e_mbd.mode_info_context->mbmi.mode == I8X8_PRED) + { + vp8_encode_intra8x8mby(IF_RTCD(&cpi->rtcd), x); + vp8_encode_intra8x8mbuv(IF_RTCD(&cpi->rtcd), x); + } + else if (x->e_mbd.mode_info_context->mbmi.mode == B_PRED) vp8_encode_intra4x4mby(IF_RTCD(&cpi->rtcd), x); else vp8_encode_intra16x16mby(IF_RTCD(&cpi->rtcd), x); - vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); + if(x->e_mbd.mode_info_context->mbmi.mode != I8X8_PRED) + vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); sum_intra_stats(cpi, x); vp8_tokenize_mb(cpi, &x->e_mbd, t); @@ -1151,21 +1109,27 @@ int vp8cx_encode_inter_macroblock int recon_yoffset, int recon_uvoffset ) { + VP8_COMMON *cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; int intra_error = 0; int rate; int distortion; + unsigned char *segment_id = &xd->mode_info_context->mbmi.segment_id; + int seg_ref_active; + unsigned char ref_pred_flag; x->skip = 0; if (xd->segmentation_enabled) - x->encode_breakout = cpi->segment_encode_breakout[xd->mode_info_context->mbmi.segment_id]; + x->encode_breakout = cpi->segment_encode_breakout[*segment_id]; else x->encode_breakout = cpi->oxcf.encode_breakout; - if (cpi->sf.RD) + //if (cpi->sf.RD) + // For now this codebase is limited to a single rd encode path { int zbin_mode_boost_enabled = cpi->zbin_mode_boost_enabled; + int single, compound, hybrid; /* Are we using the fast quantizer for the mode selection? */ if(cpi->sf.use_fastquant_for_pick) @@ -1180,7 +1144,39 @@ int vp8cx_encode_inter_macroblock cpi->zbin_mode_boost_enabled = 0; } vp8_rd_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, - &distortion, &intra_error); + &distortion, &intra_error, &single, &compound, &hybrid); + + cpi->rd_single_diff += single; + cpi->rd_comp_diff += compound; + cpi->rd_hybrid_diff += hybrid; + if (x->e_mbd.mode_info_context->mbmi.ref_frame && + x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) + { + unsigned char pred_context; + + pred_context = get_pred_context( cm, xd, PRED_COMP ); + + if (xd->mode_info_context->mbmi.second_ref_frame == INTRA_FRAME) + cpi->single_pred_count[pred_context]++; + else + cpi->comp_pred_count[pred_context]++; + } + + + /* test code: set transform size based on mode selection */ + if( cpi->common.txfm_mode == ALLOW_8X8 + && x->e_mbd.mode_info_context->mbmi.mode != I8X8_PRED + && x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) + { + x->e_mbd.mode_info_context->mbmi.txfm_size = TX_8X8; + cpi->t8x8_count ++; + } + else + { + x->e_mbd.mode_info_context->mbmi.txfm_size = TX_4X4; + cpi->t4x4_count++; + } /* switch back to the regular quantizer for the encode */ if (cpi->sf.improved_quant) @@ -1190,14 +1186,14 @@ int vp8cx_encode_inter_macroblock cpi->mb.quantize_b_pair = QUANTIZE_INVOKE(&cpi->rtcd.quantize, quantb_pair); } - /* restore cpi->zbin_mode_boost_enabled */ cpi->zbin_mode_boost_enabled = zbin_mode_boost_enabled; } - else - vp8_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, - &distortion, &intra_error); + //else + // The non rd encode path has been deleted from this code base + // to simplify development + // vp8_pick_inter_mode cpi->prediction_error += distortion; cpi->intra_error += intra_error; @@ -1208,30 +1204,6 @@ int vp8cx_encode_inter_macroblock adjust_act_zbin( cpi, x ); } -#if 0 - // Experimental RD code - cpi->frame_distortion += distortion; - cpi->last_mb_distortion = distortion; -#endif - - // MB level adjutment to quantizer setup - if (xd->segmentation_enabled) - { - // If cyclic update enabled - if (cpi->cyclic_refresh_mode_enabled) - { - // Clear segment_id back to 0 if not coded (last frame 0,0) - if ((xd->mode_info_context->mbmi.segment_id == 1) && - ((xd->mode_info_context->mbmi.ref_frame != LAST_FRAME) || (xd->mode_info_context->mbmi.mode != ZEROMV))) - { - xd->mode_info_context->mbmi.segment_id = 0; - - /* segment_id changed, so update */ - vp8cx_mb_init_quantizer(cpi, x); - } - } - } - { // Experimental code. Special case for gf and arf zeromv modes. // Increase zbin size to supress noise @@ -1260,21 +1232,56 @@ int vp8cx_encode_inter_macroblock vp8_update_zbin_extra(cpi, x); } - cpi->count_mb_ref_frame_usage[xd->mode_info_context->mbmi.ref_frame] ++; + seg_ref_active = segfeature_active( xd, *segment_id, SEG_LVL_REF_FRAME ); + + // SET VARIOUS PREDICTION FLAGS + + // Did the chosen reference frame match its predicted value. + ref_pred_flag = ( (xd->mode_info_context->mbmi.ref_frame == + get_pred_ref( cm, xd )) ); + set_pred_flag( xd, PRED_REF, ref_pred_flag ); + + // If we have just a single reference frame coded for a segment then + // exclude from the reference frame counts used to work out + // probabilities. NOTE: At the moment we dont support custom trees + // for the reference frame coding for each segment but this is a + // possible future action. + if ( !seg_ref_active || + ( ( check_segref( xd, *segment_id, INTRA_FRAME ) + + check_segref( xd, *segment_id, LAST_FRAME ) + + check_segref( xd, *segment_id, GOLDEN_FRAME ) + + check_segref( xd, *segment_id, ALTREF_FRAME ) ) > 1 ) ) + { +// TODO this may not be a good idea as it makes sample size small and means +// the predictor functions cannot use data about most likely value only most +// likely unpredicted value. +//#if CONFIG_COMPRED +// // Only update count for incorrectly predicted cases +// if ( !ref_pred_flag ) +//#endif + { + cpi->count_mb_ref_frame_usage + [xd->mode_info_context->mbmi.ref_frame]++; + } + } if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) { - vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); - if (xd->mode_info_context->mbmi.mode == B_PRED) { + vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); vp8_encode_intra4x4mby(IF_RTCD(&cpi->rtcd), x); } + else if(xd->mode_info_context->mbmi.mode == I8X8_PRED) + { + vp8_encode_intra8x8mby(IF_RTCD(&cpi->rtcd), x); + vp8_encode_intra8x8mbuv(IF_RTCD(&cpi->rtcd), x); + } else { + vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); vp8_encode_intra16x16mby(IF_RTCD(&cpi->rtcd), x); } - sum_intra_stats(cpi, x); } else @@ -1292,6 +1299,24 @@ int vp8cx_encode_inter_macroblock xd->pre.u_buffer = cpi->common.yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset; xd->pre.v_buffer = cpi->common.yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset; + if (xd->mode_info_context->mbmi.second_ref_frame) { + int second_ref_fb_idx; + + if (xd->mode_info_context->mbmi.second_ref_frame == LAST_FRAME) + second_ref_fb_idx = cpi->common.lst_fb_idx; + else if (xd->mode_info_context->mbmi.second_ref_frame == GOLDEN_FRAME) + second_ref_fb_idx = cpi->common.gld_fb_idx; + else + second_ref_fb_idx = cpi->common.alt_fb_idx; + + xd->second_pre.y_buffer = cpi->common.yv12_fb[second_ref_fb_idx].y_buffer + + recon_yoffset; + xd->second_pre.u_buffer = cpi->common.yv12_fb[second_ref_fb_idx].u_buffer + + recon_uvoffset; + xd->second_pre.v_buffer = cpi->common.yv12_fb[second_ref_fb_idx].v_buffer + + recon_uvoffset; + } + if (!x->skip) { vp8_encode_inter16x16(IF_RTCD(&cpi->rtcd), x); @@ -1302,14 +1327,40 @@ int vp8cx_encode_inter_macroblock } else + { vp8_build_inter16x16_predictors_mb(xd, xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, xd->dst.y_stride, xd->dst.uv_stride); - + } } if (!x->skip) + { +#ifdef ENC_DEBUG + if (enc_debug) + { + int i; + printf("Segment=%d [%d, %d]: %d %d:\n", x->e_mbd.mode_info_context->mbmi.segment_id, mb_col_debug, mb_row_debug, xd->mb_to_left_edge, xd->mb_to_top_edge); + for (i =0; i<400; i++) { + printf("%3d ", xd->qcoeff[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + printf("eobs = "); + for (i=0;i<25;i++) + printf("%d:%d ", i, xd->block[i].eob); + printf("\n"); + fflush(stdout); + } +#endif vp8_tokenize_mb(cpi, xd, t); +#ifdef ENC_DEBUG + if (enc_debug) { + printf("Tokenized\n"); + fflush(stdout); + } +#endif + } else { if (cpi->common.mb_no_coeff_skip) @@ -1325,6 +1376,5 @@ int vp8cx_encode_inter_macroblock cpi->skip_false_count ++; } } - return rate; } diff --git a/vp8/encoder/encodeintra.c b/vp8/encoder/encodeintra.c index 4a77c1ff3..f34de6f75 100644 --- a/vp8/encoder/encodeintra.c +++ b/vp8/encoder/encodeintra.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/idct.h" #include "quantize.h" #include "vp8/common/reconintra.h" @@ -22,22 +22,29 @@ #include "encodeintra.h" +#ifdef ENC_DEBUG +extern int enc_debug; +#endif + #if CONFIG_RUNTIME_CPU_DETECT #define IF_RTCD(x) (x) #else #define IF_RTCD(x) NULL #endif -int vp8_encode_intra(VP8_COMP *cpi, MACROBLOCK *x, int use_dc_pred) +int vp8_encode_intra(VP8_COMP *cpi, MACROBLOCK *x, int use_16x16_pred) { int i; int intra_pred_var = 0; (void) cpi; - if (use_dc_pred) + if (use_16x16_pred) { x->e_mbd.mode_info_context->mbmi.mode = DC_PRED; +#if CONFIG_COMP_INTRA_PRED + x->e_mbd.mode_info_context->mbmi.second_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); +#endif x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; @@ -47,7 +54,7 @@ int vp8_encode_intra(VP8_COMP *cpi, MACROBLOCK *x, int use_dc_pred) { for (i = 0; i < 16; i++) { - x->e_mbd.block[i].bmi.as_mode = B_DC_PRED; + x->e_mbd.block[i].bmi.as_mode.first = B_DC_PRED; vp8_encode_intra4x4block(IF_RTCD(&cpi->rtcd), x, i); } } @@ -63,8 +70,20 @@ void vp8_encode_intra4x4block(const VP8_ENCODER_RTCD *rtcd, BLOCKD *b = &x->e_mbd.block[ib]; BLOCK *be = &x->block[ib]; +#if CONFIG_COMP_INTRA_PRED + if (b->bmi.as_mode.second == (B_PREDICTION_MODE) (B_DC_PRED - 1)) + { +#endif RECON_INVOKE(&rtcd->common->recon, intra4x4_predict) - (b, b->bmi.as_mode, b->predictor); + (b, b->bmi.as_mode.first, b->predictor); +#if CONFIG_COMP_INTRA_PRED + } + else + { + RECON_INVOKE(&rtcd->common->recon, comp_intra4x4_predict) + (b, b->bmi.as_mode.first, b->bmi.as_mode.second, b->predictor); + } +#endif ENCODEMB_INVOKE(&rtcd->encodemb, subb)(be, b, 16); @@ -93,18 +112,72 @@ void vp8_encode_intra16x16mby(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) { BLOCK *b = &x->block[0]; + int tx_type = x->e_mbd.mode_info_context->mbmi.txfm_size; + +#if CONFIG_COMP_INTRA_PRED + if (x->e_mbd.mode_info_context->mbmi.second_mode == (MB_PREDICTION_MODE) (DC_PRED - 1)) +#endif RECON_INVOKE(&rtcd->common->recon, build_intra_predictors_mby)(&x->e_mbd); +#if CONFIG_COMP_INTRA_PRED + else + RECON_INVOKE(&rtcd->common->recon, build_comp_intra_predictors_mby)(&x->e_mbd); +#endif ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, *(b->base_src), x->e_mbd.predictor, b->src_stride); - vp8_transform_intra_mby(x); + if( tx_type == TX_8X8 ) + vp8_transform_intra_mby_8x8(x); + else + vp8_transform_intra_mby(x); - vp8_quantize_mby(x); + if(tx_type == TX_8X8) + vp8_quantize_mby_8x8(x); + else + vp8_quantize_mby(x); if (x->optimize) + { + if( tx_type == TX_8X8 ) + vp8_optimize_mby_8x8(x, rtcd); + else vp8_optimize_mby(x, rtcd); + } - vp8_inverse_transform_mby(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + if(tx_type == TX_8X8) + vp8_inverse_transform_mby_8x8(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + else + vp8_inverse_transform_mby(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + +#ifdef ENC_DEBUG + if (enc_debug) { + int i; + printf("Intra qcoeff:\n"); + printf("%d %d:\n", x->e_mbd.mb_to_left_edge, x->e_mbd.mb_to_top_edge); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.qcoeff[i]); + if (i%16 == 15) printf("\n"); + } + printf("Intra dqcoeff:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.dqcoeff[i]); + if (i%16 == 15) printf("\n"); + } + printf("Intra diff:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.diff[i]); + if (i%16 == 15) printf("\n"); + } + printf("Intra predictor:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.predictor[i]); + if (i%16 == 15) printf("\n"); + } + printf("eobs:\n"); + for (i=0;i<25;i++) + printf("%d ", x->e_mbd.block[i].eob); + printf("\n"); + } +#endif RECON_INVOKE(&rtcd->common->recon, recon_mby) (IF_RTCD(&rtcd->common->recon), &x->e_mbd); @@ -113,18 +186,181 @@ void vp8_encode_intra16x16mby(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) void vp8_encode_intra16x16mbuv(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) { + int tx_type = x->e_mbd.mode_info_context->mbmi.txfm_size; +#if CONFIG_COMP_INTRA_PRED + if (x->e_mbd.mode_info_context->mbmi.second_uv_mode == (MB_PREDICTION_MODE) (DC_PRED - 1)) + { +#endif RECON_INVOKE(&rtcd->common->recon, build_intra_predictors_mbuv)(&x->e_mbd); +#if CONFIG_COMP_INTRA_PRED + } + else + { + RECON_INVOKE(&rtcd->common->recon, build_comp_intra_predictors_mbuv)(&x->e_mbd); + } +#endif ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); + if(tx_type == TX_8X8) + vp8_transform_mbuv_8x8(x); + else + vp8_transform_mbuv(x); - vp8_transform_mbuv(x); - - vp8_quantize_mbuv(x); + if(tx_type == TX_8X8) + vp8_quantize_mbuv_8x8(x); + else + vp8_quantize_mbuv(x); +#ifdef ENC_DEBUG + if (enc_debug) { + int i; + printf("vp8_encode_intra16x16mbuv\n"); + printf("%d %d:\n", x->e_mbd.mb_to_left_edge, x->e_mbd.mb_to_top_edge); + printf("qcoeff:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.qcoeff[i]); + if (i%16 == 15) printf("\n"); + } + printf("dqcoeff:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.dqcoeff[i]); + if (i%16 == 15) printf("\n"); + } + printf("diff:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.diff[i]); + if (i%16 == 15) printf("\n"); + } + printf("predictor:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.predictor[i]); + if (i%16 == 15) printf("\n"); + } + printf("eobs:\n"); + for (i=0;i<25;i++) + printf("%d ", x->e_mbd.block[i].eob); + printf("\n"); + } +#endif if (x->optimize) + { + if(tx_type == TX_8X8) + vp8_optimize_mbuv_8x8(x, rtcd); + else vp8_optimize_mbuv(x, rtcd); + } - vp8_inverse_transform_mbuv(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + if(tx_type == TX_8X8) + vp8_inverse_transform_mbuv_8x8(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + else + vp8_inverse_transform_mbuv(IF_RTCD(&rtcd->common->idct), &x->e_mbd); vp8_recon_intra_mbuv(IF_RTCD(&rtcd->common->recon), &x->e_mbd); } + +void vp8_encode_intra8x8(const VP8_ENCODER_RTCD *rtcd, + MACROBLOCK *x, int ib) +{ + BLOCKD *b = &x->e_mbd.block[ib]; + BLOCK *be = &x->block[ib]; + const int iblock[4]={0,1,4,5}; + int i; + +#if CONFIG_COMP_INTRA_PRED + if (b->bmi.as_mode.second == (MB_PREDICTION_MODE) (DC_PRED - 1)) + { +#endif + RECON_INVOKE(&rtcd->common->recon, intra8x8_predict) + (b, b->bmi.as_mode.first, b->predictor); +#if CONFIG_COMP_INTRA_PRED + } + else + { + RECON_INVOKE(&rtcd->common->recon, comp_intra8x8_predict) + (b, b->bmi.as_mode.first, b->bmi.as_mode.second, b->predictor); + } +#endif + + for(i=0;i<4;i++) + { + b = &x->e_mbd.block[ib + iblock[i]]; + be = &x->block[ib + iblock[i]]; + ENCODEMB_INVOKE(&rtcd->encodemb, subb)(be, b, 16); + x->vp8_short_fdct4x4(be->src_diff, be->coeff, 32); + x->quantize_b(be, b); + vp8_inverse_transform_b(IF_RTCD(&rtcd->common->idct), b, 32); + RECON_INVOKE(&rtcd->common->recon, recon)(b->predictor, + b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } + +} + +extern const int vp8_i8x8_block[4]; +void vp8_encode_intra8x8mby(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + int i, ib; + + for(i=0;i<4;i++) + { + ib = vp8_i8x8_block[i]; + vp8_encode_intra8x8(rtcd, x, ib); + } + +} + +void vp8_encode_intra_uv4x4(const VP8_ENCODER_RTCD *rtcd, + MACROBLOCK *x, int ib, + int mode, int second) +{ + BLOCKD *b = &x->e_mbd.block[ib]; + BLOCK *be = &x->block[ib]; + +#if CONFIG_COMP_INTRA_PRED + if (second == -1) + { +#endif + RECON_INVOKE(&rtcd->common->recon, intra_uv4x4_predict) + (b, mode, b->predictor); +#if CONFIG_COMP_INTRA_PRED + } + else + { + RECON_INVOKE(&rtcd->common->recon, comp_intra_uv4x4_predict) + (b, mode, second, b->predictor); + } +#endif + + ENCODEMB_INVOKE(&rtcd->encodemb, subb)(be, b, 8); + + x->vp8_short_fdct4x4(be->src_diff, be->coeff, 16); + + x->quantize_b(be, b); + + vp8_inverse_transform_b(IF_RTCD(&rtcd->common->idct), b, 16); + + RECON_INVOKE(&rtcd->common->recon, recon_uv)(b->predictor, + b->diff, *(b->base_dst) + b->dst, b->dst_stride); +} + + + +void vp8_encode_intra8x8mbuv(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + int i, ib, mode, second; + BLOCKD *b; + for(i=0;i<4;i++) + { + ib = vp8_i8x8_block[i]; + b = &x->e_mbd.block[ib]; + mode = b->bmi.as_mode.first; +#if CONFIG_COMP_INTRA_PRED + second = b->bmi.as_mode.second; +#else + second = -1; +#endif + /*u */ + vp8_encode_intra_uv4x4(rtcd, x, i+16, mode, second); + /*v */ + vp8_encode_intra_uv4x4(rtcd, x, i+20, mode, second); + } +} diff --git a/vp8/encoder/encodeintra.h b/vp8/encoder/encodeintra.h index 9c1fa5684..ae822d3d9 100644 --- a/vp8/encoder/encodeintra.h +++ b/vp8/encoder/encodeintra.h @@ -13,10 +13,15 @@ #define _ENCODEINTRA_H_ #include "onyx_int.h" -int vp8_encode_intra(VP8_COMP *cpi, MACROBLOCK *x, int use_dc_pred); +int vp8_encode_intra(VP8_COMP *cpi, MACROBLOCK *x, int use_16x16_pred); void vp8_encode_intra16x16mby(const VP8_ENCODER_RTCD *, MACROBLOCK *x); void vp8_encode_intra16x16mbuv(const VP8_ENCODER_RTCD *, MACROBLOCK *x); void vp8_encode_intra4x4mby(const VP8_ENCODER_RTCD *, MACROBLOCK *mb); void vp8_encode_intra4x4block(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x, int ib); +void vp8_encode_intra8x8mby(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x); +void vp8_encode_intra8x8mbuv(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x); +void vp8_encode_intra8x8(const VP8_ENCODER_RTCD *rtcd, + MACROBLOCK *x, int ib); + #endif diff --git a/vp8/encoder/encodemb.c b/vp8/encoder/encodemb.c index 68005ad60..ab0f1c13e 100644 --- a/vp8/encoder/encodemb.c +++ b/vp8/encoder/encodemb.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "encodemb.h" #include "vp8/common/reconinter.h" #include "quantize.h" @@ -20,12 +20,18 @@ #include "dct.h" #include "vpx_mem/vpx_mem.h" #include "rdopt.h" +#include "vp8/common/systemdependent.h" #if CONFIG_RUNTIME_CPU_DETECT #define IF_RTCD(x) (x) #else #define IF_RTCD(x) NULL #endif + +#ifdef ENC_DEBUG +extern int enc_debug; +#endif + void vp8_subtract_b_c(BLOCK *be, BLOCKD *bd, int pitch) { unsigned char *src_ptr = (*(be->base_src) + be->src); @@ -48,6 +54,25 @@ void vp8_subtract_b_c(BLOCK *be, BLOCKD *bd, int pitch) } } +void vp8_subtract_4b_c(BLOCK *be, BLOCKD *bd, int pitch) +{ + unsigned char *src_ptr = (*(be->base_src) + be->src); + short *diff_ptr = be->src_diff; + unsigned char *pred_ptr = bd->predictor; + int src_stride = be->src_stride; + int r, c; + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + diff_ptr[c] = src_ptr[c] - pred_ptr[c]; + } + diff_ptr += pitch; + pred_ptr += pitch; + src_ptr += src_stride; + } +} + void vp8_subtract_mbuv_c(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride) { short *udiff = diff + 256; @@ -117,6 +142,19 @@ static void build_dcblock(MACROBLOCK *x) src_diff_ptr[i] = x->coeff[i * 16]; } } +void vp8_build_dcblock_8x8(MACROBLOCK *x) +{ + short *src_diff_ptr = &x->src_diff[384]; + int i; + for (i = 0; i < 16; i++) + { + src_diff_ptr[i] = 0; + } + src_diff_ptr[0] = x->coeff[0 * 16]; + src_diff_ptr[1] = x->coeff[4 * 16]; + src_diff_ptr[4] = x->coeff[8 * 16]; + src_diff_ptr[8] = x->coeff[12 * 16]; +} void vp8_transform_mbuv(MACROBLOCK *x) { @@ -197,10 +235,109 @@ static void transform_mby(MACROBLOCK *x) } } +void vp8_transform_mbuv_8x8(MACROBLOCK *x) +{ + int i; + + vp8_clear_system_state(); + + for (i = 16; i < 24; i += 4) + { + x->vp8_short_fdct8x8(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 16); + } +} + + +void vp8_transform_intra_mby_8x8(MACROBLOCK *x)//changed +{ + int i; + + vp8_clear_system_state(); + + for (i = 0; i < 9; i += 8) + { + x->vp8_short_fdct8x8(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 32); + } + for (i = 2; i < 11; i += 8) + { + x->vp8_short_fdct8x8(&x->block[i].src_diff[0], + &x->block[i+2].coeff[0], 32); + } + // build dc block from 16 y dc values + vp8_build_dcblock_8x8(x); + //vp8_build_dcblock(x); + + // do 2nd order transform on the dc block + x->short_fhaar2x2(&x->block[24].src_diff[0], + &x->block[24].coeff[0], 8); + +} + + +void vp8_transform_mb_8x8(MACROBLOCK *x) +{ + int i; + + vp8_clear_system_state(); + + for (i = 0; i < 9; i += 8) + { + x->vp8_short_fdct8x8(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 32); + } + for (i = 2; i < 11; i += 8) + { + x->vp8_short_fdct8x8(&x->block[i].src_diff[0], + &x->block[i+2].coeff[0], 32); + } + // build dc block from 16 y dc values + if (x->e_mbd.mode_info_context->mbmi.mode != B_PRED &&x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) + vp8_build_dcblock_8x8(x); + //vp8_build_dcblock(x); + + for (i = 16; i < 24; i += 4) + { + x->vp8_short_fdct8x8(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 16); + } + + // do 2nd order transform on the dc block + if (x->e_mbd.mode_info_context->mbmi.mode != B_PRED &&x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) + x->short_fhaar2x2(&x->block[24].src_diff[0], + &x->block[24].coeff[0], 8); +} + +void vp8_transform_mby_8x8(MACROBLOCK *x) +{ + int i; + + vp8_clear_system_state(); + + for (i = 0; i < 9; i += 8) + { + x->vp8_short_fdct8x8(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 32); + } + for (i = 2; i < 11; i += 8) + { + x->vp8_short_fdct8x8(&x->block[i].src_diff[0], + &x->block[i+2].coeff[0], 32); + } + // build dc block from 16 y dc values + if (x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) + { + //vp8_build_dcblock(x); + vp8_build_dcblock_8x8(x); + x->short_fhaar2x2(&x->block[24].src_diff[0], + &x->block[24].coeff[0], 8); + } +} #define RDTRUNC(RM,DM,R,D) ( (128+(R)*(RM)) & 0xFF ) - +#define RDTRUNC_8x8(RM,DM,R,D) ( (128+(R)*(RM)) & 0xFF ) typedef struct vp8_token_state vp8_token_state; struct vp8_token_state{ @@ -214,11 +351,7 @@ struct vp8_token_state{ // TODO: experiments to find optimal multiple numbers #define Y1_RD_MULT 4 #define UV_RD_MULT 2 -#if !CONFIG_EXTEND_QRANGE -#define Y2_RD_MULT 16 -#else #define Y2_RD_MULT 4 -#endif static const int plane_rd_mult[4]= { @@ -474,6 +607,80 @@ static void optimize_b(MACROBLOCK *mb, int ib, int type, *a = *l = (d->eob != !type); } + /************************************************************************** + our inverse hadamard transform effectively is weighted sum of all 16 inputs + with weight either 1 or -1. It has a last stage scaling of (sum+1)>>2. And + dc only idct is (dc+16)>>5. So if all the sums are between -65 and 63 the + output after inverse wht and idct will be all zero. A sum of absolute value + smaller than 65 guarantees all 16 different (+1/-1) weighted sums in wht + fall between -65 and +65. + **************************************************************************/ +#define SUM_2ND_COEFF_THRESH 65 + +static void check_reset_2nd_coeffs(MACROBLOCKD *x, int type, + ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + int sum=0; + int i; + BLOCKD *bd = &x->block[24]; + if(bd->dequant[0]>=SUM_2ND_COEFF_THRESH + && bd->dequant[1]>=SUM_2ND_COEFF_THRESH) + return; + + for(i=0;ieob;i++) + { + int coef = bd->dqcoeff[vp8_default_zig_zag1d[i]]; + sum+= (coef>=0)?coef:-coef; + if(sum>=SUM_2ND_COEFF_THRESH) + return; + } + + if(sum < SUM_2ND_COEFF_THRESH) + { + for(i=0;ieob;i++) + { + int rc = vp8_default_zig_zag1d[i]; + bd->qcoeff[rc]=0; + bd->dqcoeff[rc]=0; + } + bd->eob = 0; + *a = *l = (bd->eob != !type); + } +} +#define SUM_2ND_COEFF_THRESH_8X8 32 +static void check_reset_8x8_2nd_coeffs(MACROBLOCKD *x, int type, + ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + int sum=0; + BLOCKD *bd = &x->block[24]; + int coef; + + coef = bd->dqcoeff[0]; + sum+= (coef>=0)?coef:-coef; + coef = bd->dqcoeff[1]; + sum+= (coef>=0)?coef:-coef; + coef = bd->dqcoeff[4]; + sum+= (coef>=0)?coef:-coef; + coef = bd->dqcoeff[8]; + sum+= (coef>=0)?coef:-coef; + + if(sum < SUM_2ND_COEFF_THRESH_8X8) + { + bd->qcoeff[0] = 0; + bd->dqcoeff[0] = 0; + bd->qcoeff[1] = 0; + bd->dqcoeff[1] = 0; + bd->qcoeff[4] = 0; + bd->dqcoeff[4] = 0; + bd->qcoeff[8] = 0; + bd->dqcoeff[8] = 0; + bd->eob = 0; + *a = *l = (bd->eob != !type); + } +} + + + static void optimize_mb(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) { int b; @@ -490,6 +697,7 @@ static void optimize_mb(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) tl = (ENTROPY_CONTEXT *)&t_left; has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED + &&x->e_mbd.mode_info_context->mbmi.mode != I8X8_PRED && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); type = has_2nd_order ? PLANE_TYPE_Y_NO_DC : PLANE_TYPE_Y_WITH_DC; @@ -510,6 +718,8 @@ static void optimize_mb(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) b=24; optimize_b(x, b, PLANE_TYPE_Y2, ta + vp8_block2above[b], tl + vp8_block2left[b], rtcd); + check_reset_2nd_coeffs(&x->e_mbd, PLANE_TYPE_Y2, + ta + vp8_block2above[b], tl + vp8_block2left[b]); } } @@ -537,6 +747,7 @@ void vp8_optimize_mby(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) tl = (ENTROPY_CONTEXT *)&t_left; has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED + &&x->e_mbd.mode_info_context->mbmi.mode != I8X8_PRED && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); type = has_2nd_order ? PLANE_TYPE_Y_NO_DC : PLANE_TYPE_Y_WITH_DC; @@ -552,6 +763,8 @@ void vp8_optimize_mby(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) b=24; optimize_b(x, b, PLANE_TYPE_Y2, ta + vp8_block2above[b], tl + vp8_block2left[b], rtcd); + check_reset_2nd_coeffs(&x->e_mbd, PLANE_TYPE_Y2, + ta + vp8_block2above[b], tl + vp8_block2left[b]); } } @@ -581,40 +794,463 @@ void vp8_optimize_mbuv(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) } } +void optimize_b_8x8(MACROBLOCK *mb, int i, int type, + ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, + const VP8_ENCODER_RTCD *rtcd) +{ + BLOCK *b; + BLOCKD *d; + vp8_token_state tokens[65][2]; + unsigned best_mask[2]; + const short *dequant_ptr; + const short *coeff_ptr; + short *qcoeff_ptr; + short *dqcoeff_ptr; + int eob; + int i0; + int rc; + int x; + int sz = 0; + int next; + int rdmult; + int rddiv; + int final_eob; + int rd_cost0; + int rd_cost1; + int rate0; + int rate1; + int error0; + int error1; + int t0; + int t1; + int best; + int band; + int pt; + int err_mult = plane_rd_mult[type]; + + b = &mb->block[i]; + d = &mb->e_mbd.block[i]; + + /* Enable this to test the effect of RDO as a replacement for the dynamic + * zero bin instead of an augmentation of it. + */ +#if 0 + vp8_strict_quantize_b(b, d); +#endif + + dequant_ptr = d->dequant; + coeff_ptr = b->coeff; + qcoeff_ptr = d->qcoeff; + dqcoeff_ptr = d->dqcoeff; + i0 = !type; + eob = d->eob; + + /* Now set up a Viterbi trellis to evaluate alternative roundings. */ + rdmult = mb->rdmult * err_mult; + if(mb->e_mbd.mode_info_context->mbmi.ref_frame==INTRA_FRAME) + rdmult = (rdmult * 9)>>4; + rddiv = mb->rddiv; + best_mask[0] = best_mask[1] = 0; + /* Initialize the sentinel node of the trellis. */ + tokens[eob][0].rate = 0; + tokens[eob][0].error = 0; + tokens[eob][0].next = 64; + tokens[eob][0].token = DCT_EOB_TOKEN; + tokens[eob][0].qc = 0; + *(tokens[eob] + 1) = *(tokens[eob] + 0); + next = eob; + for (i = eob; i-- > i0;) + { + int base_bits; + int d2; + int dx; + + rc = vp8_default_zig_zag1d_8x8[i]; + x = qcoeff_ptr[rc]; + /* Only add a trellis state for non-zero coefficients. */ + if (x) + { + int shortcut=0; + error0 = tokens[next][0].error; + error1 = tokens[next][1].error; + /* Evaluate the first possibility for this state. */ + rate0 = tokens[next][0].rate; + rate1 = tokens[next][1].rate; + t0 = (vp8_dct_value_tokens_ptr + x)->Token; + /* Consider both possible successor states. */ + if (next < 64) + { + band = vp8_coef_bands_8x8[i + 1]; + pt = vp8_prev_token_class[t0]; + rate0 += + mb->token_costs_8x8[type][band][pt][tokens[next][0].token]; + rate1 += + mb->token_costs_8x8[type][band][pt][tokens[next][1].token]; + } + rd_cost0 = RDCOST_8x8(rdmult, rddiv, rate0, error0); + rd_cost1 = RDCOST_8x8(rdmult, rddiv, rate1, error1); + if (rd_cost0 == rd_cost1) + { + rd_cost0 = RDTRUNC_8x8(rdmult, rddiv, rate0, error0); + rd_cost1 = RDTRUNC_8x8(rdmult, rddiv, rate1, error1); + } + /* And pick the best. */ + best = rd_cost1 < rd_cost0; + base_bits = *(vp8_dct_value_cost_ptr + x); + dx = dqcoeff_ptr[rc] - coeff_ptr[rc]; + d2 = dx*dx; + tokens[i][0].rate = base_bits + (best ? rate1 : rate0); + tokens[i][0].error = d2 + (best ? error1 : error0); + tokens[i][0].next = next; + tokens[i][0].token = t0; + tokens[i][0].qc = x; + best_mask[0] |= best << i; + /* Evaluate the second possibility for this state. */ + rate0 = tokens[next][0].rate; + rate1 = tokens[next][1].rate; + + if((abs(x)*dequant_ptr[rc!=0]>abs(coeff_ptr[rc])) && + (abs(x)*dequant_ptr[rc!=0]Token; + } + if (next < 64) + { + band = vp8_coef_bands_8x8[i + 1]; + if(t0!=DCT_EOB_TOKEN) + { + pt = vp8_prev_token_class[t0]; + rate0 += mb->token_costs_8x8[type][band][pt][ + tokens[next][0].token]; + } + if(t1!=DCT_EOB_TOKEN) + { + pt = vp8_prev_token_class[t1]; + rate1 += mb->token_costs_8x8[type][band][pt][ + tokens[next][1].token]; + } + } + + rd_cost0 = RDCOST_8x8(rdmult, rddiv, rate0, error0); + rd_cost1 = RDCOST_8x8(rdmult, rddiv, rate1, error1); + if (rd_cost0 == rd_cost1) + { + rd_cost0 = RDTRUNC_8x8(rdmult, rddiv, rate0, error0); + rd_cost1 = RDTRUNC_8x8(rdmult, rddiv, rate1, error1); + } + /* And pick the best. */ + best = rd_cost1 < rd_cost0; + base_bits = *(vp8_dct_value_cost_ptr + x); + + if(shortcut) + { + dx -= (dequant_ptr[rc!=0] + sz) ^ sz; + d2 = dx*dx; + } + tokens[i][1].rate = base_bits + (best ? rate1 : rate0); + tokens[i][1].error = d2 + (best ? error1 : error0); + tokens[i][1].next = next; + tokens[i][1].token =best?t1:t0; + tokens[i][1].qc = x; + best_mask[1] |= best << i; + /* Finally, make this the new head of the trellis. */ + next = i; + } + /* There's no choice to make for a zero coefficient, so we don't + * add a new trellis node, but we do need to update the costs. + */ + else + { + band = vp8_coef_bands_8x8[i + 1]; + t0 = tokens[next][0].token; + t1 = tokens[next][1].token; + /* Update the cost of each path if we're past the EOB token. */ + if (t0 != DCT_EOB_TOKEN) + { + tokens[next][0].rate += mb->token_costs_8x8[type][band][0][t0]; + tokens[next][0].token = ZERO_TOKEN; + } + if (t1 != DCT_EOB_TOKEN) + { + tokens[next][1].rate += mb->token_costs_8x8[type][band][0][t1]; + tokens[next][1].token = ZERO_TOKEN; + } + /* Don't update next, because we didn't add a new node. */ + } + } + + /* Now pick the best path through the whole trellis. */ + band = vp8_coef_bands_8x8[i + 1]; + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + rate0 = tokens[next][0].rate; + rate1 = tokens[next][1].rate; + error0 = tokens[next][0].error; + error1 = tokens[next][1].error; + t0 = tokens[next][0].token; + t1 = tokens[next][1].token; + rate0 += mb->token_costs_8x8[type][band][pt][t0]; + rate1 += mb->token_costs_8x8[type][band][pt][t1]; + rd_cost0 = RDCOST_8x8(rdmult, rddiv, rate0, error0); + rd_cost1 = RDCOST_8x8(rdmult, rddiv, rate1, error1); + if (rd_cost0 == rd_cost1) + { + rd_cost0 = RDTRUNC_8x8(rdmult, rddiv, rate0, error0); + rd_cost1 = RDTRUNC_8x8(rdmult, rddiv, rate1, error1); + } + best = rd_cost1 < rd_cost0; + final_eob = i0 - 1; + for (i = next; i < eob; i = next) + { + x = tokens[i][best].qc; + if (x) + final_eob = i; + rc = vp8_default_zig_zag1d_8x8[i]; + qcoeff_ptr[rc] = x; + dqcoeff_ptr[rc] = (x * dequant_ptr[rc!=0]); + + next = tokens[i][best].next; + best = (best_mask[best] >> i) & 1; + } + final_eob++; + + d->eob = final_eob; + *a = *l = (d->eob != !type); + +} + +void optimize_mb_8x8(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) +{ + int b; + int type; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + vpx_memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + type = 0; + for (b = 0; b < 16; b+=4) + { + optimize_b_8x8(x, b, type, + ta + vp8_block2above_8x8[b], tl + vp8_block2left_8x8[b], + rtcd); + *(ta + vp8_block2above_8x8[b] + 1) = *(ta + vp8_block2above_8x8[b]); + *(tl + vp8_block2left_8x8[b] + 1) = *(tl + vp8_block2left_8x8[b] ); + } + + for (b = 16; b < 24; b+=4) + { + optimize_b_8x8(x, b, PLANE_TYPE_UV, + ta + vp8_block2above_8x8[b], tl + vp8_block2left_8x8[b], + rtcd); + *(ta + vp8_block2above_8x8[b]+1) = *(ta + vp8_block2above_8x8[b]); + *(tl + vp8_block2left_8x8[b]+1 ) = *(tl + vp8_block2left_8x8[b]); + } + + //8x8 always have 2nd roder haar block + check_reset_8x8_2nd_coeffs(&x->e_mbd, PLANE_TYPE_Y2, + ta + vp8_block2above_8x8[24], tl + vp8_block2left_8x8[24]); + +} + +void vp8_optimize_mby_8x8(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) +{ + int b; + int type; + int has_2nd_order; + + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + + if (!x->e_mbd.above_context) + return; + + if (!x->e_mbd.left_context) + return; + + vpx_memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + type = 0; + for (b = 0; b < 16; b+=4) + { + optimize_b_8x8(x, b, type, + ta + vp8_block2above[b], tl + vp8_block2left[b], + rtcd); + *(ta + vp8_block2above_8x8[b] + 1) = *(ta + vp8_block2above_8x8[b]); + *(tl + vp8_block2left_8x8[b] + 1) = *(tl + vp8_block2left_8x8[b] ); + } + //8x8 always have 2nd roder haar block + check_reset_8x8_2nd_coeffs(&x->e_mbd, PLANE_TYPE_Y2, + ta + vp8_block2above_8x8[24], tl + vp8_block2left_8x8[24]); + +} + +void vp8_optimize_mbuv_8x8(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) +{ + int b; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + if (!x->e_mbd.above_context) + return; + + if (!x->e_mbd.left_context) + return; + + vpx_memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + for (b = 16; b < 24; b+=4) + { + optimize_b_8x8(x, b, PLANE_TYPE_UV, + ta + vp8_block2above_8x8[b], tl + vp8_block2left_8x8[b], + rtcd); + *(ta + vp8_block2above_8x8[b]+1) = *(ta + vp8_block2above_8x8[b]); + *(tl + vp8_block2left_8x8[b]+1 ) = *(tl + vp8_block2left_8x8[b]); + } + +} + void vp8_encode_inter16x16(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) { + int tx_type = x->e_mbd.mode_info_context->mbmi.txfm_size; vp8_build_inter_predictors_mb(&x->e_mbd); vp8_subtract_mb(rtcd, x); - transform_mb(x); + if( tx_type == TX_8X8 ) + vp8_transform_mb_8x8(x); + else + transform_mb(x); - vp8_quantize_mb(x); + if( tx_type == TX_8X8 ) + vp8_quantize_mb_8x8(x); + else + vp8_quantize_mb(x); if (x->optimize) + { + if( tx_type == TX_8X8 ) + optimize_mb_8x8(x, rtcd); + else optimize_mb(x, rtcd); + } - vp8_inverse_transform_mb(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + if( tx_type == TX_8X8 ) + vp8_inverse_transform_mb_8x8(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + else + vp8_inverse_transform_mb(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + + if( tx_type == TX_8X8 ) + { +#ifdef ENC_DEBUG + if (enc_debug) + { + int i; + printf("qcoeff:\n"); + printf("%d %d:\n", x->e_mbd.mb_to_left_edge, x->e_mbd.mb_to_top_edge); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.qcoeff[i]); + if (i%16 == 15) printf("\n"); + } + printf("dqcoeff:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.dqcoeff[i]); + if (i%16 == 15) printf("\n"); + } + printf("diff:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.diff[i]); + if (i%16 == 15) printf("\n"); + } + printf("predictor:\n"); + for (i =0; i<400; i++) { + printf("%3d ", x->e_mbd.predictor[i]); + if (i%16 == 15) printf("\n"); + } + printf("\n"); + } +#endif + } RECON_INVOKE(&rtcd->common->recon, recon_mb) (IF_RTCD(&rtcd->common->recon), &x->e_mbd); +#ifdef ENC_DEBUG + if (enc_debug) { + int i, j, k; + printf("Final Reconstruction\n"); + for (i =0; i<16; i+=4) { + BLOCKD *b = &x->e_mbd.block[i]; + unsigned char *d = *(b->base_dst) + b->dst; + for (k=0; k<4; k++) { + for (j=0; j<16; j++) + printf("%3d ", d[j]); + printf("\n"); + d+=b->dst_stride; + } + } + } +#endif } -/* this funciton is used by first pass only */ +/* this function is used by first pass only */ void vp8_encode_inter16x16y(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) { + int tx_type = x->e_mbd.mode_info_context->mbmi.txfm_size; + BLOCK *b = &x->block[0]; vp8_build_inter16x16_predictors_mby(&x->e_mbd); ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, *(b->base_src), x->e_mbd.predictor, b->src_stride); - transform_mby(x); + if( tx_type == TX_8X8 ) + vp8_transform_mby_8x8(x); + else + transform_mby(x); vp8_quantize_mby(x); - vp8_inverse_transform_mby(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + if( tx_type == TX_8X8 ) + vp8_inverse_transform_mby_8x8(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + else + vp8_inverse_transform_mby(IF_RTCD(&rtcd->common->idct), &x->e_mbd); RECON_INVOKE(&rtcd->common->recon, recon_mby) (IF_RTCD(&rtcd->common->recon), &x->e_mbd); diff --git a/vp8/encoder/encodemb.h b/vp8/encoder/encodemb.h index 8fa457aa8..e211eea65 100644 --- a/vp8/encoder/encodemb.h +++ b/vp8/encoder/encodemb.h @@ -12,7 +12,7 @@ #ifndef __INC_ENCODEMB_H #define __INC_ENCODEMB_H -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "block.h" #define prototype_mberr(sym) \ @@ -103,4 +103,15 @@ void vp8_transform_intra_mby(MACROBLOCK *x); void vp8_optimize_mby(MACROBLOCK *x, const struct VP8_ENCODER_RTCD *rtcd); void vp8_optimize_mbuv(MACROBLOCK *x, const struct VP8_ENCODER_RTCD *rtcd); void vp8_encode_inter16x16y(const struct VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x); + +void vp8_transform_mb_8x8(MACROBLOCK *mb); +void vp8_transform_mby_8x8(MACROBLOCK *x); +void vp8_transform_mbuv_8x8(MACROBLOCK *x); +void vp8_transform_intra_mby_8x8(MACROBLOCK *x); +void vp8_build_dcblock_8x8(MACROBLOCK *b); +void vp8_optimize_mby_8x8(MACROBLOCK *x, const struct VP8_ENCODER_RTCD *rtcd); +void vp8_optimize_mbuv_8x8(MACROBLOCK *x, const struct VP8_ENCODER_RTCD *rtcd); + +void vp8_subtract_4b_c(BLOCK *be, BLOCKD *bd, int pitch); + #endif diff --git a/vp8/encoder/encodemv.c b/vp8/encoder/encodemv.c index a4849c654..0ba8848a0 100644 --- a/vp8/encoder/encodemv.c +++ b/vp8/encoder/encodemv.c @@ -20,6 +20,11 @@ extern unsigned int active_section; #endif +//#define DEBUG_ENC_MV +#ifdef DEBUG_ENC_MV +int enc_mvcount = 0; +#endif + static void encode_mvcomponent( vp8_writer *const w, const int v, @@ -32,8 +37,7 @@ static void encode_mvcomponent( if (x < mvnum_short) // Small { vp8_write(w, 0, p [mvpis_short]); - vp8_treed_write(w, vp8_small_mvtree, p + MVPshort, x, 3); - + vp8_treed_write(w, vp8_small_mvtree, p + MVPshort, x, mvnum_short_bits); if (!x) return; // no sign bit } @@ -46,17 +50,17 @@ static void encode_mvcomponent( do vp8_write(w, (x >> i) & 1, p [MVPbits + i]); - while (++i < 3); + while (++i < mvnum_short_bits); i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ do vp8_write(w, (x >> i) & 1, p [MVPbits + i]); - while (--i > 3); + while (--i > mvnum_short_bits); - if (x & 0xFFF0) - vp8_write(w, (x >> 3) & 1, p [MVPbits + 3]); + if (x & ~((2<> mvnum_short_bits) & 1, p [MVPbits + mvnum_short_bits]); } vp8_write(w, v < 0, p [MVPsign]); @@ -91,9 +95,20 @@ void vp8_encode_motion_vector(vp8_writer *w, const MV *mv, const MV_CONTEXT *mvc } } #endif - encode_mvcomponent(w, mv->row >> 1, &mvc[0]); encode_mvcomponent(w, mv->col >> 1, &mvc[1]); +#ifdef DEBUG_ENC_MV + { + int i; + printf("%d (np): %d %d\n", enc_mvcount++, + (mv->row >> 1)<<1, (mv->col >> 1)<<1); + //for (i=0; iprob[i]); + //printf("\n"); + //for (i=0; iprob[i]); + //printf("\n"); + fflush(stdout); + } +#endif } @@ -106,7 +121,7 @@ static unsigned int cost_mvcomponent(const int v, const struct mv_context *mvc) if (x < mvnum_short) { cost = vp8_cost_zero(p [mvpis_short]) - + vp8_treed_cost(vp8_small_mvtree, p + MVPshort, x, 3); + + vp8_treed_cost(vp8_small_mvtree, p + MVPshort, x, mvnum_short_bits); if (!x) return cost; @@ -119,17 +134,17 @@ static unsigned int cost_mvcomponent(const int v, const struct mv_context *mvc) do cost += vp8_cost_bit(p [MVPbits + i], (x >> i) & 1); - while (++i < 3); + while (++i < mvnum_short_bits); i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ do cost += vp8_cost_bit(p [MVPbits + i], (x >> i) & 1); - while (--i > 3); + while (--i > mvnum_short_bits); - if (x & 0xFFF0) - cost += vp8_cost_bit(p [MVPbits + 3], (x >> 3) & 1); + if (x & ~((2<> mvnum_short_bits) & 1); } return cost; // + vp8_cost_bit( p [MVPsign], v < 0); @@ -258,7 +273,7 @@ static void write_component_probs( { const int c = events [mv_max]; - is_short_ct [0] += c; // Short vector + is_short_ct [0] += c; // Short vector short_ct [0] += c; // Magnitude distribution } @@ -342,7 +357,7 @@ static void write_component_probs( int j = 0; vp8_tree_probs_from_distribution( - 8, vp8_small_mvencodings, vp8_small_mvtree, + mvnum_short, vp8_small_mvencodings, vp8_small_mvtree, p, short_bct, short_ct, 256, 1 ); @@ -415,3 +430,345 @@ void vp8_write_mvprobs(VP8_COMP *cpi) active_section = 5; #endif } + +#if CONFIG_HIGH_PRECISION_MV + +static void encode_mvcomponent_hp( + vp8_writer *const w, + const int v, + const struct mv_context_hp *mvc +) +{ + const vp8_prob *p = mvc->prob; + const int x = v < 0 ? -v : v; + + if (x < mvnum_short_hp) // Small + { + vp8_write(w, 0, p [mvpis_short_hp]); + vp8_treed_write(w, vp8_small_mvtree_hp, p + MVPshort_hp, x, + mvnum_short_bits_hp); + if (!x) + return; // no sign bit + } + else // Large + { + int i = 0; + + vp8_write(w, 1, p [mvpis_short_hp]); + + do + vp8_write(w, (x >> i) & 1, p [MVPbits_hp + i]); + + while (++i < mvnum_short_bits_hp); + + i = mvlong_width_hp - 1; /* Skip bit 3, which is sometimes implicit */ + + do + vp8_write(w, (x >> i) & 1, p [MVPbits_hp + i]); + + while (--i > mvnum_short_bits_hp); + + if (x & ~((2<> mvnum_short_bits_hp) & 1, + p [MVPbits_hp + mvnum_short_bits_hp]); + } + + vp8_write(w, v < 0, p [MVPsign_hp]); +} +#if 0 +static int max_mv_r = 0; +static int max_mv_c = 0; +#endif +void vp8_encode_motion_vector_hp(vp8_writer *w, const MV *mv, + const MV_CONTEXT_HP *mvc) +{ + +#if 0 + { + if (abs(mv->row >> 1) > max_mv_r) + { + FILE *f = fopen("maxmv.stt", "a"); + max_mv_r = abs(mv->row >> 1); + fprintf(f, "New Mv Row Max %6d\n", (mv->row >> 1)); + + if ((abs(mv->row) / 2) != max_mv_r) + fprintf(f, "MV Row conversion error %6d\n", abs(mv->row) / 2); + + fclose(f); + } + + if (abs(mv->col >> 1) > max_mv_c) + { + FILE *f = fopen("maxmv.stt", "a"); + fprintf(f, "New Mv Col Max %6d\n", (mv->col >> 1)); + max_mv_c = abs(mv->col >> 1); + fclose(f); + } + } +#endif + encode_mvcomponent_hp(w, mv->row, &mvc[0]); + encode_mvcomponent_hp(w, mv->col, &mvc[1]); +#ifdef DEBUG_ENC_MV + { + int i; + printf("%d (hp): %d %d\n", enc_mvcount++, mv->row, mv->col); + //for (i=0; iprob[i]); + //printf("\n"); + //for (i=0; iprob[i]); + //printf("\n"); + fflush(stdout); + } +#endif +} + + +static unsigned int cost_mvcomponent_hp(const int v, + const struct mv_context_hp *mvc) +{ + const vp8_prob *p = mvc->prob; + const int x = v; //v<0? -v:v; + unsigned int cost; + + if (x < mvnum_short_hp) + { + cost = vp8_cost_zero(p [mvpis_short_hp]) + + vp8_treed_cost(vp8_small_mvtree_hp, p + MVPshort_hp, x, + mvnum_short_bits_hp); + + if (!x) + return cost; + } + else + { + int i = 0; + cost = vp8_cost_one(p [mvpis_short_hp]); + + do + cost += vp8_cost_bit(p [MVPbits_hp + i], (x >> i) & 1); + + while (++i < mvnum_short_bits_hp); + + i = mvlong_width_hp - 1; /* Skip bit 3, which is sometimes implicit */ + + do + cost += vp8_cost_bit(p [MVPbits_hp + i], (x >> i) & 1); + + while (--i > mvnum_short_bits_hp); + + if (x & ~((2<> mvnum_short_bits_hp) & 1); + } + + return cost; // + vp8_cost_bit( p [MVPsign], v < 0); +} + +void vp8_build_component_cost_table_hp(int *mvcost[2], + const MV_CONTEXT_HP *mvc, + int mvc_flag[2]) +{ + int i = 1; //-mv_max; + unsigned int cost0 = 0; + unsigned int cost1 = 0; + + vp8_clear_system_state(); + + i = 1; + + if (mvc_flag[0]) + { + mvcost [0] [0] = cost_mvcomponent_hp(0, &mvc[0]); + + do + { + //mvcost [0] [i] = cost_mvcomponent( i, &mvc[0]); + cost0 = cost_mvcomponent_hp(i, &mvc[0]); + + mvcost [0] [i] = cost0 + vp8_cost_zero(mvc[0].prob[MVPsign_hp]); + mvcost [0] [-i] = cost0 + vp8_cost_one(mvc[0].prob[MVPsign_hp]); + } + while (++i <= mv_max_hp); + } + + i = 1; + + if (mvc_flag[1]) + { + mvcost [1] [0] = cost_mvcomponent_hp(0, &mvc[1]); + + do + { + //mvcost [1] [i] = cost_mvcomponent( i, mvc[1]); + cost1 = cost_mvcomponent_hp(i, &mvc[1]); + + mvcost [1] [i] = cost1 + vp8_cost_zero(mvc[1].prob[MVPsign_hp]); + mvcost [1] [-i] = cost1 + vp8_cost_one(mvc[1].prob[MVPsign_hp]); + } + while (++i <= mv_max_hp); + } +} + + +static void write_component_probs_hp( + vp8_writer *const w, + struct mv_context_hp *cur_mvc, + const struct mv_context_hp *default_mvc_, + const struct mv_context_hp *update_mvc, + const unsigned int events [MVvals_hp], + unsigned int rc, + int *updated +) +{ + vp8_prob *Pcur = cur_mvc->prob; + const vp8_prob *default_mvc = default_mvc_->prob; + const vp8_prob *Pupdate = update_mvc->prob; + unsigned int is_short_ct[2], sign_ct[2]; + + unsigned int bit_ct [mvlong_width_hp] [2]; + + unsigned int short_ct [mvnum_short_hp]; + unsigned int short_bct [mvnum_short_hp-1] [2]; + + vp8_prob Pnew [MVPcount_hp]; + + (void) rc; + vp8_copy_array(Pnew, default_mvc, MVPcount_hp); + + vp8_zero(is_short_ct) + vp8_zero(sign_ct) + vp8_zero(bit_ct) + vp8_zero(short_ct) + vp8_zero(short_bct) + + + //j=0 + { + const int c = events [mv_max_hp]; + + is_short_ct [0] += c; // Short vector + short_ct [0] += c; // Magnitude distribution + } + + //j: 1 ~ mv_max (1023) + { + int j = 1; + + do + { + const int c1 = events [mv_max_hp + j]; //positive + const int c2 = events [mv_max_hp - j]; //negative + const int c = c1 + c2; + int a = j; + + sign_ct [0] += c1; + sign_ct [1] += c2; + + if (a < mvnum_short_hp) + { + is_short_ct [0] += c; // Short vector + short_ct [a] += c; // Magnitude distribution + } + else + { + int k = mvlong_width_hp - 1; + is_short_ct [1] += c; // Long vector + + /* bit 3 not always encoded. */ + do + bit_ct [k] [(a >> k) & 1] += c; + + while (--k >= 0); + } + } + while (++j <= mv_max_hp); + } + + calc_prob(Pnew + mvpis_short_hp, is_short_ct); + + calc_prob(Pnew + MVPsign_hp, sign_ct); + + { + vp8_prob p [mvnum_short_hp - 1]; /* actually only need branch ct */ + int j = 0; + + vp8_tree_probs_from_distribution( + mvnum_short_hp, vp8_small_mvencodings_hp, vp8_small_mvtree_hp, + p, short_bct, short_ct, + 256, 1 + ); + + do + calc_prob(Pnew + MVPshort_hp + j, short_bct[j]); + + while (++j < mvnum_short_hp - 1); + } + + { + int j = 0; + + do + calc_prob(Pnew + MVPbits_hp + j, bit_ct[j]); + + while (++j < mvlong_width_hp); + } + + update(w, is_short_ct, Pcur + mvpis_short_hp, Pnew[mvpis_short_hp], + *Pupdate++, updated); + + update(w, sign_ct, Pcur + MVPsign_hp, Pnew[MVPsign_hp], *Pupdate++, + updated); + + { + const vp8_prob *const new_p = Pnew + MVPshort_hp; + vp8_prob *const cur_p = Pcur + MVPshort_hp; + + int j = 0; + + do + + update(w, short_bct[j], cur_p + j, new_p[j], *Pupdate++, updated); + + while (++j < mvnum_short_hp - 1); + } + + { + const vp8_prob *const new_p = Pnew + MVPbits_hp; + vp8_prob *const cur_p = Pcur + MVPbits_hp; + + int j = 0; + + do + + update(w, bit_ct[j], cur_p + j, new_p[j], *Pupdate++, updated); + + while (++j < mvlong_width_hp); + } +} + +void vp8_write_mvprobs_hp(VP8_COMP *cpi) +{ + vp8_writer *const w = & cpi->bc; + MV_CONTEXT_HP *mvc = cpi->common.fc.mvc_hp; + int flags[2] = {0, 0}; +#ifdef ENTROPY_STATS + active_section = 4; +#endif + write_component_probs_hp( + w, &mvc[0], &vp8_default_mv_context_hp[0], &vp8_mv_update_probs_hp[0], + cpi->MVcount_hp[0], 0, &flags[0] + ); + write_component_probs_hp( + w, &mvc[1], &vp8_default_mv_context_hp[1], &vp8_mv_update_probs_hp[1], + cpi->MVcount_hp[1], 1, &flags[1] + ); + + if (flags[0] || flags[1]) + vp8_build_component_cost_table_hp(cpi->mb.mvcost_hp, + (const MV_CONTEXT_HP *) + cpi->common.fc.mvc_hp, flags); + +#ifdef ENTROPY_STATS + active_section = 5; +#endif +} +#endif /* CONFIG_HIGH_PRECISION_MV */ diff --git a/vp8/encoder/encodemv.h b/vp8/encoder/encodemv.h index a6116c133..09b0935cb 100644 --- a/vp8/encoder/encodemv.h +++ b/vp8/encoder/encodemv.h @@ -17,5 +17,10 @@ void vp8_write_mvprobs(VP8_COMP *); void vp8_encode_motion_vector(vp8_writer *, const MV *, const MV_CONTEXT *); void vp8_build_component_cost_table(int *mvcost[2], const MV_CONTEXT *mvc, int mvc_flag[2]); +#if CONFIG_HIGH_PRECISION_MV +void vp8_write_mvprobs_hp(VP8_COMP *); +void vp8_encode_motion_vector_hp(vp8_writer *, const MV *, const MV_CONTEXT_HP *); +void vp8_build_component_cost_table_hp(int *mvcost[2], const MV_CONTEXT_HP *mvc, int mvc_flag[2]); +#endif /* CONFIG_HIGH_PRECISION_MV */ #endif diff --git a/vp8/encoder/ethreading.c b/vp8/encoder/ethreading.c deleted file mode 100644 index c4e12ff02..000000000 --- a/vp8/encoder/ethreading.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "onyx_int.h" -#include "vp8/common/threading.h" -#include "vp8/common/common.h" -#include "vp8/common/extend.h" - -#if CONFIG_MULTITHREAD - -extern int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, - TOKENEXTRA **t, int recon_yoffset, - int recon_uvoffset); -extern int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, - TOKENEXTRA **t); -extern void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x); -extern void vp8_build_block_offsets(MACROBLOCK *x); -extern void vp8_setup_block_ptrs(MACROBLOCK *x); - -extern void loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm); - -static THREAD_FUNCTION loopfilter_thread(void *p_data) -{ - VP8_COMP *cpi = (VP8_COMP *)(((LPFTHREAD_DATA *)p_data)->ptr1); - VP8_COMMON *cm = &cpi->common; - - while (1) - { - if (cpi->b_multi_threaded == 0) - break; - - if (sem_wait(&cpi->h_event_start_lpf) == 0) - { - if (cpi->b_multi_threaded == FALSE) // we're shutting down - break; - - loopfilter_frame(cpi, cm); - - sem_post(&cpi->h_event_end_lpf); - } - } - - return 0; -} - -static -THREAD_FUNCTION thread_encoding_proc(void *p_data) -{ - int ithread = ((ENCODETHREAD_DATA *)p_data)->ithread; - VP8_COMP *cpi = (VP8_COMP *)(((ENCODETHREAD_DATA *)p_data)->ptr1); - MB_ROW_COMP *mbri = (MB_ROW_COMP *)(((ENCODETHREAD_DATA *)p_data)->ptr2); - ENTROPY_CONTEXT_PLANES mb_row_left_context; - - const int nsync = cpi->mt_sync_range; - //printf("Started thread %d\n", ithread); - - while (1) - { - if (cpi->b_multi_threaded == 0) - break; - - //if(WaitForSingleObject(cpi->h_event_mbrencoding[ithread], INFINITE) == WAIT_OBJECT_0) - if (sem_wait(&cpi->h_event_start_encoding[ithread]) == 0) - { - VP8_COMMON *cm = &cpi->common; - int mb_row; - MACROBLOCK *x = &mbri->mb; - MACROBLOCKD *xd = &x->e_mbd; - TOKENEXTRA *tp ; - - int *segment_counts = mbri->segment_counts; - int *totalrate = &mbri->totalrate; - - if (cpi->b_multi_threaded == FALSE) // we're shutting down - break; - - for (mb_row = ithread + 1; mb_row < cm->mb_rows; mb_row += (cpi->encoding_thread_count + 1)) - { - - int i; - int recon_yoffset, recon_uvoffset; - int mb_col; - int ref_fb_idx = cm->lst_fb_idx; - int dst_fb_idx = cm->new_fb_idx; - int recon_y_stride = cm->yv12_fb[ref_fb_idx].y_stride; - int recon_uv_stride = cm->yv12_fb[ref_fb_idx].uv_stride; - int map_index = (mb_row * cm->mb_cols); - volatile int *last_row_current_mb_col; - - tp = cpi->tok + (mb_row * (cm->mb_cols * 16 * 24)); - - last_row_current_mb_col = &cpi->mt_current_mb_col[mb_row - 1]; - - // reset above block coeffs - xd->above_context = cm->above_context; - xd->left_context = &mb_row_left_context; - - vp8_zero(mb_row_left_context); - - xd->up_available = (mb_row != 0); - recon_yoffset = (mb_row * recon_y_stride * 16); - recon_uvoffset = (mb_row * recon_uv_stride * 8); - - cpi->tplist[mb_row].start = tp; - - //printf("Thread mb_row = %d\n", mb_row); - - // Set the mb activity pointer to the start of the row. - x->mb_activity_ptr = &cpi->mb_activity_map[map_index]; - - // for each macroblock col in image - for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) - { - if ((mb_col & (nsync - 1)) == 0) - { - while (mb_col > (*last_row_current_mb_col - nsync) && *last_row_current_mb_col != cm->mb_cols - 1) - { - x86_pause_hint(); - thread_sleep(0); - } - } - - // Distance of Mb to the various image edges. - // These specified to 8th pel as they are always compared to values that are in 1/8th pel units - xd->mb_to_left_edge = -((mb_col * 16) << 3); - xd->mb_to_right_edge = ((cm->mb_cols - 1 - mb_col) * 16) << 3; - xd->mb_to_top_edge = -((mb_row * 16) << 3); - xd->mb_to_bottom_edge = ((cm->mb_rows - 1 - mb_row) * 16) << 3; - - // Set up limit values for motion vectors used to prevent them extending outside the UMV borders - x->mv_col_min = -((mb_col * 16) + (VP8BORDERINPIXELS - 16)); - x->mv_col_max = ((cm->mb_cols - 1 - mb_col) * 16) + (VP8BORDERINPIXELS - 16); - x->mv_row_min = -((mb_row * 16) + (VP8BORDERINPIXELS - 16)); - x->mv_row_max = ((cm->mb_rows - 1 - mb_row) * 16) + (VP8BORDERINPIXELS - 16); - - xd->dst.y_buffer = cm->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset; - xd->dst.u_buffer = cm->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset; - xd->dst.v_buffer = cm->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset; - xd->left_available = (mb_col != 0); - - x->rddiv = cpi->RDDIV; - x->rdmult = cpi->RDMULT; - - //Copy current mb to a buffer - RECON_INVOKE(&xd->rtcd->recon, copy16x16)(x->src.y_buffer, x->src.y_stride, x->thismb, 16); - - if (cpi->oxcf.tuning == VP8_TUNE_SSIM) - vp8_activity_masking(cpi, x); - - // Is segmentation enabled - // MB level adjutment to quantizer - if (xd->segmentation_enabled) - { - // Code to set segment id in xd->mbmi.segment_id for current MB (with range checking) - if (cpi->segmentation_map[map_index + mb_col] <= 3) - xd->mode_info_context->mbmi.segment_id = cpi->segmentation_map[map_index + mb_col]; - else - xd->mode_info_context->mbmi.segment_id = 0; - - vp8cx_mb_init_quantizer(cpi, x); - } - else - xd->mode_info_context->mbmi.segment_id = 0; // Set to Segment 0 by default - - x->active_ptr = cpi->active_map + map_index + mb_col; - - if (cm->frame_type == KEY_FRAME) - { - *totalrate += vp8cx_encode_intra_macro_block(cpi, x, &tp); -#ifdef MODE_STATS - y_modes[xd->mbmi.mode] ++; -#endif - } - else - { - *totalrate += vp8cx_encode_inter_macroblock(cpi, x, &tp, recon_yoffset, recon_uvoffset); - -#ifdef MODE_STATS - inter_y_modes[xd->mbmi.mode] ++; - - if (xd->mbmi.mode == SPLITMV) - { - int b; - - for (b = 0; b < xd->mbmi.partition_count; b++) - { - inter_b_modes[x->partition->bmi[b].mode] ++; - } - } - -#endif - - // Count of last ref frame 0,0 useage - if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)) - cpi->inter_zz_count++; - - // Special case code for cyclic refresh - // If cyclic update enabled then copy xd->mbmi.segment_id; (which may have been updated based on mode - // during vp8cx_encode_inter_macroblock()) back into the global sgmentation map - if (cpi->cyclic_refresh_mode_enabled && xd->segmentation_enabled) - { - const MB_MODE_INFO * mbmi = &xd->mode_info_context->mbmi; - cpi->segmentation_map[map_index + mb_col] = mbmi->segment_id; - - // If the block has been refreshed mark it as clean (the magnitude of the -ve influences how long it will be before we consider another refresh): - // Else if it was coded (last frame 0,0) and has not already been refreshed then mark it as a candidate for cleanup next time (marked 0) - // else mark it as dirty (1). - if (mbmi->segment_id) - cpi->cyclic_refresh_map[map_index + mb_col] = -1; - else if ((mbmi->mode == ZEROMV) && (mbmi->ref_frame == LAST_FRAME)) - { - if (cpi->cyclic_refresh_map[map_index + mb_col] == 1) - cpi->cyclic_refresh_map[map_index + mb_col] = 0; - } - else - cpi->cyclic_refresh_map[map_index + mb_col] = 1; - - } - } - cpi->tplist[mb_row].stop = tp; - - // Increment pointer into gf useage flags structure. - x->gf_active_ptr++; - - // Increment the activity mask pointers. - x->mb_activity_ptr++; - - // adjust to the next column of macroblocks - x->src.y_buffer += 16; - x->src.u_buffer += 8; - x->src.v_buffer += 8; - - recon_yoffset += 16; - recon_uvoffset += 8; - - // Keep track of segment useage - segment_counts[xd->mode_info_context->mbmi.segment_id]++; - - // skip to next mb - xd->mode_info_context++; - x->partition_info++; - xd->above_context++; - - cpi->mt_current_mb_col[mb_row] = mb_col; - } - - //extend the recon for intra prediction - vp8_extend_mb_row( - &cm->yv12_fb[dst_fb_idx], - xd->dst.y_buffer + 16, - xd->dst.u_buffer + 8, - xd->dst.v_buffer + 8); - - // this is to account for the border - xd->mode_info_context++; - x->partition_info++; - - x->src.y_buffer += 16 * x->src.y_stride * (cpi->encoding_thread_count + 1) - 16 * cm->mb_cols; - x->src.u_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; - x->src.v_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; - - xd->mode_info_context += xd->mode_info_stride * cpi->encoding_thread_count; - x->partition_info += xd->mode_info_stride * cpi->encoding_thread_count; - x->gf_active_ptr += cm->mb_cols * cpi->encoding_thread_count; - - if (mb_row == cm->mb_rows - 1) - { - //SetEvent(cpi->h_event_main); - sem_post(&cpi->h_event_end_encoding); /* signal frame encoding end */ - } - } - } - } - - //printf("exit thread %d\n", ithread); - return 0; -} - -static void setup_mbby_copy(MACROBLOCK *mbdst, MACROBLOCK *mbsrc) -{ - - MACROBLOCK *x = mbsrc; - MACROBLOCK *z = mbdst; - int i; - - z->ss = x->ss; - z->ss_count = x->ss_count; - z->searches_per_step = x->searches_per_step; - z->errorperbit = x->errorperbit; - - z->sadperbit16 = x->sadperbit16; - z->sadperbit4 = x->sadperbit4; - - /* - z->mv_col_min = x->mv_col_min; - z->mv_col_max = x->mv_col_max; - z->mv_row_min = x->mv_row_min; - z->mv_row_max = x->mv_row_max; - z->vector_range = x->vector_range ; - */ - - z->vp8_short_fdct4x4 = x->vp8_short_fdct4x4; - z->vp8_short_fdct8x4 = x->vp8_short_fdct8x4; - z->short_walsh4x4 = x->short_walsh4x4; - z->quantize_b = x->quantize_b; - z->quantize_b_pair = x->quantize_b_pair; - z->optimize = x->optimize; - - /* - z->mvc = x->mvc; - z->src.y_buffer = x->src.y_buffer; - z->src.u_buffer = x->src.u_buffer; - z->src.v_buffer = x->src.v_buffer; - */ - - - vpx_memcpy(z->mvcosts, x->mvcosts, sizeof(x->mvcosts)); - z->mvcost[0] = &z->mvcosts[0][mv_max+1]; - z->mvcost[1] = &z->mvcosts[1][mv_max+1]; - z->mvsadcost[0] = &z->mvsadcosts[0][mvfp_max+1]; - z->mvsadcost[1] = &z->mvsadcosts[1][mvfp_max+1]; - - - vpx_memcpy(z->token_costs, x->token_costs, sizeof(x->token_costs)); - vpx_memcpy(z->inter_bmode_costs, x->inter_bmode_costs, sizeof(x->inter_bmode_costs)); - //memcpy(z->mvcosts, x->mvcosts, sizeof(x->mvcosts)); - //memcpy(z->mvcost, x->mvcost, sizeof(x->mvcost)); - vpx_memcpy(z->mbmode_cost, x->mbmode_cost, sizeof(x->mbmode_cost)); - vpx_memcpy(z->intra_uv_mode_cost, x->intra_uv_mode_cost, sizeof(x->intra_uv_mode_cost)); - vpx_memcpy(z->bmode_costs, x->bmode_costs, sizeof(x->bmode_costs)); - - for (i = 0; i < 25; i++) - { - z->block[i].quant = x->block[i].quant; - z->block[i].quant_fast = x->block[i].quant_fast; - z->block[i].quant_shift = x->block[i].quant_shift; - z->block[i].zbin = x->block[i].zbin; - z->block[i].zrun_zbin_boost = x->block[i].zrun_zbin_boost; - z->block[i].round = x->block[i].round; - /* - z->block[i].src = x->block[i].src; - */ - z->block[i].src_stride = x->block[i].src_stride; - z->block[i].force_empty = x->block[i].force_empty; - - } - - { - MACROBLOCKD *xd = &x->e_mbd; - MACROBLOCKD *zd = &z->e_mbd; - - /* - zd->mode_info_context = xd->mode_info_context; - zd->mode_info = xd->mode_info; - - zd->mode_info_stride = xd->mode_info_stride; - zd->frame_type = xd->frame_type; - zd->up_available = xd->up_available ; - zd->left_available = xd->left_available; - zd->left_context = xd->left_context; - zd->last_frame_dc = xd->last_frame_dc; - zd->last_frame_dccons = xd->last_frame_dccons; - zd->gold_frame_dc = xd->gold_frame_dc; - zd->gold_frame_dccons = xd->gold_frame_dccons; - zd->mb_to_left_edge = xd->mb_to_left_edge; - zd->mb_to_right_edge = xd->mb_to_right_edge; - zd->mb_to_top_edge = xd->mb_to_top_edge ; - zd->mb_to_bottom_edge = xd->mb_to_bottom_edge; - zd->gf_active_ptr = xd->gf_active_ptr; - zd->frames_since_golden = xd->frames_since_golden; - zd->frames_till_alt_ref_frame = xd->frames_till_alt_ref_frame; - */ - zd->subpixel_predict = xd->subpixel_predict; - zd->subpixel_predict8x4 = xd->subpixel_predict8x4; - zd->subpixel_predict8x8 = xd->subpixel_predict8x8; - zd->subpixel_predict16x16 = xd->subpixel_predict16x16; - zd->segmentation_enabled = xd->segmentation_enabled; - zd->mb_segement_abs_delta = xd->mb_segement_abs_delta; - vpx_memcpy(zd->segment_feature_data, xd->segment_feature_data, sizeof(xd->segment_feature_data)); - - for (i = 0; i < 25; i++) - { - zd->block[i].dequant = xd->block[i].dequant; - } - } -} - -void vp8cx_init_mbrthread_data(VP8_COMP *cpi, - MACROBLOCK *x, - MB_ROW_COMP *mbr_ei, - int mb_row, - int count - ) -{ - - VP8_COMMON *const cm = & cpi->common; - MACROBLOCKD *const xd = & x->e_mbd; - int i; - (void) mb_row; - - for (i = 0; i < count; i++) - { - MACROBLOCK *mb = & mbr_ei[i].mb; - MACROBLOCKD *mbd = &mb->e_mbd; - - mbd->subpixel_predict = xd->subpixel_predict; - mbd->subpixel_predict8x4 = xd->subpixel_predict8x4; - mbd->subpixel_predict8x8 = xd->subpixel_predict8x8; - mbd->subpixel_predict16x16 = xd->subpixel_predict16x16; -#if CONFIG_RUNTIME_CPU_DETECT - mbd->rtcd = xd->rtcd; -#endif - mb->gf_active_ptr = x->gf_active_ptr; - - mb->vector_range = 32; - - vpx_memset(mbr_ei[i].segment_counts, 0, sizeof(mbr_ei[i].segment_counts)); - mbr_ei[i].totalrate = 0; - - mb->partition_info = x->pi + x->e_mbd.mode_info_stride * (i + 1); - - mbd->mode_info_context = cm->mi + x->e_mbd.mode_info_stride * (i + 1); - mbd->mode_info_stride = cm->mode_info_stride; - - mbd->frame_type = cm->frame_type; - - mbd->frames_since_golden = cm->frames_since_golden; - mbd->frames_till_alt_ref_frame = cm->frames_till_alt_ref_frame; - - mb->src = * cpi->Source; - mbd->pre = cm->yv12_fb[cm->lst_fb_idx]; - mbd->dst = cm->yv12_fb[cm->new_fb_idx]; - - mb->src.y_buffer += 16 * x->src.y_stride * (i + 1); - mb->src.u_buffer += 8 * x->src.uv_stride * (i + 1); - mb->src.v_buffer += 8 * x->src.uv_stride * (i + 1); - - vp8_build_block_offsets(mb); - - vp8_setup_block_dptrs(mbd); - - vp8_setup_block_ptrs(mb); - - mbd->left_context = &cm->left_context; - mb->mvc = cm->fc.mvc; - - setup_mbby_copy(&mbr_ei[i].mb, x); - - mbd->fullpixel_mask = 0xffffffff; - if(cm->full_pixel) - mbd->fullpixel_mask = 0xfffffff8; - } -} - -void vp8cx_create_encoder_threads(VP8_COMP *cpi) -{ - const VP8_COMMON * cm = &cpi->common; - - cpi->b_multi_threaded = 0; - cpi->encoding_thread_count = 0; - - if (cm->processor_core_count > 1 && cpi->oxcf.multi_threaded > 1) - { - int ithread; - int th_count = cpi->oxcf.multi_threaded - 1; - - /* don't allocate more threads than cores available */ - if (cpi->oxcf.multi_threaded > cm->processor_core_count) - th_count = cm->processor_core_count - 1; - - /* we have th_count + 1 (main) threads processing one row each */ - /* no point to have more threads than the sync range allows */ - if(th_count > ((cm->mb_cols / cpi->mt_sync_range) - 1)) - { - th_count = (cm->mb_cols / cpi->mt_sync_range) - 1; - } - - if(th_count == 0) - return; - - CHECK_MEM_ERROR(cpi->h_encoding_thread, vpx_malloc(sizeof(pthread_t) * th_count)); - CHECK_MEM_ERROR(cpi->h_event_start_encoding, vpx_malloc(sizeof(sem_t) * th_count)); - CHECK_MEM_ERROR(cpi->mb_row_ei, vpx_memalign(32, sizeof(MB_ROW_COMP) * th_count)); - vpx_memset(cpi->mb_row_ei, 0, sizeof(MB_ROW_COMP) * th_count); - CHECK_MEM_ERROR(cpi->en_thread_data, - vpx_malloc(sizeof(ENCODETHREAD_DATA) * th_count)); - CHECK_MEM_ERROR(cpi->mt_current_mb_col, - vpx_malloc(sizeof(*cpi->mt_current_mb_col) * cm->mb_rows)); - - sem_init(&cpi->h_event_end_encoding, 0, 0); - - cpi->b_multi_threaded = 1; - cpi->encoding_thread_count = th_count; - - /* - printf("[VP8:] multi_threaded encoding is enabled with %d threads\n\n", - (cpi->encoding_thread_count +1)); - */ - - for (ithread = 0; ithread < th_count; ithread++) - { - ENCODETHREAD_DATA * ethd = &cpi->en_thread_data[ithread]; - - sem_init(&cpi->h_event_start_encoding[ithread], 0, 0); - ethd->ithread = ithread; - ethd->ptr1 = (void *)cpi; - ethd->ptr2 = (void *)&cpi->mb_row_ei[ithread]; - - pthread_create(&cpi->h_encoding_thread[ithread], 0, thread_encoding_proc, ethd); - } - - { - LPFTHREAD_DATA * lpfthd = &cpi->lpf_thread_data; - - sem_init(&cpi->h_event_start_lpf, 0, 0); - sem_init(&cpi->h_event_end_lpf, 0, 0); - - lpfthd->ptr1 = (void *)cpi; - pthread_create(&cpi->h_filter_thread, 0, loopfilter_thread, lpfthd); - } - } - -} - -void vp8cx_remove_encoder_threads(VP8_COMP *cpi) -{ - if (cpi->b_multi_threaded) - { - //shutdown other threads - cpi->b_multi_threaded = 0; - { - int i; - - for (i = 0; i < cpi->encoding_thread_count; i++) - { - //SetEvent(cpi->h_event_mbrencoding[i]); - sem_post(&cpi->h_event_start_encoding[i]); - pthread_join(cpi->h_encoding_thread[i], 0); - - sem_destroy(&cpi->h_event_start_encoding[i]); - } - - sem_post(&cpi->h_event_start_lpf); - pthread_join(cpi->h_filter_thread, 0); - } - - sem_destroy(&cpi->h_event_end_encoding); - sem_destroy(&cpi->h_event_end_lpf); - sem_destroy(&cpi->h_event_start_lpf); - - //free thread related resources - vpx_free(cpi->h_event_start_encoding); - vpx_free(cpi->h_encoding_thread); - vpx_free(cpi->mb_row_ei); - vpx_free(cpi->en_thread_data); - vpx_free(cpi->mt_current_mb_col); - } -} -#endif diff --git a/vp8/encoder/find_rotation.c b/vp8/encoder/find_rotation.c new file mode 100644 index 000000000..742c0ba81 --- /dev/null +++ b/vp8/encoder/find_rotation.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "block.h" +#include "variance.h" + +#if CONFIG_ROTATION + +int vp8_find_best_rotation(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *bestmv, + int_mv *ref_mv, int *bri, int error_per_bit, + const vp8_variance_fn_ptr_t *vfp, int *mvcost[2], + int *distortion, unsigned int *sse1) +{ + unsigned char *z = (*(b->base_src) + b->src); + + int ri; + + int y_stride; + + unsigned int besterr; + int br = bestmv->as_mv.row; + int bc = bestmv->as_mv.col; + unsigned char *y = *(d->base_pre) + d->pre + br * d->pre_stride + bc; + y_stride = d->pre_stride; + + // calculate central point error + besterr = vfp->vf(y, y_stride, z, b->src_stride, sse1); + *distortion = besterr; + + // find the best matching rotation + *bri = 5; + for (ri = 0; ri < ROTATIONS; ri++) + { + unsigned int this_err; + unsigned char pb[256]; + predict_rotated_16x16(ri, y, y_stride, pb, 16); + this_err = vfp->vf(pb, 16, z, b->src_stride, sse1); + + if (this_err < besterr) + { + *bri = ri; + besterr = this_err; + } + } + *sse1 = besterr; + *distortion = besterr; + + return 0; +} + +#endif diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c index f2a1cd2d6..d63a1f923 100644 --- a/vp8/encoder/firstpass.c +++ b/vp8/encoder/firstpass.c @@ -26,6 +26,7 @@ #include "vp8/common/swapyv12buffer.h" #include #include "rdopt.h" +#include "ratectrl.h" #include "vp8/common/quant_common.h" #include "encodemv.h" @@ -37,19 +38,18 @@ #define IF_RTCD(x) NULL #endif +#if CONFIG_HIGH_PRECISION_MV +#define XMVCOST (x->e_mbd.allow_high_precision_mv?x->mvcost_hp:x->mvcost) +#else +#define XMVCOST (x->mvcost) +#endif + extern void vp8_build_block_offsets(MACROBLOCK *x); extern void vp8_setup_block_ptrs(MACROBLOCK *x); extern void vp8cx_frame_init_quantizer(VP8_COMP *cpi); extern void vp8_set_mbmode_and_mvs(MACROBLOCK *x, MB_PREDICTION_MODE mb, int_mv *mv); extern void vp8_alloc_compressor_data(VP8_COMP *cpi); -//#define GFQ_ADJUSTMENT (40 + ((15*Q)/10)) -//#define GFQ_ADJUSTMENT (80 + ((15*Q)/10)) -#define GFQ_ADJUSTMENT vp8_gf_boost_qadjustment[Q] -extern int vp8_kf_boost_qadjustment[QINDEX_RANGE]; - -extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE]; - #define IIFACTOR 1.5 #define IIKFACTOR1 1.40 #define IIKFACTOR2 1.5 @@ -69,21 +69,28 @@ extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE]; static int vscale_lookup[7] = {0, 1, 1, 2, 2, 3, 3}; static int hscale_lookup[7] = {0, 0, 1, 1, 2, 2, 3}; - -static const int cq_level[QINDEX_RANGE] = -{ - 0,0,1,1,2,3,3,4,4,5,6,6,7,8,8,9, - 9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,20, - 20,21,22,22,23,24,24,25,26,27,27,28,29,30,30,31, - 32,33,33,34,35,36,36,37,38,39,39,40,41,42,42,43, - 44,45,46,46,47,48,49,50,50,51,52,53,54,55,55,56, - 57,58,59,60,60,61,62,63,64,65,66,67,67,68,69,70, - 71,72,73,74,75,75,76,77,78,79,80,81,82,83,84,85, - 86,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100 -}; - static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame); +static int select_cq_level( int qindex ) +{ + int ret_val = QINDEX_RANGE - 1; + int i; + + double target_q = ( vp8_convert_qindex_to_q( qindex ) * 0.5847 ) + 1.0; + + for ( i = 0; i < QINDEX_RANGE; i++ ) + { + if ( target_q <= vp8_convert_qindex_to_q( i ) ) + { + ret_val = i; + break; + } + } + + return ret_val; +} + + // Resets the first pass file to the given position using a relative seek from the current position static void reset_fpf_position(VP8_COMP *cpi, FIRSTPASS_STATS *Position) { @@ -152,7 +159,7 @@ static void output_stats(const VP8_COMP *cpi, fprintf(fpfile, "%12.0f %12.0f %12.0f %12.4f %12.4f %12.4f %12.4f" " %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f" - " %12.0f %12.4f\n", + " %12.0f %12.0f %12.4f\n", stats->frame, stats->intra_error, stats->coded_error, @@ -168,6 +175,7 @@ static void output_stats(const VP8_COMP *cpi, stats->MVrv, stats->MVcv, stats->mv_in_out_count, + stats->new_mv_count, stats->count, stats->duration); fclose(fpfile); @@ -192,6 +200,7 @@ static void zero_stats(FIRSTPASS_STATS *section) section->MVrv = 0.0; section->MVcv = 0.0; section->mv_in_out_count = 0.0; + section->new_mv_count = 0.0; section->count = 0.0; section->duration = 1.0; } @@ -213,10 +222,33 @@ static void accumulate_stats(FIRSTPASS_STATS *section, FIRSTPASS_STATS *frame) section->MVrv += frame->MVrv; section->MVcv += frame->MVcv; section->mv_in_out_count += frame->mv_in_out_count; + section->new_mv_count += frame->new_mv_count; section->count += frame->count; section->duration += frame->duration; } +static void subtract_stats(FIRSTPASS_STATS *section, FIRSTPASS_STATS *frame) +{ + section->frame -= frame->frame; + section->intra_error -= frame->intra_error; + section->coded_error -= frame->coded_error; + section->ssim_weighted_pred_err -= frame->ssim_weighted_pred_err; + section->pcnt_inter -= frame->pcnt_inter; + section->pcnt_motion -= frame->pcnt_motion; + section->pcnt_second_ref -= frame->pcnt_second_ref; + section->pcnt_neutral -= frame->pcnt_neutral; + section->MVr -= frame->MVr; + section->mvr_abs -= frame->mvr_abs; + section->MVc -= frame->MVc; + section->mvc_abs -= frame->mvc_abs; + section->MVrv -= frame->MVrv; + section->MVcv -= frame->MVcv; + section->mv_in_out_count -= frame->mv_in_out_count; + section->new_mv_count -= frame->new_mv_count; + section->count -= frame->count; + section->duration -= frame->duration; +} + static void avg_stats(FIRSTPASS_STATS *section) { if (section->count < 1.0) @@ -242,49 +274,16 @@ static void avg_stats(FIRSTPASS_STATS *section) // Calculate a modified Error used in distributing bits between easier and harder frames static double calculate_modified_err(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) { - double av_err = cpi->twopass.total_stats->ssim_weighted_pred_err; + double av_err = ( cpi->twopass.total_stats->ssim_weighted_pred_err / + cpi->twopass.total_stats->count ); double this_err = this_frame->ssim_weighted_pred_err; double modified_err; - //double relative_next_iiratio; - //double next_iiratio; - //double sum_iiratio; - //int i; - - //FIRSTPASS_STATS next_frame; - //FIRSTPASS_STATS *start_pos; - - /*start_pos = cpi->twopass.stats_in; - sum_iiratio = 0.0; - i = 0; - while ( (i < 1) && input_stats(cpi,&next_frame) != EOF ) - { - - next_iiratio = next_frame.intra_error / DOUBLE_DIVIDE_CHECK(next_frame.coded_error); - next_iiratio = ( next_iiratio < 1.0 ) ? 1.0 : (next_iiratio > 20.0) ? 20.0 : next_iiratio; - sum_iiratio += next_iiratio; - i++; - } - if ( i > 0 ) - { - relative_next_iiratio = sum_iiratio / DOUBLE_DIVIDE_CHECK(cpi->twopass.avg_iiratio * (double)i); - } - else - { - relative_next_iiratio = 1.0; - } - reset_fpf_position(cpi, start_pos);*/ - if (this_err > av_err) modified_err = av_err * pow((this_err / DOUBLE_DIVIDE_CHECK(av_err)), POW1); else modified_err = av_err * pow((this_err / DOUBLE_DIVIDE_CHECK(av_err)), POW2); - /* - relative_next_iiratio = pow(relative_next_iiratio,0.25); - modified_err = modified_err * relative_next_iiratio; - */ - return modified_err; } @@ -356,33 +355,8 @@ static int frame_max_bits(VP8_COMP *cpi) // Max allocation for a single frame based on the max section guidelines passed in and how many bits are left int max_bits; - // For CBR we need to also consider buffer fullness. - // If we are running below the optimal level then we need to gradually tighten up on max_bits. - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - double buffer_fullness_ratio = (double)cpi->buffer_level / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.optimal_buffer_level); - - // For CBR base this on the target average bits per frame plus the maximum sedction rate passed in by the user - max_bits = (int)(cpi->av_per_frame_bandwidth * ((double)cpi->oxcf.two_pass_vbrmax_section / 100.0)); - - // If our buffer is below the optimum level - if (buffer_fullness_ratio < 1.0) - { - // The lower of max_bits / 4 or cpi->av_per_frame_bandwidth / 4. - int min_max_bits = ((cpi->av_per_frame_bandwidth >> 2) < (max_bits >> 2)) ? cpi->av_per_frame_bandwidth >> 2 : max_bits >> 2; - - max_bits = (int)(max_bits * buffer_fullness_ratio); - - if (max_bits < min_max_bits) - max_bits = min_max_bits; // Lowest value we will set ... which should allow the buffer to refil. - } - } - // VBR - else - { - // For VBR base this on the bits and frames left plus the two_pass_vbrmax_section rate passed in by the user - max_bits = (int)(((double)cpi->twopass.bits_left / (cpi->twopass.total_stats->count - (double)cpi->common.current_video_frame)) * ((double)cpi->oxcf.two_pass_vbrmax_section / 100.0)); - } + // For VBR base this on the bits and frames left plus the two_pass_vbrmax_section rate passed in by the user + max_bits = (int)(((double)cpi->twopass.bits_left / (cpi->twopass.total_stats->count - (double)cpi->common.current_video_frame)) * ((double)cpi->oxcf.two_pass_vbrmax_section / 100.0)); // Trap case where we are out of bits if (max_bits < 0) @@ -452,7 +426,7 @@ static void first_pass_motion_search(VP8_COMP *cpi, MACROBLOCK *x, ref_mv_full.as_mv.row = ref_mv->as_mv.row>>3; tmp_err = cpi->diamond_search_sad(x, b, d, &ref_mv_full, &tmp_mv, step_param, x->sadperbit16, &num00, &v_fn_ptr, - x->mvcost, ref_mv); + XMVCOST, ref_mv); if ( tmp_err < INT_MAX-new_mv_mode_penalty ) tmp_err += new_mv_mode_penalty; @@ -477,8 +451,8 @@ static void first_pass_motion_search(VP8_COMP *cpi, MACROBLOCK *x, { tmp_err = cpi->diamond_search_sad(x, b, d, &ref_mv_full, &tmp_mv, step_param + n, x->sadperbit16, - &num00, &v_fn_ptr, x->mvcost, - ref_mv); + &num00, &v_fn_ptr, + XMVCOST, ref_mv); if ( tmp_err < INT_MAX-new_mv_mode_penalty ) tmp_err += new_mv_mode_penalty; @@ -516,8 +490,9 @@ void vp8_first_pass(VP8_COMP *cpi) int second_ref_count = 0; int intrapenalty = 256; int neutral_count = 0; - + int new_mv_count = 0; int sum_in_vectors = 0; + uint32_t lastmv_as_int = 0; int_mv zero_ref_mv; @@ -548,9 +523,13 @@ void vp8_first_pass(VP8_COMP *cpi) //if ( 0 ) { int flag[2] = {1, 1}; - vp8_initialize_rd_consts(cpi, cm->base_qindex+cm->y1dc_delta_q); + vp8_initialize_rd_consts(cpi, cm->base_qindex + cm->y1dc_delta_q); vpx_memcpy(cm->fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context)); vp8_build_component_cost_table(cpi->mb.mvcost, (const MV_CONTEXT *) cm->fc.mvc, flag); +#if CONFIG_HIGH_PRECISION_MV + vpx_memcpy(cm->fc.mvc_hp, vp8_default_mv_context_hp, sizeof(vp8_default_mv_context_hp)); + vp8_build_component_cost_table_hp(cpi->mb.mvcost_hp, (const MV_CONTEXT_HP *) cm->fc.mvc_hp, flag); +#endif } // for each macroblock row in image @@ -697,6 +676,11 @@ void vp8_first_pass(VP8_COMP *cpi) { mvcount++; + // Was it different from the last non zero vector + if ( d->bmi.mv.as_int != lastmv_as_int ) + new_mv_count++; + lastmv_as_int = d->bmi.mv.as_int; + // Does the Row vector point inwards or outwards if (mb_row < cm->mb_rows / 2) { @@ -794,6 +778,7 @@ void vp8_first_pass(VP8_COMP *cpi) fps.MVrv = ((double)sum_mvrs - (fps.MVr * fps.MVr / (double)mvcount)) / (double)mvcount; fps.MVcv = ((double)sum_mvcs - (fps.MVc * fps.MVc / (double)mvcount)) / (double)mvcount; fps.mv_in_out_count = (double)sum_in_vectors / (double)(mvcount * 2); + fps.new_mv_count = new_mv_count; fps.pcnt_motion = 1.0 * (double)mvcount / cpi->common.MBs; } @@ -849,44 +834,150 @@ void vp8_first_pass(VP8_COMP *cpi) cm->current_video_frame++; } -extern const int vp8_bits_per_mb[2][QINDEX_RANGE]; -#define BASE_ERRPERMB 150 -static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh) +// Estimate a cost per mb attributable to overheads such as the coding of +// modes and motion vectors. +// Currently simplistic in its assumptions for testing. +// + + +double bitcost( double prob ) +{ + return -(log( prob ) / log( 2.0 )); +} +static long long estimate_modemvcost(VP8_COMP *cpi, + FIRSTPASS_STATS * fpstats) +{ + int mv_cost; + int mode_cost; + + double av_pct_inter = fpstats->pcnt_inter / fpstats->count; + double av_pct_motion = fpstats->pcnt_motion / fpstats->count; + double av_intra = (1.0 - av_pct_inter); + + double zz_cost; + double motion_cost; + double intra_cost; + + zz_cost = bitcost(av_pct_inter - av_pct_motion); + motion_cost = bitcost(av_pct_motion); + intra_cost = bitcost(av_intra); + + // Estimate of extra bits per mv overhead for mbs + // << 9 is the normalization to the (bits * 512) used in vp8_bits_per_mb + mv_cost = ((int)(fpstats->new_mv_count / fpstats->count) * 8) << 9; + + // Crude estimate of overhead cost from modes + // << 9 is the normalization to (bits * 512) used in vp8_bits_per_mb + mode_cost = + (int)( ( ((av_pct_inter - av_pct_motion) * zz_cost) + + (av_pct_motion * motion_cost) + + (av_intra * intra_cost) ) * cpi->common.MBs ) << 9; + + //return mv_cost + mode_cost; + // TODO PGW Fix overhead costs for extended Q range + return 0; +} + +static double calc_correction_factor( double err_per_mb, + double err_divisor, + double pt_low, + double pt_high, + int Q ) +{ + double power_term; + double error_term = err_per_mb / err_divisor; + double correction_factor; + + // Adjustment based on actual quantizer to power term. + power_term = (vp8_convert_qindex_to_q(Q) * 0.01) + pt_low; + power_term = (power_term > pt_high) ? pt_high : power_term; + + // Adjustments to error term + // TBD + + // Calculate correction factor + correction_factor = pow(error_term, power_term); + + // Clip range + correction_factor = + (correction_factor < 0.05) + ? 0.05 : (correction_factor > 5.0) ? 5.0 : correction_factor; + + return correction_factor; +} + +// Given a current maxQ value sets a range for future values. +// PGW TODO.. +// This code removes direct dependency on QIndex to determin the range +// (now uses the actual quantizer) but has not been tuned. +static double adjust_maxq_qrange(VP8_COMP *cpi) +{ + int i; + double q; + + // Set the max corresponding to cpi->avg_q * 2.0 + q = cpi->avg_q * 2.0; + cpi->twopass.maxq_max_limit = cpi->worst_quality; + for ( i = cpi->best_quality; i <= cpi->worst_quality; i++ ) + { + cpi->twopass.maxq_max_limit = i; + if ( vp8_convert_qindex_to_q(i) >= q ) + break; + } + + // Set the min corresponding to cpi->avg_q * 0.5 + q = cpi->avg_q * 0.5; + cpi->twopass.maxq_min_limit = cpi->best_quality; + for ( i = cpi->worst_quality; i >= cpi->best_quality; i-- ) + { + cpi->twopass.maxq_min_limit = i; + if ( vp8_convert_qindex_to_q(i) <= q ) + break; + } +} +#define ERR_DIVISOR 150.0 +static int estimate_max_q(VP8_COMP *cpi, + FIRSTPASS_STATS * fpstats, + int section_target_bandwitdh, + int overhead_bits ) { int Q; int num_mbs = cpi->common.MBs; int target_norm_bits_per_mb; + double section_err = (fpstats->coded_error / fpstats->count); double err_per_mb = section_err / num_mbs; - double correction_factor; + double err_correction_factor; double corr_high; double speed_correction = 1.0; - double pow_highq = 0.90; - double pow_lowq = 0.40; + double inter_pct = (fpstats->pcnt_inter / fpstats->count); + double intra_pct = 1.0 - inter_pct; + int overhead_bits_per_mb; if (section_target_bandwitdh <= 0) return cpi->twopass.maxq_max_limit; // Highest value allowed - target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) ? (512 * section_target_bandwitdh) / num_mbs : 512 * (section_target_bandwitdh / num_mbs); + target_norm_bits_per_mb = + (section_target_bandwitdh < (1 << 20)) + ? (512 * section_target_bandwitdh) / num_mbs + : 512 * (section_target_bandwitdh / num_mbs); - // Calculate a corrective factor based on a rolling ratio of bits spent vs target bits - if ((cpi->rolling_target_bits > 0) && (cpi->active_worst_quality < cpi->worst_quality)) + // Calculate a corrective factor based on a rolling ratio of bits spent + // vs target bits + if ((cpi->rolling_target_bits > 0) && + (cpi->active_worst_quality < cpi->worst_quality)) { double rolling_ratio; - rolling_ratio = (double)cpi->rolling_actual_bits / (double)cpi->rolling_target_bits; + rolling_ratio = (double)cpi->rolling_actual_bits / + (double)cpi->rolling_target_bits; - //if ( cpi->twopass.est_max_qcorrection_factor > rolling_ratio ) if (rolling_ratio < 0.95) - //cpi->twopass.est_max_qcorrection_factor *= adjustment_rate; cpi->twopass.est_max_qcorrection_factor -= 0.005; - //else if ( cpi->twopass.est_max_qcorrection_factor < rolling_ratio ) else if (rolling_ratio > 1.05) cpi->twopass.est_max_qcorrection_factor += 0.005; - //cpi->twopass.est_max_qcorrection_factor /= adjustment_rate; - cpi->twopass.est_max_qcorrection_factor = (cpi->twopass.est_max_qcorrection_factor < 0.1) ? 0.1 @@ -894,8 +985,9 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ ? 10.0 : cpi->twopass.est_max_qcorrection_factor; } - // Corrections for higher compression speed settings (reduced compression expected) - if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + // Corrections for higher compression speed settings + // (reduced compression expected) + if (cpi->compressor_speed == 1) { if (cpi->oxcf.cpu_used <= 5) speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); @@ -903,10 +995,12 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ speed_correction = 1.25; } - // Correction factor used for Q values >= 20 - corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); - corr_high = (corr_high < 0.05) - ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; + // Estimate of overhead bits per mb + // Correction to overhead bits for min allowed Q. + // PGW TODO.. This code is broken for the extended Q range + // for now overhead set to 0. + overhead_bits_per_mb = overhead_bits / num_mbs; + overhead_bits_per_mb *= pow( 0.98, (double)cpi->twopass.maxq_min_limit ); // Try and pick a max Q that will be high enough to encode the // content at the given rate. @@ -914,18 +1008,24 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ { int bits_per_mb_at_this_q; - if (Q < 50) - { - correction_factor = pow(err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01)); - correction_factor = (correction_factor < 0.05) ? 0.05 : (correction_factor > 5.0) ? 5.0 : correction_factor; - } - else - correction_factor = corr_high; + // Error per MB based correction factor + err_correction_factor = + calc_correction_factor(err_per_mb, ERR_DIVISOR, 0.36, 0.90, Q); - bits_per_mb_at_this_q = (int)(.5 + correction_factor + bits_per_mb_at_this_q = + vp8_bits_per_mb(INTER_FRAME, Q) + overhead_bits_per_mb; + + bits_per_mb_at_this_q = (int)(.5 + err_correction_factor * speed_correction * cpi->twopass.est_max_qcorrection_factor * cpi->twopass.section_max_qfactor - * (double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0); + * (double)bits_per_mb_at_this_q); + + // Mode and motion overhead + // As Q rises in real encode loop rd code will force overhead down + // We make a crude adjustment for this here as *.98 per Q step. + // PGW TODO.. This code is broken for the extended Q range + // for now overhead set to 0. + overhead_bits_per_mb = (int)((double)overhead_bits_per_mb * 0.98); if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) break; @@ -934,44 +1034,63 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ // Restriction on active max q for constrained quality mode. if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && (Q < cpi->cq_target_quality) ) - //(Q < cpi->oxcf.cq_level;) ) { Q = cpi->cq_target_quality; - //Q = cpi->oxcf.cq_level; } // Adjust maxq_min_limit and maxq_max_limit limits based on - // averaga q observed in clip for non kf/gf.arf frames + // averaga q observed in clip for non kf/gf/arf frames // Give average a chance to settle though. + // PGW TODO.. This code is broken for the extended Q range if ( (cpi->ni_frames > ((unsigned int)cpi->twopass.total_stats->count >> 8)) && (cpi->ni_frames > 150) ) { - cpi->twopass.maxq_max_limit = ((cpi->ni_av_qi + 32) < cpi->worst_quality) - ? (cpi->ni_av_qi + 32) : cpi->worst_quality; - cpi->twopass.maxq_min_limit = ((cpi->ni_av_qi - 32) > cpi->best_quality) - ? (cpi->ni_av_qi - 32) : cpi->best_quality; + adjust_maxq_qrange( cpi ); } return Q; } -static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh) + +// For cq mode estimate a cq level that matches the observed +// complexity and data rate. +static int estimate_cq( VP8_COMP *cpi, + FIRSTPASS_STATS * fpstats, + int section_target_bandwitdh, + int overhead_bits ) { int Q; int num_mbs = cpi->common.MBs; int target_norm_bits_per_mb; + double section_err = (fpstats->coded_error / fpstats->count); double err_per_mb = section_err / num_mbs; - double correction_factor; + double err_correction_factor; double corr_high; double speed_correction = 1.0; - double pow_highq = 0.90; - double pow_lowq = 0.40; + double clip_iiratio; + double clip_iifactor; + double inter_pct = (fpstats->pcnt_inter / fpstats->count); + double intra_pct = 1.0 - inter_pct; + int overhead_bits_per_mb; - target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) ? (512 * section_target_bandwitdh) / num_mbs : 512 * (section_target_bandwitdh / num_mbs); + if (0) + { + FILE *f = fopen("epmp.stt", "a"); + fprintf(f, "%10.2f\n", err_per_mb ); + fclose(f); + } - // Corrections for higher compression speed settings (reduced compression expected) - if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) + ? (512 * section_target_bandwitdh) / num_mbs + : 512 * (section_target_bandwitdh / num_mbs); + + // Estimate of overhead bits per mb + overhead_bits_per_mb = overhead_bits / num_mbs; + + // Corrections for higher compression speed settings + // (reduced compression expected) + if (cpi->compressor_speed == 1) { if (cpi->oxcf.cpu_used <= 5) speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); @@ -979,24 +1098,88 @@ static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_band speed_correction = 1.25; } - // Correction factor used for Q values >= 20 - corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); - corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; + // II ratio correction factor for clip as a whole + clip_iiratio = cpi->twopass.total_stats->intra_error / + DOUBLE_DIVIDE_CHECK(cpi->twopass.total_stats->coded_error); + clip_iifactor = 1.0 - ((clip_iiratio - 10.0) * 0.025); + if (clip_iifactor < 0.80) + clip_iifactor = 0.80; // Try and pick a Q that can encode the content at the given rate. for (Q = 0; Q < MAXQ; Q++) { int bits_per_mb_at_this_q; - if (Q < 50) - { - correction_factor = pow(err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01)); - correction_factor = (correction_factor < 0.05) ? 0.05 : (correction_factor > 5.0) ? 5.0 : correction_factor; - } - else - correction_factor = corr_high; + // Error per MB based correction factor + err_correction_factor = + calc_correction_factor(err_per_mb, 100.0, 0.36, 0.90, Q); - bits_per_mb_at_this_q = (int)(.5 + correction_factor * speed_correction * cpi->twopass.est_max_qcorrection_factor * (double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0); + bits_per_mb_at_this_q = + vp8_bits_per_mb(INTER_FRAME, Q) + overhead_bits_per_mb; + + bits_per_mb_at_this_q = + (int)( .5 + err_correction_factor * + speed_correction * + clip_iifactor * + (double)bits_per_mb_at_this_q); + + // Mode and motion overhead + // As Q rises in real encode loop rd code will force overhead down + // We make a crude adjustment for this here as *.98 per Q step. + // PGW TODO.. This code is broken for the extended Q range + // for now overhead set to 0. + overhead_bits_per_mb = (int)((double)overhead_bits_per_mb * 0.98); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + // Clip value to range "best allowed to (worst allowed - 1)" + Q = select_cq_level( Q ); + if ( Q >= cpi->worst_quality ) + Q = cpi->worst_quality - 1; + if ( Q < cpi->best_quality ) + Q = cpi->best_quality; + + return Q; +} + +static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh) +{ + int Q; + int num_mbs = cpi->common.MBs; + int target_norm_bits_per_mb; + + double err_per_mb = section_err / num_mbs; + double err_correction_factor; + double corr_high; + double speed_correction = 1.0; + + target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) ? (512 * section_target_bandwitdh) / num_mbs : 512 * (section_target_bandwitdh / num_mbs); + + // Corrections for higher compression speed settings (reduced compression expected) + if (cpi->compressor_speed == 1) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + + // Try and pick a Q that can encode the content at the given rate. + for (Q = 0; Q < MAXQ; Q++) + { + int bits_per_mb_at_this_q; + + // Error per MB based correction factor + err_correction_factor = + calc_correction_factor(err_per_mb, ERR_DIVISOR, 0.36, 0.90, Q); + + bits_per_mb_at_this_q = + (int)( .5 + ( err_correction_factor * + speed_correction * + cpi->twopass.est_max_qcorrection_factor * + (double)vp8_bits_per_mb(INTER_FRAME, Q) / 1.0 ) ); if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) break; @@ -1048,7 +1231,7 @@ static int estimate_kf_group_q(VP8_COMP *cpi, double section_err, int section_ta iiratio_correction_factor = 0.5; // Corrections for higher compression speed settings (reduced compression expected) - if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + if (cpi->compressor_speed == 1) { if (cpi->oxcf.cpu_used <= 5) speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); @@ -1059,23 +1242,17 @@ static int estimate_kf_group_q(VP8_COMP *cpi, double section_err, int section_ta // Combine the various factors calculated above combined_correction_factor = speed_correction * iiratio_correction_factor * current_spend_ratio; - // Correction factor used for Q values >= 20 - corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); - corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; - // Try and pick a Q that should be high enough to encode the content at the given rate. for (Q = 0; Q < MAXQ; Q++) { - // Q values < 20 treated as a special case - if (Q < 20) - { - err_correction_factor = pow(err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01)); - err_correction_factor = (err_correction_factor < 0.05) ? 0.05 : (err_correction_factor > 5.0) ? 5.0 : err_correction_factor; - } - else - err_correction_factor = corr_high; + // Error per MB based correction factor + err_correction_factor = + calc_correction_factor(err_per_mb, ERR_DIVISOR, pow_lowq, pow_highq, Q); - bits_per_mb_at_this_q = (int)(.5 + err_correction_factor * combined_correction_factor * (double)vp8_bits_per_mb[INTER_FRAME][Q]); + bits_per_mb_at_this_q = + (int)(.5 + ( err_correction_factor * + combined_correction_factor * + (double)vp8_bits_per_mb(INTER_FRAME, Q)) ); if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) break; @@ -1102,77 +1279,6 @@ static int estimate_kf_group_q(VP8_COMP *cpi, double section_err, int section_ta return Q; } -// For cq mode estimate a cq level that matches the observed -// complexity and data rate. -static int estimate_cq(VP8_COMP *cpi, double section_err, int section_target_bandwitdh) -{ - int Q; - int num_mbs = cpi->common.MBs; - int target_norm_bits_per_mb; - - double err_per_mb = section_err / num_mbs; - double correction_factor; - double corr_high; - double speed_correction = 1.0; - double pow_highq = 0.90; - double pow_lowq = 0.40; - double clip_iiratio; - double clip_iifactor; - - target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) - ? (512 * section_target_bandwitdh) / num_mbs - : 512 * (section_target_bandwitdh / num_mbs); - - // Corrections for higher compression speed settings - // (reduced compression expected) - if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) - { - if (cpi->oxcf.cpu_used <= 5) - speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); - else - speed_correction = 1.25; - } - // II ratio correction factor for clip as a whole - clip_iiratio = cpi->twopass.total_stats->intra_error / - DOUBLE_DIVIDE_CHECK(cpi->twopass.total_stats->coded_error); - clip_iifactor = 1.0 - ((clip_iiratio - 10.0) * 0.025); - if (clip_iifactor < 0.80) - clip_iifactor = 0.80; - - // Correction factor used for Q values >= 20 - corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); - corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; - - // Try and pick a Q that can encode the content at the given rate. - for (Q = 0; Q < MAXQ; Q++) - { - int bits_per_mb_at_this_q; - - if (Q < 50) - { - correction_factor = - pow( err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01)); - - correction_factor = (correction_factor < 0.05) ? 0.05 - : (correction_factor > 5.0) ? 5.0 - : correction_factor; - } - else - correction_factor = corr_high; - - bits_per_mb_at_this_q = - (int)( .5 + correction_factor * - speed_correction * - clip_iifactor * - (double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0); - - if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) - break; - } - - return cq_level[Q]; -} - extern void vp8_new_frame_rate(VP8_COMP *cpi, double framerate); void vp8_init_second_pass(VP8_COMP *cpi) @@ -1180,22 +1286,21 @@ void vp8_init_second_pass(VP8_COMP *cpi) FIRSTPASS_STATS this_frame; FIRSTPASS_STATS *start_pos; - double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + double lower_bounds_min_rate = FRAME_OVERHEAD_BITS*cpi->oxcf.frame_rate; + double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth + * cpi->oxcf.two_pass_vbrmin_section / 100); + + if (two_pass_min_rate < lower_bounds_min_rate) + two_pass_min_rate = lower_bounds_min_rate; zero_stats(cpi->twopass.total_stats); + zero_stats(cpi->twopass.total_left_stats); if (!cpi->twopass.stats_in_end) return; *cpi->twopass.total_stats = *cpi->twopass.stats_in_end; - - cpi->twopass.total_error_left = cpi->twopass.total_stats->ssim_weighted_pred_err; - cpi->twopass.total_intra_error_left = cpi->twopass.total_stats->intra_error; - cpi->twopass.total_coded_error_left = cpi->twopass.total_stats->coded_error; - cpi->twopass.start_tot_err_left = cpi->twopass.total_error_left; - - //cpi->twopass.bits_left = (int64_t)(cpi->twopass.total_stats->count * cpi->oxcf.target_bandwidth / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.frame_rate)); - //cpi->twopass.bits_left -= (int64_t)(cpi->twopass.total_stats->count * two_pass_min_rate / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.frame_rate)); + *cpi->twopass.total_left_stats = *cpi->twopass.total_stats; // each frame can have a different duration, as the frame rate in the source // isn't guaranteed to be constant. The frame rate prior to the first frame @@ -1207,7 +1312,6 @@ void vp8_init_second_pass(VP8_COMP *cpi) cpi->output_frame_rate = cpi->oxcf.frame_rate; cpi->twopass.bits_left = (int64_t)(cpi->twopass.total_stats->duration * cpi->oxcf.target_bandwidth / 10000000.0) ; cpi->twopass.bits_left -= (int64_t)(cpi->twopass.total_stats->duration * two_pass_min_rate / 10000000.0); - cpi->twopass.clip_bits_total = cpi->twopass.bits_left; // Calculate a minimum intra value to be used in determining the IIratio // scores used in the second pass. We have this minimum to make sure @@ -1216,8 +1320,6 @@ void vp8_init_second_pass(VP8_COMP *cpi) cpi->twopass.kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs; cpi->twopass.gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs; - avg_stats(cpi->twopass.total_stats); - // Scan the first pass file and calculate an average Intra / Inter error score ratio for the sequence { double sum_iiratio = 0.0; @@ -1716,35 +1818,6 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) cpi->twopass.gf_decay_rate = (i > 0) ? (int)(100.0 * (1.0 - decay_accumulator)) / i : 0; - // When using CBR apply additional buffer related upper limits - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - double max_boost; - - // For cbr apply buffer related limits - if (cpi->drop_frames_allowed) - { - int df_buffer_level = cpi->oxcf.drop_frames_water_mark * - (cpi->oxcf.optimal_buffer_level / 100); - - if (cpi->buffer_level > df_buffer_level) - max_boost = ((double)((cpi->buffer_level - df_buffer_level) * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); - else - max_boost = 0.0; - } - else if (cpi->buffer_level > 0) - { - max_boost = ((double)(cpi->buffer_level * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); - } - else - { - max_boost = 0.0; - } - - if (boost_score > max_boost) - boost_score = max_boost; - } - // Dont allow conventional gf too near the next kf if ((cpi->twopass.frames_to_key - i) < MIN_GF_INTERVAL) { @@ -1815,9 +1888,9 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // Boost for arf frame #if NEW_BOOST - Boost = (alt_boost * GFQ_ADJUSTMENT) / 100; + Boost = (alt_boost * vp8_gfboost_qadjust(Q)) / 100; #else - Boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); + Boost = (cpi->gfu_boost * 3 * vp8_gfboost_qadjust(Q)) / (2 * 100); #endif Boost += (i * 50); @@ -1982,9 +2055,9 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) if (cpi->source_alt_ref_pending && i == 0) { #if NEW_BOOST - Boost = (alt_boost * GFQ_ADJUSTMENT) / 100; + Boost = (alt_boost * vp8_gfboost_qadjust(Q)) / 100; #else - Boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); + Boost = (cpi->gfu_boost * 3 * vp8_gfboost_qadjust(Q)) / (2 * 100); #endif Boost += (cpi->baseline_gf_interval * 50); @@ -2001,7 +2074,7 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) else { // boost based on inter / intra ratio of subsequent frames - Boost = (cpi->gfu_boost * GFQ_ADJUSTMENT) / 100; + Boost = (cpi->gfu_boost * vp8_gfboost_qadjust(Q)) / 100; // Set max and minimum boost and hence minimum allocation if (Boost > (cpi->baseline_gf_interval * 150)) @@ -2063,13 +2136,6 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) } } - // Apply an additional limit for CBR - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - if (cpi->twopass.gf_bits > (cpi->buffer_level >> 1)) - cpi->twopass.gf_bits = cpi->buffer_level >> 1; - } - // Dont allow a negative value for gf_bits if (gf_bits < 0) gf_bits = 0; @@ -2224,6 +2290,46 @@ static void assign_std_frame_bits(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) cpi->per_frame_bandwidth = target_frame_size; // Per frame bit target for this frame } +// Make a damped adjustment to the active max q. +int adjust_active_maxq( int old_maxqi, int new_maxqi ) +{ + int i; + int ret_val = new_maxqi; + double old_q; + double new_q; + double target_q; + + old_q = vp8_convert_qindex_to_q( old_maxqi ); + new_q = vp8_convert_qindex_to_q( new_maxqi ); + + target_q = ((old_q * 7.0) + new_q) / 8.0; + + if ( target_q > old_q ) + { + for ( i = old_maxqi; i <= new_maxqi; i++ ) + { + if ( vp8_convert_qindex_to_q( i ) >= target_q ) + { + ret_val = i; + break; + } + } + } + else + { + for ( i = old_maxqi; i >= new_maxqi; i-- ) + { + if ( vp8_convert_qindex_to_q( i ) <= target_q ) + { + ret_val = i; + break; + } + } + } + + return ret_val; +} + void vp8_second_pass(VP8_COMP *cpi) { int tmp_q; @@ -2238,6 +2344,8 @@ void vp8_second_pass(VP8_COMP *cpi) FIRSTPASS_STATS *start_pos; + int overhead_bits; + if (!cpi->twopass.stats_in) { return ; @@ -2260,19 +2368,6 @@ void vp8_second_pass(VP8_COMP *cpi) // Define next KF group and assign bits to it vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); find_next_key_frame(cpi, &this_frame_copy); - - // Special case: Error error_resilient_mode mode does not make much sense for two pass but with its current meaning but this code is designed to stop - // outlandish behaviour if someone does set it when using two pass. It effectively disables GF groups. - // This is temporary code till we decide what should really happen in this case. - if (cpi->oxcf.error_resilient_mode) - { - cpi->twopass.gf_group_bits = cpi->twopass.kf_group_bits; - cpi->twopass.gf_group_error_left = cpi->twopass.kf_group_error_left; - cpi->baseline_gf_interval = cpi->twopass.frames_to_key; - cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; - cpi->source_alt_ref_pending = FALSE; - } - } // Is this a GF / ARF (Note that a KF is always also a GF) @@ -2298,26 +2393,9 @@ void vp8_second_pass(VP8_COMP *cpi) // Otherwise this is an ordinary frame else { - // Special case: Error error_resilient_mode mode does not make much sense for two pass but with its current meaning but this code is designed to stop - // outlandish behaviour if someone does set it when using two pass. It effectively disables GF groups. - // This is temporary code till we decide what should really happen in this case. - if (cpi->oxcf.error_resilient_mode) - { - cpi->frames_till_gf_update_due = cpi->twopass.frames_to_key; - - if (cpi->common.frame_type != KEY_FRAME) - { - // Assign bits from those allocated to the GF group - vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); - assign_std_frame_bits(cpi, &this_frame_copy); - } - } - else - { - // Assign bits from those allocated to the GF group - vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); - assign_std_frame_bits(cpi, &this_frame_copy); - } + // Assign bits from those allocated to the GF group + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + assign_std_frame_bits(cpi, &this_frame_copy); } // Keep a globally available copy of this and the next frame's iiratio. @@ -2337,20 +2415,26 @@ void vp8_second_pass(VP8_COMP *cpi) if (cpi->target_bandwidth < 0) cpi->target_bandwidth = 0; + + // Account for mv, mode and other overheads. + overhead_bits = estimate_modemvcost( + cpi, cpi->twopass.total_left_stats ); + + // Special case code for first frame. if (cpi->common.current_video_frame == 0) { cpi->twopass.est_max_qcorrection_factor = 1.0; - // Experimental code to try and set a cq_level in constrained - // quality mode. + // Set a cq_level in constrained quality mode. if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY ) { int est_cq; est_cq = estimate_cq( cpi, - (cpi->twopass.total_coded_error_left / frames_left), - (int)(cpi->twopass.bits_left / frames_left)); + cpi->twopass.total_left_stats, + (int)(cpi->twopass.bits_left / frames_left), + overhead_bits ); cpi->cq_target_quality = cpi->oxcf.cq_level; if ( est_cq > cpi->cq_target_quality ) @@ -2360,22 +2444,23 @@ void vp8_second_pass(VP8_COMP *cpi) // guess at maxq needed in 2nd pass cpi->twopass.maxq_max_limit = cpi->worst_quality; cpi->twopass.maxq_min_limit = cpi->best_quality; - tmp_q = estimate_max_q( cpi, - (cpi->twopass.total_coded_error_left / frames_left), - (int)(cpi->twopass.bits_left / frames_left)); + + tmp_q = estimate_max_q( + cpi, + cpi->twopass.total_left_stats, + (int)(cpi->twopass.bits_left / frames_left), + overhead_bits ); + + cpi->active_worst_quality = tmp_q; + cpi->ni_av_qi = tmp_q; + cpi->avg_q = vp8_convert_qindex_to_q( tmp_q ); // Limit the maxq value returned subsequently. // This increases the risk of overspend or underspend if the initial // estimate for the clip is bad, but helps prevent excessive // variation in Q, especially near the end of a clip // where for example a small overspend may cause Q to crash - cpi->twopass.maxq_max_limit = ((tmp_q + 32) < cpi->worst_quality) - ? (tmp_q + 32) : cpi->worst_quality; - cpi->twopass.maxq_min_limit = ((tmp_q - 32) > cpi->best_quality) - ? (tmp_q - 32) : cpi->best_quality; - - cpi->active_worst_quality = tmp_q; - cpi->ni_av_qi = tmp_q; + adjust_maxq_qrange(cpi); } // The last few frames of a clip almost always have to few or too many @@ -2383,28 +2468,28 @@ void vp8_second_pass(VP8_COMP *cpi) // radical adjustments to the allowed quantizer range just to use up a // few surplus bits or get beneath the target rate. else if ( (cpi->common.current_video_frame < - (((unsigned int)cpi->twopass.total_stats->count * 255)>>8)) && + (((unsigned int)cpi->twopass.total_stats->count * 255)>>8)) && ((cpi->common.current_video_frame + cpi->baseline_gf_interval) < - (unsigned int)cpi->twopass.total_stats->count) ) + (unsigned int)cpi->twopass.total_stats->count) ) { if (frames_left < 1) frames_left = 1; - tmp_q = estimate_max_q(cpi, (cpi->twopass.total_coded_error_left / frames_left), (int)(cpi->twopass.bits_left / frames_left)); + tmp_q = estimate_max_q( + cpi, + cpi->twopass.total_left_stats, + (int)(cpi->twopass.bits_left / frames_left), + overhead_bits ); - // Move active_worst_quality but in a damped way - if (tmp_q > cpi->active_worst_quality) - cpi->active_worst_quality ++; - else if (tmp_q < cpi->active_worst_quality) - cpi->active_worst_quality --; - - cpi->active_worst_quality = ((cpi->active_worst_quality * 3) + tmp_q + 2) / 4; + // Make a damped adjustment to active max Q + cpi->active_worst_quality = + adjust_active_maxq( cpi->active_worst_quality, tmp_q ); } cpi->twopass.frames_to_key --; - cpi->twopass.total_error_left -= this_frame_error; - cpi->twopass.total_intra_error_left -= this_frame_intra_error; - cpi->twopass.total_coded_error_left -= this_frame_coded_error; + + // Update the total stats remaining sturcture + subtract_stats(cpi->twopass.total_left_stats, &this_frame ); } @@ -2678,51 +2763,6 @@ static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) max_grp_bits = (int64_t)max_bits * (int64_t)cpi->twopass.frames_to_key; if (cpi->twopass.kf_group_bits > max_grp_bits) cpi->twopass.kf_group_bits = max_grp_bits; - - // Additional special case for CBR if buffer is getting full. - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - int opt_buffer_lvl = cpi->oxcf.optimal_buffer_level; - int buffer_lvl = cpi->buffer_level; - - // If the buffer is near or above the optimal and this kf group is - // not being allocated much then increase the allocation a bit. - if (buffer_lvl >= opt_buffer_lvl) - { - int high_water_mark = (opt_buffer_lvl + - cpi->oxcf.maximum_buffer_size) >> 1; - - int64_t av_group_bits; - - // Av bits per frame * number of frames - av_group_bits = (int64_t)cpi->av_per_frame_bandwidth * - (int64_t)cpi->twopass.frames_to_key; - - // We are at or above the maximum. - if (cpi->buffer_level >= high_water_mark) - { - int64_t min_group_bits; - - min_group_bits = av_group_bits + - (int64_t)(buffer_lvl - - high_water_mark); - - if (cpi->twopass.kf_group_bits < min_group_bits) - cpi->twopass.kf_group_bits = min_group_bits; - } - // We are above optimal but below the maximum - else if (cpi->twopass.kf_group_bits < av_group_bits) - { - int64_t bits_below_av = av_group_bits - - cpi->twopass.kf_group_bits; - - cpi->twopass.kf_group_bits += - (int64_t)((double)bits_below_av * - (double)(buffer_lvl - opt_buffer_lvl) / - (double)(high_water_mark - opt_buffer_lvl)); - } - } - } } else cpi->twopass.kf_group_bits = 0; @@ -2802,33 +2842,6 @@ static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // cpi->twopass.section_max_qfactor = 1.0; } - // When using CBR apply additional buffer fullness related upper limits - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - double max_boost; - - if (cpi->drop_frames_allowed) - { - int df_buffer_level = cpi->oxcf.drop_frames_water_mark * (cpi->oxcf.optimal_buffer_level / 100); - - if (cpi->buffer_level > df_buffer_level) - max_boost = ((double)((cpi->buffer_level - df_buffer_level) * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); - else - max_boost = 0.0; - } - else if (cpi->buffer_level > 0) - { - max_boost = ((double)(cpi->buffer_level * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); - } - else - { - max_boost = 0.0; - } - - if (boost_score > max_boost) - boost_score = max_boost; - } - // Reset the first pass file position reset_fpf_position(cpi, start_position); @@ -2866,18 +2879,31 @@ static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) kf_boost = (int)((double)kf_boost * 100.0) >> 4; // Scale 16 to 100 - // Adjustment to boost based on recent average q - //kf_boost = kf_boost * vp8_kf_boost_qadjustment[cpi->ni_av_qi] / 100; - if (kf_boost < 250) // Min KF boost kf_boost = 250; // We do three calculations for kf size. // The first is based on the error score for the whole kf group. - // The second (optionaly) on the key frames own error if this is smaller than the average for the group. - // The final one insures that the frame receives at least the allocation it would have received based on its own error score vs the error score remaining - - allocation_chunks = ((cpi->twopass.frames_to_key - 1) * 100) + kf_boost; // cpi->twopass.frames_to_key-1 because key frame itself is taken care of by kf_boost + // The second (optionaly) on the key frames own error if this is + // smaller than the average for the group. + // The final one insures that the frame receives at least the + // allocation it would have received based on its own error score vs + // the error score remaining + // Special case if the sequence appears almost totaly static + // as measured by the decay accumulator. In this case we want to + // spend almost all of the bits on the key frame. + // cpi->twopass.frames_to_key-1 because key frame itself is taken + // care of by kf_boost. + if ( decay_accumulator >= 0.99 ) + { + allocation_chunks = + ((cpi->twopass.frames_to_key - 1) * 10) + kf_boost; + } + else + { + allocation_chunks = + ((cpi->twopass.frames_to_key - 1) * 100) + kf_boost; + } // Normalize Altboost and allocations chunck down to prevent overflow while (kf_boost > 1000) @@ -2891,13 +2917,6 @@ static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // Calculate the number of bits to be spent on the key frame cpi->twopass.kf_bits = (int)((double)kf_boost * ((double)cpi->twopass.kf_group_bits / (double)allocation_chunks)); - // Apply an additional limit for CBR - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - if (cpi->twopass.kf_bits > ((3 * cpi->buffer_level) >> 2)) - cpi->twopass.kf_bits = (3 * cpi->buffer_level) >> 2; - } - // If the key frame is actually easier than the average for the // kf group (which does sometimes happen... eg a blank intro frame) // Then use an alternate calculation based on the kf error score @@ -2946,147 +2965,4 @@ static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // Adjust the count of total modified error left. // The count of bits left is adjusted elsewhere based on real coded frame sizes cpi->twopass.modified_error_left -= kf_group_err; - - if (cpi->oxcf.allow_spatial_resampling) - { - int resample_trigger = FALSE; - int last_kf_resampled = FALSE; - int kf_q; - int scale_val = 0; - int hr, hs, vr, vs; - int new_width = cpi->oxcf.Width; - int new_height = cpi->oxcf.Height; - - int projected_buffer_level = cpi->buffer_level; - int tmp_q; - - double projected_bits_perframe; - double group_iiratio = (kf_group_intra_err - first_frame.intra_error) / (kf_group_coded_err - first_frame.coded_error); - double err_per_frame = kf_group_err / cpi->twopass.frames_to_key; - double bits_per_frame; - double av_bits_per_frame; - double effective_size_ratio; - - if ((cpi->common.Width != cpi->oxcf.Width) || (cpi->common.Height != cpi->oxcf.Height)) - last_kf_resampled = TRUE; - - // Set back to unscaled by defaults - cpi->common.horiz_scale = NORMAL; - cpi->common.vert_scale = NORMAL; - - // Calculate Average bits per frame. - //av_bits_per_frame = cpi->twopass.bits_left/(double)(cpi->twopass.total_stats->count - cpi->common.current_video_frame); - av_bits_per_frame = cpi->oxcf.target_bandwidth / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.frame_rate); - //if ( av_bits_per_frame < 0.0 ) - // av_bits_per_frame = 0.0 - - // CBR... Use the clip average as the target for deciding resample - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - bits_per_frame = av_bits_per_frame; - } - - // In VBR we want to avoid downsampling in easy section unless we are under extreme pressure - // So use the larger of target bitrate for this sectoion or average bitrate for sequence - else - { - bits_per_frame = cpi->twopass.kf_group_bits / cpi->twopass.frames_to_key; // This accounts for how hard the section is... - - if (bits_per_frame < av_bits_per_frame) // Dont turn to resampling in easy sections just because they have been assigned a small number of bits - bits_per_frame = av_bits_per_frame; - } - - // bits_per_frame should comply with our minimum - if (bits_per_frame < (cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100)) - bits_per_frame = (cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); - - // Work out if spatial resampling is necessary - kf_q = estimate_kf_group_q(cpi, err_per_frame, bits_per_frame, group_iiratio); - - // If we project a required Q higher than the maximum allowed Q then make a guess at the actual size of frames in this section - projected_bits_perframe = bits_per_frame; - tmp_q = kf_q; - - while (tmp_q > cpi->worst_quality) - { - projected_bits_perframe *= 1.04; - tmp_q--; - } - - // Guess at buffer level at the end of the section - projected_buffer_level = cpi->buffer_level - (int)((projected_bits_perframe - av_bits_per_frame) * cpi->twopass.frames_to_key); - - if (0) - { - FILE *f = fopen("Subsamle.stt", "a"); - fprintf(f, " %8d %8d %8d %8d %12.0f %8d %8d %8d\n", cpi->common.current_video_frame, kf_q, cpi->common.horiz_scale, cpi->common.vert_scale, kf_group_err / cpi->twopass.frames_to_key, (int)(cpi->twopass.kf_group_bits / cpi->twopass.frames_to_key), new_height, new_width); - fclose(f); - } - - // The trigger for spatial resampling depends on the various parameters such as whether we are streaming (CBR) or VBR. - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - // Trigger resample if we are projected to fall below down sample level or - // resampled last time and are projected to remain below the up sample level - if ((projected_buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100)) || - (last_kf_resampled && (projected_buffer_level < (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100)))) - //( ((cpi->buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100))) && - // ((projected_buffer_level < (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100))) )) - resample_trigger = TRUE; - else - resample_trigger = FALSE; - } - else - { - int64_t clip_bits = (int64_t)(cpi->twopass.total_stats->count * cpi->oxcf.target_bandwidth / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.frame_rate)); - int64_t over_spend = cpi->oxcf.starting_buffer_level - cpi->buffer_level; - - if ((last_kf_resampled && (kf_q > cpi->worst_quality)) || // If triggered last time the threshold for triggering again is reduced - ((kf_q > cpi->worst_quality) && // Projected Q higher than allowed and ... - (over_spend > clip_bits / 20))) // ... Overspend > 5% of total bits - resample_trigger = TRUE; - else - resample_trigger = FALSE; - - } - - if (resample_trigger) - { - while ((kf_q >= cpi->worst_quality) && (scale_val < 6)) - { - scale_val ++; - - cpi->common.vert_scale = vscale_lookup[scale_val]; - cpi->common.horiz_scale = hscale_lookup[scale_val]; - - Scale2Ratio(cpi->common.horiz_scale, &hr, &hs); - Scale2Ratio(cpi->common.vert_scale, &vr, &vs); - - new_width = ((hs - 1) + (cpi->oxcf.Width * hr)) / hs; - new_height = ((vs - 1) + (cpi->oxcf.Height * vr)) / vs; - - // Reducing the area to 1/4 does not reduce the complexity (err_per_frame) to 1/4... - // effective_sizeratio attempts to provide a crude correction for this - effective_size_ratio = (double)(new_width * new_height) / (double)(cpi->oxcf.Width * cpi->oxcf.Height); - effective_size_ratio = (1.0 + (3.0 * effective_size_ratio)) / 4.0; - - // Now try again and see what Q we get with the smaller image size - kf_q = estimate_kf_group_q(cpi, err_per_frame * effective_size_ratio, bits_per_frame, group_iiratio); - - if (0) - { - FILE *f = fopen("Subsamle.stt", "a"); - fprintf(f, "******** %8d %8d %8d %12.0f %8d %8d %8d\n", kf_q, cpi->common.horiz_scale, cpi->common.vert_scale, kf_group_err / cpi->twopass.frames_to_key, (int)(cpi->twopass.kf_group_bits / cpi->twopass.frames_to_key), new_height, new_width); - fclose(f); - } - } - } - - if ((cpi->common.Width != new_width) || (cpi->common.Height != new_height)) - { - cpi->common.Width = new_width; - cpi->common.Height = new_height; - vp8_alloc_compressor_data(cpi); - } - } } diff --git a/vp8/encoder/generic/csystemdependent.c b/vp8/encoder/generic/csystemdependent.c index b85827926..ebb16e3f0 100644 --- a/vp8/encoder/generic/csystemdependent.c +++ b/vp8/encoder/generic/csystemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/encoder/variance.h" #include "vp8/encoder/onyx_int.h" @@ -69,8 +69,8 @@ void vp8_cmachine_specific_config(VP8_COMP *cpi) cpi->rtcd.variance.mse16x16 = vp8_mse16x16_c; cpi->rtcd.variance.getmbss = vp8_get_mb_ss_c; - cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_c; - + cpi->rtcd.fdct.short8x8 = vp8_short_fdct8x8_c; + cpi->rtcd.fdct.haar_short2x2 = vp8_short_fhaar2x2_c; cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_c; cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_c; cpi->rtcd.fdct.fast4x4 = vp8_short_fdct4x4_c; @@ -88,19 +88,21 @@ void vp8_cmachine_specific_config(VP8_COMP *cpi) cpi->rtcd.quantize.quantb_pair = vp8_regular_quantize_b_pair; cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_c; cpi->rtcd.quantize.fastquantb_pair = vp8_fast_quantize_b_pair_c; + cpi->rtcd.quantize.quantb_8x8 = vp8_regular_quantize_b_8x8; + cpi->rtcd.quantize.fastquantb_8x8 = vp8_fast_quantize_b_8x8_c; + cpi->rtcd.quantize.quantb_2x2 = vp8_regular_quantize_b_2x2; + cpi->rtcd.quantize.fastquantb_2x2 = vp8_fast_quantize_b_2x2_c; cpi->rtcd.search.full_search = vp8_full_search_sad; cpi->rtcd.search.refining_search = vp8_refining_search_sad; cpi->rtcd.search.diamond_search = vp8_diamond_search_sad; -#if !(CONFIG_REALTIME_ONLY) cpi->rtcd.temporal.apply = vp8_temporal_filter_apply_c; -#endif #if CONFIG_INTERNAL_STATS cpi->rtcd.variance.ssimpf_8x8 = vp8_ssim_parms_8x8_c; cpi->rtcd.variance.ssimpf_16x16 = vp8_ssim_parms_16x16_c; #endif #endif - // Pure C: + cpi->rtcd.variance.satd16x16 = vp8_satd16x16_c; vp8_yv12_copy_partial_frame_ptr = vp8_yv12_copy_partial_frame; #if ARCH_X86 || ARCH_X86_64 @@ -111,12 +113,10 @@ void vp8_cmachine_specific_config(VP8_COMP *cpi) vp8_arch_arm_encoder_init(cpi); #endif -#if CONFIG_EXTEND_QRANGE cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_c; cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_c; cpi->rtcd.fdct.fast4x4 = vp8_short_fdct4x4_c; cpi->rtcd.fdct.fast8x4 = vp8_short_fdct8x4_c; cpi->rtcd.fdct.walsh_short4x4 = vp8_short_walsh4x4_c; -#endif } diff --git a/vp8/encoder/lookahead.c b/vp8/encoder/lookahead.c index b92e82bdf..b800d0136 100644 --- a/vp8/encoder/lookahead.c +++ b/vp8/encoder/lookahead.c @@ -13,7 +13,7 @@ #include "lookahead.h" #include "vp8/common/extend.h" -#define MAX_LAG_BUFFERS (CONFIG_REALTIME_ONLY? 1 : 25) +#define MAX_LAG_BUFFERS 25 struct lookahead_ctx { diff --git a/vp8/encoder/mbgraph.c b/vp8/encoder/mbgraph.c new file mode 100644 index 000000000..869562662 --- /dev/null +++ b/vp8/encoder/mbgraph.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int do_16x16_motion_iteration +( + VP8_COMP *cpi, + int_mv *ref_mv, + int_mv *dst_mv +) +{ + MACROBLOCK * const x = &cpi->mb; + MACROBLOCKD * const xd = &x->e_mbd; + BLOCK *b = &x->block[0]; + BLOCKD *d = &xd->block[0]; + vp8_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[BLOCK_16X16]; + unsigned int best_err; + int step_param, further_steps; + static int dummy_cost[2*mv_max+1]; + int *mvcost[2] = { &dummy_cost[mv_max+1], &dummy_cost[mv_max+1] }; + int *mvsadcost[2] = { &dummy_cost[mv_max+1], &dummy_cost[mv_max+1] }; +#if CONFIG_HIGH_PRECISION_MV + static int dummy_cost_hp[2*mv_max_hp+1]; + int *mvcost_hp[2] = { &dummy_cost_hp[mv_max_hp+1], &dummy_cost_hp[mv_max_hp+1] }; + int *mvsadcost_hp[2] = { &dummy_cost_hp[mv_max_hp+1], &dummy_cost_hp[mv_max_hp+1] }; +#endif + int col_min = (ref_mv->as_mv.col>>3) - MAX_FULL_PEL_VAL + ((ref_mv->as_mv.col & 7)?1:0); + int row_min = (ref_mv->as_mv.row>>3) - MAX_FULL_PEL_VAL + ((ref_mv->as_mv.row & 7)?1:0); + int col_max = (ref_mv->as_mv.col>>3) + MAX_FULL_PEL_VAL; + int row_max = (ref_mv->as_mv.row>>3) + MAX_FULL_PEL_VAL; + int tmp_col_min = x->mv_col_min; + int tmp_col_max = x->mv_col_max; + int tmp_row_min = x->mv_row_min; + int tmp_row_max = x->mv_row_max; + int_mv ref_full; + + // Further step/diamond searches as necessary + if (cpi->Speed < 8) + { + step_param = cpi->sf.first_step + ((cpi->Speed > 5) ? 1 : 0); + further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; + } + else + { + step_param = cpi->sf.first_step + 2; + further_steps = 0; + } + + /* Get intersection of UMV window and valid MV window to reduce # of checks in diamond search. */ + if (x->mv_col_min < col_min ) + x->mv_col_min = col_min; + if (x->mv_col_max > col_max ) + x->mv_col_max = col_max; + if (x->mv_row_min < row_min ) + x->mv_row_min = row_min; + if (x->mv_row_max > row_max ) + x->mv_row_max = row_max; + + ref_full.as_mv.col = ref_mv->as_mv.col >> 3; + ref_full.as_mv.row = ref_mv->as_mv.row >> 3; + + /*cpi->sf.search_method == HEX*/ + best_err = vp8_hex_search(x, b, d, + &ref_full, dst_mv, + step_param, + x->errorperbit, + &v_fn_ptr, +#if CONFIG_HIGH_PRECISION_MV + xd->allow_high_precision_mv?mvsadcost_hp:mvsadcost, xd->allow_high_precision_mv?mvcost_hp:mvcost, +#else + mvsadcost, mvcost, +#endif + ref_mv); + + // Try sub-pixel MC + //if (bestsme > error_thresh && bestsme < INT_MAX) + { + int distortion; + unsigned int sse; + best_err = cpi->find_fractional_mv_step(x, b, d, + dst_mv, ref_mv, + x->errorperbit, &v_fn_ptr, +#if CONFIG_HIGH_PRECISION_MV + xd->allow_high_precision_mv?mvcost_hp:mvcost, +#else + mvcost, +#endif + &distortion, &sse); + } + + vp8_set_mbmode_and_mvs(x, NEWMV, dst_mv); + vp8_build_inter16x16_predictors_mby(xd); + //VARIANCE_INVOKE(&cpi->rtcd.variance, satd16x16) + best_err = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x16) + (xd->dst.y_buffer, xd->dst.y_stride, + xd->predictor, 16, &best_err); + + /* restore UMV window */ + x->mv_col_min = tmp_col_min; + x->mv_col_max = tmp_col_max; + x->mv_row_min = tmp_row_min; + x->mv_row_max = tmp_row_max; + + return best_err; +} + +static int do_16x16_motion_search +( + VP8_COMP *cpi, + int_mv *ref_mv, + int_mv *dst_mv, + YV12_BUFFER_CONFIG *buf, + int buf_mb_y_offset, + YV12_BUFFER_CONFIG *ref, + int mb_y_offset +) +{ + MACROBLOCK * const x = &cpi->mb; + MACROBLOCKD * const xd = &x->e_mbd; + unsigned int err, tmp_err; + int_mv tmp_mv; + int n; + + for (n = 0; n < 16; n++) { + BLOCKD *d = &xd->block[n]; + BLOCK *b = &x->block[n]; + + b->base_src = &buf->y_buffer; + b->src_stride = buf->y_stride; + b->src = buf->y_stride * (n & 12) + (n & 3) * 4 + buf_mb_y_offset; + + d->base_pre = &ref->y_buffer; + d->pre_stride = ref->y_stride; + d->pre = ref->y_stride * (n & 12) + (n & 3) * 4 + mb_y_offset; + } + + // Try zero MV first + // FIXME should really use something like near/nearest MV and/or MV prediction + xd->pre.y_buffer = ref->y_buffer + mb_y_offset; + xd->pre.y_stride = ref->y_stride; + //VARIANCE_INVOKE(&cpi->rtcd.variance, satd16x16) + err = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x16) + (ref->y_buffer + mb_y_offset, + ref->y_stride, xd->dst.y_buffer, + xd->dst.y_stride, &err); + dst_mv->as_int = 0; + + // Test last reference frame using the previous best mv as the + // starting point (best reference) for the search + tmp_err = do_16x16_motion_iteration(cpi, ref_mv, &tmp_mv); + if (tmp_err < err) + { + err = tmp_err; + dst_mv->as_int = tmp_mv.as_int; + } + + // If the current best reference mv is not centred on 0,0 then do a 0,0 based search as well + if (ref_mv->as_int) + { + int tmp_err; + int_mv zero_ref_mv, tmp_mv; + + zero_ref_mv.as_int = 0; + tmp_err = do_16x16_motion_iteration(cpi, &zero_ref_mv, &tmp_mv); + if (tmp_err < err) + { + dst_mv->as_int = tmp_mv.as_int; + err = tmp_err; + } + } + + return err; +} + +static int do_16x16_zerozero_search +( + VP8_COMP *cpi, + int_mv *dst_mv, + YV12_BUFFER_CONFIG *buf, + int buf_mb_y_offset, + YV12_BUFFER_CONFIG *ref, + int mb_y_offset +) +{ + MACROBLOCK * const x = &cpi->mb; + MACROBLOCKD * const xd = &x->e_mbd; + unsigned int err; + int n; + + for (n = 0; n < 16; n++) { + BLOCKD *d = &xd->block[n]; + BLOCK *b = &x->block[n]; + + b->base_src = &buf->y_buffer; + b->src_stride = buf->y_stride; + b->src = buf->y_stride * (n & 12) + (n & 3) * 4 + buf_mb_y_offset; + + d->base_pre = &ref->y_buffer; + d->pre_stride = ref->y_stride; + d->pre = ref->y_stride * (n & 12) + (n & 3) * 4 + mb_y_offset; + } + + // Try zero MV first + // FIXME should really use something like near/nearest MV and/or MV prediction + xd->pre.y_buffer = ref->y_buffer + mb_y_offset; + xd->pre.y_stride = ref->y_stride; + //VARIANCE_INVOKE(&cpi->rtcd.variance, satd16x16) + err = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x16) + (ref->y_buffer + mb_y_offset, + ref->y_stride, xd->dst.y_buffer, + xd->dst.y_stride, &err); + + dst_mv->as_int = 0; + + return err; +} +static int find_best_16x16_intra +( + VP8_COMP *cpi, + YV12_BUFFER_CONFIG *buf, + int mb_y_offset, + MB_PREDICTION_MODE *pbest_mode +) +{ + MACROBLOCK * const x = &cpi->mb; + MACROBLOCKD * const xd = &x->e_mbd; + MB_PREDICTION_MODE best_mode = -1, mode; + int best_err = INT_MAX; + + // calculate SATD for each intra prediction mode; + // we're intentionally not doing 4x4, we just want a rough estimate + for (mode = DC_PRED; mode <= TM_PRED; mode++) + { + unsigned int err; + + xd->mode_info_context->mbmi.mode = mode; + RECON_INVOKE(&cpi->rtcd.common->recon, build_intra_predictors_mby)(xd); + //VARIANCE_INVOKE(&cpi->rtcd.variance, satd16x16) + err = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x16) + (xd->predictor, 16, + buf->y_buffer + mb_y_offset, + buf->y_stride, &err); + // find best + if (err < best_err) + { + best_err = err; + best_mode = mode; + } + } + + if (pbest_mode) + *pbest_mode = best_mode; + + return best_err; +} + +static void update_mbgraph_mb_stats +( + VP8_COMP *cpi, + MBGRAPH_MB_STATS *stats, + YV12_BUFFER_CONFIG *buf, + int mb_y_offset, + YV12_BUFFER_CONFIG *golden_ref, + int_mv *prev_golden_ref_mv, + int gld_y_offset, + YV12_BUFFER_CONFIG *alt_ref, + int_mv *prev_alt_ref_mv, + int arf_y_offset +) +{ + MACROBLOCK * const x = &cpi->mb; + MACROBLOCKD * const xd = &x->e_mbd; + int intra_error; + + // FIXME in practice we're completely ignoring chroma here + xd->dst.y_buffer = buf->y_buffer + mb_y_offset; + + // do intra 16x16 prediction + intra_error = find_best_16x16_intra(cpi, buf, mb_y_offset, &stats->ref[INTRA_FRAME].m.mode); + if (intra_error <= 0) + intra_error = 1; + stats->ref[INTRA_FRAME].err = intra_error; + + // Golden frame MV search, if it exists and is different than last frame + if (golden_ref) + { + int g_motion_error = do_16x16_motion_search(cpi, prev_golden_ref_mv, + &stats->ref[GOLDEN_FRAME].m.mv, + buf, mb_y_offset, + golden_ref, gld_y_offset); + stats->ref[GOLDEN_FRAME].err = g_motion_error; + } + else + { + stats->ref[GOLDEN_FRAME].err = INT_MAX; + stats->ref[GOLDEN_FRAME].m.mv.as_int = 0; + } + + // Alt-ref frame MV search, if it exists and is different than last/golden frame + if (alt_ref) + { + //int a_motion_error = do_16x16_motion_search(cpi, prev_alt_ref_mv, + // &stats->ref[ALTREF_FRAME].m.mv, + // buf, mb_y_offset, + // alt_ref, arf_y_offset); + + int a_motion_error = + do_16x16_zerozero_search( cpi, + &stats->ref[ALTREF_FRAME].m.mv, + buf, mb_y_offset, + alt_ref, arf_y_offset); + + stats->ref[ALTREF_FRAME].err = a_motion_error; + } + else + { + stats->ref[ALTREF_FRAME].err = INT_MAX; + stats->ref[ALTREF_FRAME].m.mv.as_int = 0; + } +} + +static void update_mbgraph_frame_stats +( + VP8_COMP *cpi, + MBGRAPH_FRAME_STATS *stats, + YV12_BUFFER_CONFIG *buf, + YV12_BUFFER_CONFIG *golden_ref, + YV12_BUFFER_CONFIG *alt_ref +) +{ + MACROBLOCK * const x = &cpi->mb; + VP8_COMMON * const cm = &cpi->common; + MACROBLOCKD * const xd = &x->e_mbd; + int mb_col, mb_row, offset = 0; + int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0; + int_mv arf_top_mv, gld_top_mv; + MODE_INFO mi_local; + + // Set up limit values for motion vectors to prevent them extending outside the UMV borders + arf_top_mv.as_int = 0; + gld_top_mv.as_int = 0; + x->mv_row_min = -(VP8BORDERINPIXELS - 16 - INTERP_EXTEND); + x->mv_row_max = (cm->mb_rows - 1) * 16 + VP8BORDERINPIXELS - 16 - INTERP_EXTEND; + xd->up_available = 0; + xd->dst.y_stride = buf->y_stride; + xd->pre.y_stride = buf->y_stride; + xd->dst.uv_stride = buf->uv_stride; + xd->mode_info_context = &mi_local; + + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + int_mv arf_left_mv, gld_left_mv; + int mb_y_in_offset = mb_y_offset; + int arf_y_in_offset = arf_y_offset; + int gld_y_in_offset = gld_y_offset; + + // Set up limit values for motion vectors to prevent them extending outside the UMV borders + arf_left_mv.as_int = arf_top_mv.as_int; + gld_left_mv.as_int = gld_top_mv.as_int; + x->mv_col_min = -(VP8BORDERINPIXELS - 16 - INTERP_EXTEND); + x->mv_col_max = (cm->mb_cols - 1) * 16 + VP8BORDERINPIXELS - 16 - INTERP_EXTEND; + xd->left_available = 0; + + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col]; + + update_mbgraph_mb_stats(cpi, mb_stats, buf, mb_y_in_offset, + golden_ref, &gld_left_mv, gld_y_in_offset, + alt_ref, &arf_left_mv, arf_y_in_offset); + arf_left_mv.as_int = mb_stats->ref[ALTREF_FRAME].m.mv.as_int; + gld_left_mv.as_int = mb_stats->ref[GOLDEN_FRAME].m.mv.as_int; + if (mb_col == 0) + { + arf_top_mv.as_int = arf_left_mv.as_int; + gld_top_mv.as_int = gld_left_mv.as_int; + } + xd->left_available = 1; + mb_y_in_offset += 16; + gld_y_in_offset += 16; + arf_y_in_offset += 16; + x->mv_col_min -= 16; + x->mv_col_max -= 16; + } + xd->up_available = 1; + mb_y_offset += buf->y_stride * 16; + gld_y_offset += golden_ref->y_stride * 16; + if (alt_ref) + arf_y_offset += alt_ref->y_stride * 16; + x->mv_row_min -= 16; + x->mv_row_max -= 16; + offset += cm->mb_cols; + } +} + +// Test for small magnitude (<= 1 pel mvs) +int small_mv( MV mv ) +{ + if ( (abs( (int)mv.col ) > 2) || (abs( (int)mv.row ) > 2) ) + return FALSE; + else + return TRUE; +} + +//void separate_arf_mbs_byzz +void separate_arf_mbs +( + VP8_COMP *cpi +) +{ + VP8_COMMON * const cm = &cpi->common; + int mb_col, mb_row, offset, i; + int ncnt[4]; + int n_frames = cpi->mbgraph_n_frames; + + int * arf_not_zz; + + CHECK_MEM_ERROR(arf_not_zz, + vpx_calloc(cm->mb_rows * cm->mb_cols * sizeof(*arf_not_zz), 1)); + + vpx_memset(arf_not_zz, 0, sizeof(arf_not_zz)); + + // We are not interested in results beyond the alt ref itself. + if ( n_frames > cpi->frames_till_gf_update_due ) + n_frames = cpi->frames_till_gf_update_due; + + // defer cost to reference frames + for (i = n_frames - 1; i >= 0; i--) + { + MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i]; + + for (offset = 0, mb_row = 0; mb_row < cm->mb_rows; + offset += cm->mb_cols, mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + MBGRAPH_MB_STATS *mb_stats = + &frame_stats->mb_stats[offset + mb_col]; + + int altref_err = mb_stats->ref[ALTREF_FRAME].err; + + int intra_err = + mb_stats->ref[INTRA_FRAME ].err + 250; + + int golden_err = + mb_stats->ref[GOLDEN_FRAME].err + 250; + + // Test for altref vs intra and gf and that its mv was 0,0. + if ( (altref_err > 1000) || + (altref_err > intra_err) || + (altref_err > golden_err) ) + { + arf_not_zz[offset + mb_col]++; + } + } + } + } + + vpx_memset(ncnt, 0, sizeof(ncnt)); + for (offset = 0, mb_row = 0; mb_row < cm->mb_rows; + offset += cm->mb_cols, mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + // If any of the blocks in the sequence failed then the MB + // goes in segment 0 + if ( arf_not_zz[offset + mb_col] ) + { + ncnt[0]++; + cpi->segmentation_map[offset + mb_col] = 0; + } + else + { + ncnt[1]++; + cpi->segmentation_map[offset + mb_col] = 1; + } + } + } + + // Only bother with segmentation if over 10% of the MBs in static segment + //if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) ) + if ( 1 ) + { + // Note % of blocks that are marked as static + if ( cm->MBs ) + cpi->static_mb_pct = (ncnt[1] * 100) / cm->MBs; + + // This error case should not be reachable as this function should + // never be called with the common data structure unititialized. + else + cpi->static_mb_pct = 0; + + vp8_enable_segmentation((VP8_PTR) cpi); + } + else + { + cpi->static_mb_pct = 0; + vp8_disable_segmentation((VP8_PTR) cpi); + } + + // Free localy allocated storage + vpx_free(arf_not_zz); +} + +void vp8_update_mbgraph_stats +( + VP8_COMP *cpi +) +{ + VP8_COMMON * const cm = &cpi->common; + int i, n_frames = vp8_lookahead_depth(cpi->lookahead); + YV12_BUFFER_CONFIG *golden_ref = &cm->yv12_fb[cm->gld_fb_idx]; + + // we need to look ahead beyond where the ARF transitions into + // being a GF - so exit if we don't look ahead beyond that + if (n_frames <= cpi->frames_till_gf_update_due) + return; + if (n_frames > MAX_LAG_BUFFERS) + n_frames = MAX_LAG_BUFFERS; + + cpi->mbgraph_n_frames = n_frames; + for (i = 0; i < n_frames; i++) + { + MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i]; + vpx_memset(frame_stats->mb_stats, 0, + cm->mb_rows * cm->mb_cols * sizeof(*cpi->mbgraph_stats[i].mb_stats)); + } + + // do motion search to find contribution of each reference to data + // later on in this GF group + // FIXME really, the GF/last MC search should be done forward, and + // the ARF MC search backwards, to get optimal results for MV caching + for (i = 0; i < n_frames; i++) + { + MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i]; + struct lookahead_entry *q_cur = + vp8_lookahead_peek(cpi->lookahead, i); + + assert(q_cur != NULL); + + update_mbgraph_frame_stats(cpi, frame_stats, &q_cur->img, + golden_ref, cpi->Source); + } + + vp8_clear_system_state(); //__asm emms; + + separate_arf_mbs(cpi); +} diff --git a/vp8/encoder/mbgraph.h b/vp8/encoder/mbgraph.h new file mode 100644 index 000000000..11ff3e2f0 --- /dev/null +++ b/vp8/encoder/mbgraph.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef __INC_MBGRAPH_H__ +#define __INC_MBGRAPH_H__ 1 + +extern void vp8_update_mbgraph_stats(VP8_COMP *cpi); + +#endif /* __INC_MBGRAPH_H__ */ diff --git a/vp8/encoder/mcomp.c b/vp8/encoder/mcomp.c index c1a0ea7bf..f07d18b49 100644 --- a/vp8/encoder/mcomp.c +++ b/vp8/encoder/mcomp.c @@ -11,7 +11,7 @@ #include "mcomp.h" #include "vpx_mem/vpx_mem.h" -#include "vpx_config.h" +#include "vpx_ports/config.h" #include #include #include @@ -22,6 +22,16 @@ static int mv_ref_ct [31] [4] [2]; static int mv_mode_cts [4] [2]; #endif +#if CONFIG_HIGH_PRECISION_MV +int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight, int ishp) +{ + // MV costing is based on the distribution of vectors in the previous frame and as such will tend to + // over state the cost of vectors. In addition coding a new vector can have a knock on effect on the + // cost of subsequent vectors and the quality of prediction from NEAR and NEAREST for subsequent blocks. + // The "Weight" parameter allows, to a limited extent, for some account to be taken of these factors. + return ((mvcost[0][(mv->as_mv.row - ref->as_mv.row) >> (ishp==0)] + mvcost[1][(mv->as_mv.col - ref->as_mv.col) >> (ishp==0)]) * Weight) >> 7; +} +#else int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight) { // MV costing is based on the distribution of vectors in the previous frame and as such will tend to @@ -30,13 +40,24 @@ int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight) // The "Weight" parameter allows, to a limited extent, for some account to be taken of these factors. return ((mvcost[0][(mv->as_mv.row - ref->as_mv.row) >> 1] + mvcost[1][(mv->as_mv.col - ref->as_mv.col) >> 1]) * Weight) >> 7; } +#endif +#if CONFIG_HIGH_PRECISION_MV +static int mv_err_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int error_per_bit, int ishp) +{ + return ((mvcost[0][(mv->as_mv.row - ref->as_mv.row) >> (ishp==0)] + + mvcost[1][(mv->as_mv.col - ref->as_mv.col) >> (ishp==0)]) + * error_per_bit + 128) >> 8; +} +#else static int mv_err_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int error_per_bit) { return ((mvcost[0][(mv->as_mv.row - ref->as_mv.row) >> 1] + mvcost[1][(mv->as_mv.col - ref->as_mv.col) >> 1]) * error_per_bit + 128) >> 8; } +#endif + static int mvsad_err_cost(int_mv *mv, int_mv *ref, int *mvsadcost[2], int error_per_bit) { @@ -46,6 +67,7 @@ static int mvsad_err_cost(int_mv *mv, int_mv *ref, int *mvsadcost[2], int error_ * error_per_bit + 128) >> 8; } + void vp8_init_dsmotion_compensation(MACROBLOCK *x, int stride) { int Len; @@ -175,13 +197,32 @@ void vp8_init3smotion_compensation(MACROBLOCK *x, int stride) * 32 cols area that is enough for 16x16 macroblock. Later, for SPLITMV, we * could reduce the area. */ -#define MVC(r,c) (((mvcost[0][(r)-rr] + mvcost[1][(c) - rc]) * error_per_bit + 128 )>>8 ) // estimated cost of a motion vector (r,c) + #define PRE(r,c) (y + (((r)>>2) * y_stride + ((c)>>2) -(offset))) // pointer to predictor base of a motionvector +#if CONFIG_SIXTEENTH_SUBPEL_UV +#define SP(x) (((x)&3)<<2) // convert motion vector component to offset for svf calc +#else #define SP(x) (((x)&3)<<1) // convert motion vector component to offset for svf calc +#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */ +#define MVC(r,c) (((mvcost[0][(r)-rr] + mvcost[1][(c)-rc]) * error_per_bit + 128 )>>8 ) // estimated cost of a motion vector (r,c) #define DIST(r,c) vfp->svf( PRE(r,c), y_stride, SP(c),SP(r), z,b->src_stride,&sse) // returns subpixel variance error function. -#define IFMVCV(r,c,s,e) if ( c >= minc && c <= maxc && r >= minr && r <= maxr) s else e; #define ERR(r,c) (MVC(r,c)+DIST(r,c)) // returns distortion + motion vector cost +#define IFMVCV(r,c,s,e) if ( c >= minc && c <= maxc && r >= minr && r <= maxr) s else e; + +#if CONFIG_HIGH_PRECISION_MV +#define PREHP(r,c) (y + (((r)>>3) * y_stride + ((c)>>3) -(offset))) // pointer to predictor base of a motionvector +#if CONFIG_SIXTEENTH_SUBPEL_UV +#define SPHP(x) (((x)&7)<<1) // convert motion vector component to offset for svf calc +#else /* CONFIG_SIXTEENTH_SUBPEL_UV */ +#define SPHP(x) ((x)&7) // convert motion vector component to offset for svf calc +#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */ +#define DISTHP(r,c) vfp->svf( PREHP(r,c), y_stride, SPHP(c),SPHP(r), z,b->src_stride,&sse) // returns subpixel variance error function. +#define ERRHP(r,c) (MVC(r,c)+DISTHP(r,c)) // returns distortion + motion vector cost +#define CHECK_BETTER(v,r,c) IFMVCV(r,c,{thismse = ((xd->allow_high_precision_mv)?DISTHP(r,c):DIST(r,c)); if((v = (MVC(r,c)+thismse)) < besterr) { besterr = v; br=r; bc=c; *distortion = thismse; *sse1 = sse; }}, v=INT_MAX;)// checks if (r,c) has better score than previous best +#else #define CHECK_BETTER(v,r,c) IFMVCV(r,c,{thismse = DIST(r,c); if((v = (MVC(r,c)+thismse)) < besterr) { besterr = v; br=r; bc=c; *distortion = thismse; *sse1 = sse; }}, v=INT_MAX;)// checks if (r,c) has better score than previous best +#endif /* CONFIG_HIGH_PRECISION_MV */ + #define MIN(x,y) (((x)<(y))?(x):(y)) #define MAX(x,y) (((x)>(y))?(x):(y)) @@ -193,37 +234,34 @@ int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, unsigned int *sse1) { unsigned char *z = (*(b->base_src) + b->src); + MACROBLOCKD *xd = &x->e_mbd; - int rr = ref_mv->as_mv.row >> 1, rc = ref_mv->as_mv.col >> 1; - int br = bestmv->as_mv.row << 2, bc = bestmv->as_mv.col << 2; - int tr = br, tc = bc; + int rr, rc, br, bc, hstep; + int tr, tc; unsigned int besterr = INT_MAX; unsigned int left, right, up, down, diag; unsigned int sse; unsigned int whichdir; unsigned int halfiters = 4; unsigned int quarteriters = 4; +#if CONFIG_HIGH_PRECISION_MV + unsigned int eighthiters = 4; +#endif int thismse; - - int minc = MAX(x->mv_col_min << 2, (ref_mv->as_mv.col >> 1) - ((1 << mvlong_width) - 1)); - int maxc = MIN(x->mv_col_max << 2, (ref_mv->as_mv.col >> 1) + ((1 << mvlong_width) - 1)); - int minr = MAX(x->mv_row_min << 2, (ref_mv->as_mv.row >> 1) - ((1 << mvlong_width) - 1)); - int maxr = MIN(x->mv_row_max << 2, (ref_mv->as_mv.row >> 1) + ((1 << mvlong_width) - 1)); - + int maxc, minc, maxr, minr; int y_stride; int offset; #if ARCH_X86 || ARCH_X86_64 - MACROBLOCKD *xd = &x->e_mbd; unsigned char *y0 = *(d->base_pre) + d->pre + (bestmv->as_mv.row) * d->pre_stride + bestmv->as_mv.col; unsigned char *y; int buf_r1, buf_r2, buf_c1, buf_c2; // Clamping to avoid out-of-range data access - buf_r1 = ((bestmv->as_mv.row - 3) < x->mv_row_min)?(bestmv->as_mv.row - x->mv_row_min):3; - buf_r2 = ((bestmv->as_mv.row + 3) > x->mv_row_max)?(x->mv_row_max - bestmv->as_mv.row):3; - buf_c1 = ((bestmv->as_mv.col - 3) < x->mv_col_min)?(bestmv->as_mv.col - x->mv_col_min):3; - buf_c2 = ((bestmv->as_mv.col + 3) > x->mv_col_max)?(x->mv_col_max - bestmv->as_mv.col):3; + buf_r1 = ((bestmv->as_mv.row - INTERP_EXTEND) < x->mv_row_min)?(bestmv->as_mv.row - x->mv_row_min):INTERP_EXTEND; + buf_r2 = ((bestmv->as_mv.row + INTERP_EXTEND) > x->mv_row_max)?(x->mv_row_max - bestmv->as_mv.row):INTERP_EXTEND; + buf_c1 = ((bestmv->as_mv.col - INTERP_EXTEND) < x->mv_col_min)?(bestmv->as_mv.col - x->mv_col_min):INTERP_EXTEND; + buf_c2 = ((bestmv->as_mv.col + INTERP_EXTEND) > x->mv_col_max)?(x->mv_col_max - bestmv->as_mv.col):INTERP_EXTEND; y_stride = 32; /* Copy to intermediate buffer before searching. */ @@ -234,6 +272,34 @@ int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, y_stride = d->pre_stride; #endif + +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + { + rr = ref_mv->as_mv.row; rc = ref_mv->as_mv.col; + br = bestmv->as_mv.row << 3; bc = bestmv->as_mv.col << 3; + hstep = 4; + minc = MAX(x->mv_col_min << 3, (ref_mv->as_mv.col) - ((1 << mvlong_width_hp) - 1)); + maxc = MIN(x->mv_col_max << 3, (ref_mv->as_mv.col) + ((1 << mvlong_width_hp) - 1)); + minr = MAX(x->mv_row_min << 3, (ref_mv->as_mv.row) - ((1 << mvlong_width_hp) - 1)); + maxr = MIN(x->mv_row_max << 3, (ref_mv->as_mv.row) + ((1 << mvlong_width_hp) - 1)); + } + else +#endif + { + rr = ref_mv->as_mv.row >> 1; rc = ref_mv->as_mv.col >> 1; + br = bestmv->as_mv.row << 2; bc = bestmv->as_mv.col << 2; + hstep = 2; + minc = MAX(x->mv_col_min << 2, (ref_mv->as_mv.col >> 1) - ((1 << mvlong_width) - 1)); + maxc = MIN(x->mv_col_max << 2, (ref_mv->as_mv.col >> 1) + ((1 << mvlong_width) - 1)); + minr = MAX(x->mv_row_min << 2, (ref_mv->as_mv.row >> 1) - ((1 << mvlong_width) - 1)); + maxr = MIN(x->mv_row_max << 2, (ref_mv->as_mv.row >> 1) + ((1 << mvlong_width) - 1)); + } + + tr = br; + tc = bc; + + offset = (bestmv->as_mv.row) * y_stride + bestmv->as_mv.col; // central mv @@ -243,32 +309,36 @@ int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, // calculate central point error besterr = vfp->vf(y, y_stride, z, b->src_stride, sse1); *distortion = besterr; +#if CONFIG_HIGH_PRECISION_MV + besterr += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else besterr += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); +#endif // TODO: Each subsequent iteration checks at least one point in common with the last iteration could be 2 ( if diag selected) while (--halfiters) { // 1/2 pel - CHECK_BETTER(left, tr, tc - 2); - CHECK_BETTER(right, tr, tc + 2); - CHECK_BETTER(up, tr - 2, tc); - CHECK_BETTER(down, tr + 2, tc); + CHECK_BETTER(left, tr, tc - hstep); + CHECK_BETTER(right, tr, tc + hstep); + CHECK_BETTER(up, tr - hstep, tc); + CHECK_BETTER(down, tr + hstep, tc); whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); switch (whichdir) { case 0: - CHECK_BETTER(diag, tr - 2, tc - 2); + CHECK_BETTER(diag, tr - hstep, tc - hstep); break; case 1: - CHECK_BETTER(diag, tr - 2, tc + 2); + CHECK_BETTER(diag, tr - hstep, tc + hstep); break; case 2: - CHECK_BETTER(diag, tr + 2, tc - 2); + CHECK_BETTER(diag, tr + hstep, tc - hstep); break; case 3: - CHECK_BETTER(diag, tr + 2, tc + 2); + CHECK_BETTER(diag, tr + hstep, tc + hstep); break; } @@ -282,28 +352,29 @@ int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, // TODO: Each subsequent iteration checks at least one point in common with the last iteration could be 2 ( if diag selected) // 1/4 pel + hstep >>= 1; while (--quarteriters) { - CHECK_BETTER(left, tr, tc - 1); - CHECK_BETTER(right, tr, tc + 1); - CHECK_BETTER(up, tr - 1, tc); - CHECK_BETTER(down, tr + 1, tc); + CHECK_BETTER(left, tr, tc - hstep); + CHECK_BETTER(right, tr, tc + hstep); + CHECK_BETTER(up, tr - hstep, tc); + CHECK_BETTER(down, tr + hstep, tc); whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); switch (whichdir) { case 0: - CHECK_BETTER(diag, tr - 1, tc - 1); + CHECK_BETTER(diag, tr - hstep, tc - hstep); break; case 1: - CHECK_BETTER(diag, tr - 1, tc + 1); + CHECK_BETTER(diag, tr - hstep, tc + hstep); break; case 2: - CHECK_BETTER(diag, tr + 1, tc - 1); + CHECK_BETTER(diag, tr + hstep, tc - hstep); break; case 3: - CHECK_BETTER(diag, tr + 1, tc + 1); + CHECK_BETTER(diag, tr + hstep, tc + hstep); break; } @@ -315,8 +386,56 @@ int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, tc = bc; } - bestmv->as_mv.row = br << 1; - bestmv->as_mv.col = bc << 1; +#if CONFIG_HIGH_PRECISION_MV + if (x->e_mbd.allow_high_precision_mv) + { + hstep >>= 1; + while (--eighthiters) + { + CHECK_BETTER(left, tr, tc - hstep); + CHECK_BETTER(right, tr, tc + hstep); + CHECK_BETTER(up, tr - hstep, tc); + CHECK_BETTER(down, tr + hstep, tc); + + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + + switch (whichdir) + { + case 0: + CHECK_BETTER(diag, tr - hstep, tc - hstep); + break; + case 1: + CHECK_BETTER(diag, tr - hstep, tc + hstep); + break; + case 2: + CHECK_BETTER(diag, tr + hstep, tc - hstep); + break; + case 3: + CHECK_BETTER(diag, tr + hstep, tc + hstep); + break; + } + + // no reason to check the same one again. + if (tr == br && tc == bc) + break; + + tr = br; + tc = bc; + } + } +#endif +#if CONFIG_HIGH_PRECISION_MV + if (x->e_mbd.allow_high_precision_mv) + { + bestmv->as_mv.row = br; + bestmv->as_mv.col = bc; + } + else +#endif /* CONFIG_HIGH_PRECISION_MV */ + { + bestmv->as_mv.row = br << 1; + bestmv->as_mv.col = bc << 1; + } if ((abs(bestmv->as_mv.col - ref_mv->as_mv.col) > (MAX_FULL_PEL_VAL<<3)) || (abs(bestmv->as_mv.row - ref_mv->as_mv.row) > (MAX_FULL_PEL_VAL<<3))) @@ -333,6 +452,19 @@ int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, #undef CHECK_BETTER #undef MIN #undef MAX + +#if CONFIG_HIGH_PRECISION_MV +#undef PREHP +#undef DPHP +#undef DISTHP +#undef ERRHP +#endif + +#if CONFIG_SIXTEENTH_SUBPEL_UV +#define SP(x) (((x)&7)<<1) // convert motion vector component to offset for svf calc +#else +#define SP(x) ((x)&7) // convert motion vector component to offset for svf calc +#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *bestmv, int_mv *ref_mv, int error_per_bit, @@ -343,15 +475,19 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int bestmse = INT_MAX; int_mv startmv; int_mv this_mv; +#if CONFIG_HIGH_PRECISION_MV + int_mv orig_mv; + int yrow_movedback=0, ycol_movedback=0; +#endif unsigned char *z = (*(b->base_src) + b->src); int left, right, up, down, diag; unsigned int sse; int whichdir ; int thismse; int y_stride; + MACROBLOCKD *xd = &x->e_mbd; #if ARCH_X86 || ARCH_X86_64 - MACROBLOCKD *xd = &x->e_mbd; unsigned char *y0 = *(d->base_pre) + d->pre + (bestmv->as_mv.row) * d->pre_stride + bestmv->as_mv.col; unsigned char *y; @@ -368,17 +504,28 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, bestmv->as_mv.row <<= 3; bestmv->as_mv.col <<= 3; startmv = *bestmv; +#if CONFIG_HIGH_PRECISION_MV + orig_mv = *bestmv; +#endif // calculate central point error bestmse = vfp->vf(y, y_stride, z, b->src_stride, sse1); *distortion = bestmse; +#if CONFIG_HIGH_PRECISION_MV + bestmse += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else bestmse += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); +#endif // go left then right and check error this_mv.as_mv.row = startmv.as_mv.row; this_mv.as_mv.col = ((startmv.as_mv.col - 8) | 4); thismse = vfp->svf_halfpix_h(y - 1, y_stride, z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (left < bestmse) { @@ -390,7 +537,11 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, this_mv.as_mv.col += 8; thismse = vfp->svf_halfpix_h(y, y_stride, z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (right < bestmse) { @@ -404,7 +555,11 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, this_mv.as_mv.col = startmv.as_mv.col; this_mv.as_mv.row = ((startmv.as_mv.row - 8) | 4); thismse = vfp->svf_halfpix_v(y - y_stride, y_stride, z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (up < bestmse) { @@ -416,7 +571,11 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, this_mv.as_mv.row += 8; thismse = vfp->svf_halfpix_v(y, y_stride, z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (down < bestmse) { @@ -458,7 +617,11 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, break; } +#if CONFIG_HIGH_PRECISION_MV + diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (diag < bestmse) { @@ -473,10 +636,20 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, // time to check quarter pels. if (bestmv->as_mv.row < startmv.as_mv.row) + { y -= y_stride; +#if CONFIG_HIGH_PRECISION_MV + yrow_movedback = 1; +#endif + } if (bestmv->as_mv.col < startmv.as_mv.col) + { y--; +#if CONFIG_HIGH_PRECISION_MV + ycol_movedback = 1; +#endif + } startmv = *bestmv; @@ -488,15 +661,19 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, if (startmv.as_mv.col & 7) { this_mv.as_mv.col = startmv.as_mv.col - 2; - thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); } else { this_mv.as_mv.col = (startmv.as_mv.col - 8) | 6; - thismse = vfp->svf(y - 1, y_stride, 6, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y - 1, y_stride, SP(6), SP(this_mv.as_mv.row), z, b->src_stride, &sse); } +#if CONFIG_HIGH_PRECISION_MV + left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (left < bestmse) { @@ -507,8 +684,12 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, } this_mv.as_mv.col += 4; - thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (right < bestmse) { @@ -524,15 +705,19 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, if (startmv.as_mv.row & 7) { this_mv.as_mv.row = startmv.as_mv.row - 2; - thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); } else { this_mv.as_mv.row = (startmv.as_mv.row - 8) | 6; - thismse = vfp->svf(y - y_stride, y_stride, this_mv.as_mv.col & 7, 6, z, b->src_stride, &sse); + thismse = vfp->svf(y - y_stride, y_stride, SP(this_mv.as_mv.col), SP(6), z, b->src_stride, &sse); } +#if CONFIG_HIGH_PRECISION_MV + up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (up < bestmse) { @@ -543,8 +728,12 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, } this_mv.as_mv.row += 4; - thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (down < bestmse) { @@ -573,12 +762,12 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, if (startmv.as_mv.col & 7) { this_mv.as_mv.col -= 2; - thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); } else { this_mv.as_mv.col = (startmv.as_mv.col - 8) | 6; - thismse = vfp->svf(y - 1, y_stride, 6, this_mv.as_mv.row & 7, z, b->src_stride, &sse);; + thismse = vfp->svf(y - 1, y_stride, SP(6), SP(this_mv.as_mv.row), z, b->src_stride, &sse);; } } else @@ -588,12 +777,12 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, if (startmv.as_mv.col & 7) { this_mv.as_mv.col -= 2; - thismse = vfp->svf(y - y_stride, y_stride, this_mv.as_mv.col & 7, 6, z, b->src_stride, &sse); + thismse = vfp->svf(y - y_stride, y_stride, SP(this_mv.as_mv.col), SP(6), z, b->src_stride, &sse); } else { this_mv.as_mv.col = (startmv.as_mv.col - 8) | 6; - thismse = vfp->svf(y - y_stride - 1, y_stride, 6, 6, z, b->src_stride, &sse); + thismse = vfp->svf(y - y_stride - 1, y_stride, SP(6), SP(6), z, b->src_stride, &sse); } } @@ -604,12 +793,12 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, if (startmv.as_mv.row & 7) { this_mv.as_mv.row -= 2; - thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); } else { this_mv.as_mv.row = (startmv.as_mv.row - 8) | 6; - thismse = vfp->svf(y - y_stride, y_stride, this_mv.as_mv.col & 7, 6, z, b->src_stride, &sse); + thismse = vfp->svf(y - y_stride, y_stride, SP(this_mv.as_mv.col), SP(6), z, b->src_stride, &sse); } break; @@ -619,23 +808,27 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, if (startmv.as_mv.col & 7) { this_mv.as_mv.col -= 2; - thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); } else { this_mv.as_mv.col = (startmv.as_mv.col - 8) | 6; - thismse = vfp->svf(y - 1, y_stride, 6, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y - 1, y_stride, SP(6), SP(this_mv.as_mv.row), z, b->src_stride, &sse); } break; case 3: this_mv.as_mv.col += 2; this_mv.as_mv.row += 2; - thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); break; } +#if CONFIG_HIGH_PRECISION_MV + diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (diag < bestmse) { @@ -645,9 +838,195 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, *sse1 = sse; } +#if CONFIG_HIGH_PRECISION_MV + if (!x->e_mbd.allow_high_precision_mv) + return bestmse; + + /* Now do 1/8th pixel */ + if (bestmv->as_mv.row < orig_mv.as_mv.row && !yrow_movedback) + { + y -= y_stride; + yrow_movedback = 1; + } + + if (bestmv->as_mv.col < orig_mv.as_mv.col && !ycol_movedback) + { + y--; + ycol_movedback = 1; + } + + startmv = *bestmv; + + // go left then right and check error + this_mv.as_mv.row = startmv.as_mv.row; + + if (startmv.as_mv.col & 7) + { + this_mv.as_mv.col = startmv.as_mv.col - 1; + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.col = (startmv.as_mv.col - 8) | 7; + thismse = vfp->svf(y - 1, y_stride, SP(7), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + } + + left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + *distortion = thismse; + *sse1 = sse; + } + + this_mv.as_mv.col += 2; + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + *distortion = thismse; + *sse1 = sse; + } + + // go up then down and check error + this_mv.as_mv.col = startmv.as_mv.col; + + if (startmv.as_mv.row & 7) + { + this_mv.as_mv.row = startmv.as_mv.row - 1; + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.row = (startmv.as_mv.row - 8) | 7; + thismse = vfp->svf(y - y_stride, y_stride, SP(this_mv.as_mv.col), SP(7), z, b->src_stride, &sse); + } + + up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + *distortion = thismse; + *sse1 = sse; + } + + this_mv.as_mv.row += 2; + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + *distortion = thismse; + *sse1 = sse; + } + + + // now check 1 more diagonal + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + +// for(whichdir=0;whichdir<4;whichdir++) +// { + this_mv = startmv; + + switch (whichdir) + { + case 0: + + if (startmv.as_mv.row & 7) + { + this_mv.as_mv.row -= 1; + + if (startmv.as_mv.col & 7) + { + this_mv.as_mv.col -= 1; + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.col = (startmv.as_mv.col - 8) | 7; + thismse = vfp->svf(y - 1, y_stride, SP(7), SP(this_mv.as_mv.row), z, b->src_stride, &sse);; + } + } + else + { + this_mv.as_mv.row = (startmv.as_mv.row - 8) | 7; + + if (startmv.as_mv.col & 7) + { + this_mv.as_mv.col -= 1; + thismse = vfp->svf(y - y_stride, y_stride, SP(this_mv.as_mv.col), SP(7), z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.col = (startmv.as_mv.col - 8) | 7; + thismse = vfp->svf(y - y_stride - 1, y_stride, SP(7), SP(7), z, b->src_stride, &sse); + } + } + + break; + case 1: + this_mv.as_mv.col += 1; + + if (startmv.as_mv.row & 7) + { + this_mv.as_mv.row -= 1; + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.row = (startmv.as_mv.row - 8) | 7; + thismse = vfp->svf(y - y_stride, y_stride, SP(this_mv.as_mv.col), SP(7), z, b->src_stride, &sse); + } + + break; + case 2: + this_mv.as_mv.row += 1; + + if (startmv.as_mv.col & 7) + { + this_mv.as_mv.col -= 1; + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.col = (startmv.as_mv.col - 8) | 7; + thismse = vfp->svf(y - 1, y_stride, SP(7), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + } + + break; + case 3: + this_mv.as_mv.col += 1; + this_mv.as_mv.row += 1; + thismse = vfp->svf(y, y_stride, SP(this_mv.as_mv.col), SP(this_mv.as_mv.row), z, b->src_stride, &sse); + break; + } + + diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + *distortion = thismse; + *sse1 = sse; + } + +#endif /* CONFIG_HIGH_PRECISION_MV */ + return bestmse; } +#undef SP + int vp8_find_best_half_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *bestmv, int_mv *ref_mv, int error_per_bit, @@ -664,9 +1043,9 @@ int vp8_find_best_half_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int whichdir ; int thismse; int y_stride; + MACROBLOCKD *xd = &x->e_mbd; #if ARCH_X86 || ARCH_X86_64 - MACROBLOCKD *xd = &x->e_mbd; unsigned char *y0 = *(d->base_pre) + d->pre + (bestmv->as_mv.row) * d->pre_stride + bestmv->as_mv.col; unsigned char *y; @@ -687,13 +1066,21 @@ int vp8_find_best_half_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, // calculate central point error bestmse = vfp->vf(y, y_stride, z, b->src_stride, sse1); *distortion = bestmse; +#if CONFIG_HIGH_PRECISION_MV + bestmse += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else bestmse += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); +#endif // go left then right and check error this_mv.as_mv.row = startmv.as_mv.row; this_mv.as_mv.col = ((startmv.as_mv.col - 8) | 4); thismse = vfp->svf_halfpix_h(y - 1, y_stride, z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (left < bestmse) { @@ -705,7 +1092,11 @@ int vp8_find_best_half_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, this_mv.as_mv.col += 8; thismse = vfp->svf_halfpix_h(y, y_stride, z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (right < bestmse) { @@ -719,7 +1110,11 @@ int vp8_find_best_half_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, this_mv.as_mv.col = startmv.as_mv.col; this_mv.as_mv.row = ((startmv.as_mv.row - 8) | 4); thismse = vfp->svf_halfpix_v(y - y_stride, y_stride, z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (up < bestmse) { @@ -731,7 +1126,11 @@ int vp8_find_best_half_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, this_mv.as_mv.row += 8; thismse = vfp->svf_halfpix_v(y, y_stride, z, b->src_stride, &sse); +#if CONFIG_HIGH_PRECISION_MV + down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (down < bestmse) { @@ -770,7 +1169,11 @@ int vp8_find_best_half_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, break; } +#if CONFIG_HIGH_PRECISION_MV + diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit, xd->allow_high_precision_mv); +#else diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +#endif if (diag < bestmse) { @@ -854,6 +1257,7 @@ int vp8_hex_search int k = -1; int all_in; int best_site = -1; + MACROBLOCKD *xd = &x->e_mbd; int_mv fcenter_mv; fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; @@ -1035,9 +1439,18 @@ int vp8_diamond_search_sad unsigned char *check_here; int thissad; + MACROBLOCKD *xd = &x->e_mbd; int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; int_mv fcenter_mv; + +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + { + mvsadcost[0] = x->mvsadcost_hp[0]; + mvsadcost[1] = x->mvsadcost_hp[1]; + } +#endif fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; @@ -1115,7 +1528,11 @@ int vp8_diamond_search_sad return INT_MAX; return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) +#if CONFIG_HIGH_PRECISION_MV + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit, xd->allow_high_precision_mv); +#else + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +#endif } int vp8_diamond_search_sadx4 @@ -1156,9 +1573,18 @@ int vp8_diamond_search_sadx4 unsigned char *check_here; unsigned int thissad; + MACROBLOCKD *xd = &x->e_mbd; int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; int_mv fcenter_mv; + +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + { + mvsadcost[0] = x->mvsadcost_hp[0]; + mvsadcost[1] = x->mvsadcost_hp[1]; + } +#endif fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; @@ -1277,7 +1703,11 @@ int vp8_diamond_search_sadx4 return INT_MAX; return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) +#if CONFIG_HIGH_PRECISION_MV + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit, xd->allow_high_precision_mv); +#else + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +#endif } int vp8_full_search_sad(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, @@ -1298,6 +1728,7 @@ int vp8_full_search_sad(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, unsigned char *check_here; int thissad; + MACROBLOCKD *xd = &x->e_mbd; int ref_row = ref_mv->as_mv.row; int ref_col = ref_mv->as_mv.col; @@ -1309,6 +1740,14 @@ int vp8_full_search_sad(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; int_mv fcenter_mv; + +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + { + mvsadcost[0] = x->mvsadcost_hp[0]; + mvsadcost[1] = x->mvsadcost_hp[1]; + } +#endif fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; @@ -1367,7 +1806,11 @@ int vp8_full_search_sad(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, if (bestsad < INT_MAX) return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) +#if CONFIG_HIGH_PRECISION_MV + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit, xd->allow_high_precision_mv); +#else + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +#endif else return INT_MAX; } @@ -1390,6 +1833,7 @@ int vp8_full_search_sadx3(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, unsigned char *check_here; unsigned int thissad; + MACROBLOCKD *xd = &x->e_mbd; int ref_row = ref_mv->as_mv.row; int ref_col = ref_mv->as_mv.col; @@ -1403,6 +1847,14 @@ int vp8_full_search_sadx3(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; int_mv fcenter_mv; + +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + { + mvsadcost[0] = x->mvsadcost_hp[0]; + mvsadcost[1] = x->mvsadcost_hp[1]; + } +#endif fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; @@ -1497,7 +1949,11 @@ int vp8_full_search_sadx3(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, if (bestsad < INT_MAX) return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) +#if CONFIG_HIGH_PRECISION_MV + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit, xd->allow_high_precision_mv); +#else + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +#endif else return INT_MAX; } @@ -1520,6 +1976,7 @@ int vp8_full_search_sadx8(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, unsigned char *check_here; unsigned int thissad; + MACROBLOCKD *xd = &x->e_mbd; int ref_row = ref_mv->as_mv.row; int ref_col = ref_mv->as_mv.col; @@ -1534,6 +1991,14 @@ int vp8_full_search_sadx8(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; int_mv fcenter_mv; + +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + { + mvsadcost[0] = x->mvsadcost_hp[0]; + mvsadcost[1] = x->mvsadcost_hp[1]; + } +#endif fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; @@ -1657,7 +2122,11 @@ int vp8_full_search_sadx8(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, if (bestsad < INT_MAX) return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) +#if CONFIG_HIGH_PRECISION_MV + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit, xd->allow_high_precision_mv); +#else + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +#endif else return INT_MAX; } @@ -1680,10 +2149,19 @@ int vp8_refining_search_sad(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, unsigned int thissad; int_mv this_mv; unsigned int bestsad = INT_MAX; + MACROBLOCKD *xd = &x->e_mbd; int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; int_mv fcenter_mv; +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + { + mvsadcost[0] = x->mvsadcost_hp[0]; + mvsadcost[1] = x->mvsadcost_hp[1]; + } +#endif + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; @@ -1734,7 +2212,11 @@ int vp8_refining_search_sad(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, if (bestsad < INT_MAX) return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) +#if CONFIG_HIGH_PRECISION_MV + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit, xd->allow_high_precision_mv); +#else + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +#endif else return INT_MAX; } @@ -1757,10 +2239,19 @@ int vp8_refining_search_sadx4(MACROBLOCK *x, BLOCK *b, BLOCKD *d, unsigned int thissad; int_mv this_mv; unsigned int bestsad = INT_MAX; + MACROBLOCKD *xd = &x->e_mbd; int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; int_mv fcenter_mv; +#if CONFIG_HIGH_PRECISION_MV + if (xd->allow_high_precision_mv) + { + mvsadcost[0] = x->mvsadcost_hp[0]; + mvsadcost[1] = x->mvsadcost_hp[1]; + } +#endif + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; @@ -1847,46 +2338,37 @@ int vp8_refining_search_sadx4(MACROBLOCK *x, BLOCK *b, BLOCKD *d, if (bestsad < INT_MAX) return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) +#if CONFIG_HIGH_PRECISION_MV + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit, xd->allow_high_precision_mv); +#else + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +#endif else return INT_MAX; } + + #ifdef ENTROPY_STATS void print_mode_context(void) { - FILE *f = fopen("modecont.c", "w"); + FILE *f = fopen("modecont.c", "a"); int i, j; fprintf(f, "#include \"entropy.h\"\n"); - fprintf(f, "const int vp8_mode_contexts[6][4] =\n"); + fprintf(f, "const int vp8_mode_contexts[6][4] ="); fprintf(f, "{\n"); - for (j = 0; j < 6; j++) { - fprintf(f, " { // %d \n", j); + fprintf(f, " {/* %d */ ", j); fprintf(f, " "); - for (i = 0; i < 4; i++) { - int overal_prob; int this_prob; - int count; // = mv_ref_ct[j][i][0]+mv_ref_ct[j][i][1]; - - // Overall probs - count = mv_mode_cts[i][0] + mv_mode_cts[i][1]; - - if (count) - overal_prob = 256 * mv_mode_cts[i][0] / count; - else - overal_prob = 128; - - if (overal_prob == 0) - overal_prob = 1; + int count; // context probs count = mv_ref_ct[j][i][0] + mv_ref_ct[j][i][1]; - if (count) this_prob = 256 * mv_ref_ct[j][i][0] / count; else @@ -1894,12 +2376,8 @@ void print_mode_context(void) if (this_prob == 0) this_prob = 1; - fprintf(f, "%5d, ", this_prob); - //fprintf(f,"%5d, %5d, %8d,", this_prob, overal_prob, (this_prob << 10)/overal_prob); - //fprintf(f,"%8d, ", (this_prob << 10)/overal_prob); } - fprintf(f, " },\n"); } @@ -1908,7 +2386,6 @@ void print_mode_context(void) } /* MV ref count ENTROPY_STATS stats code */ -#ifdef ENTROPY_STATS void init_mv_ref_counts() { vpx_memset(mv_ref_ct, 0, sizeof(mv_ref_ct)); @@ -1963,5 +2440,3 @@ void accum_mv_refs(MB_PREDICTION_MODE m, const int ct[4]) } #endif/* END MV ref count ENTROPY_STATS stats code */ - -#endif diff --git a/vp8/encoder/mcomp.h b/vp8/encoder/mcomp.h index 416c4d5eb..f1314533f 100644 --- a/vp8/encoder/mcomp.h +++ b/vp8/encoder/mcomp.h @@ -25,8 +25,11 @@ extern void accum_mv_refs(MB_PREDICTION_MODE, const int near_mv_ref_cts[4]); #define MAX_FULL_PEL_VAL ((1 << (MAX_MVSEARCH_STEPS)) - 1) // Max full pel mv specified in 1 pel units #define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS-1)) // Maximum size of the first step in full pel units -extern void print_mode_context(void); +#if CONFIG_HIGH_PRECISION_MV +extern int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight, int ishp); +#else extern int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight); +#endif extern void vp8_init_dsmotion_compensation(MACROBLOCK *x, int stride); extern void vp8_init3smotion_compensation(MACROBLOCK *x, int stride); diff --git a/vp8/encoder/modecosts.c b/vp8/encoder/modecosts.c index c636c482b..b6f77e1a1 100644 --- a/vp8/encoder/modecosts.c +++ b/vp8/encoder/modecosts.c @@ -37,11 +37,30 @@ void vp8_init_mode_costs(VP8_COMP *c) vp8_cost_tokens((int *)c->mb.inter_bmode_costs, x->fc.bmode_prob, T); } - vp8_cost_tokens((int *)c->mb.inter_bmode_costs, x->fc.sub_mv_ref_prob, vp8_sub_mv_ref_tree); + vp8_cost_tokens((int *)c->mb.inter_bmode_costs, + x->fc.sub_mv_ref_prob, vp8_sub_mv_ref_tree); vp8_cost_tokens(c->mb.mbmode_cost[1], x->fc.ymode_prob, vp8_ymode_tree); - vp8_cost_tokens(c->mb.mbmode_cost[0], x->kf_ymode_prob, vp8_kf_ymode_tree); +#if CONFIG_QIMODE + vp8_cost_tokens(c->mb.mbmode_cost[0], + x->kf_ymode_prob[c->common.kf_ymode_probs_index], + vp8_kf_ymode_tree); +#else + vp8_cost_tokens(c->mb.mbmode_cost[0], + x->kf_ymode_prob, vp8_kf_ymode_tree); +#endif +#if CONFIG_UVINTRA + vp8_cost_tokens(c->mb.intra_uv_mode_cost[1], + x->fc.uv_mode_prob[VP8_YMODES-1], vp8_uv_mode_tree); + vp8_cost_tokens(c->mb.intra_uv_mode_cost[0], + x->kf_uv_mode_prob[VP8_YMODES-1], vp8_uv_mode_tree); +#else + vp8_cost_tokens(c->mb.intra_uv_mode_cost[1], + x->fc.uv_mode_prob, vp8_uv_mode_tree); + vp8_cost_tokens(c->mb.intra_uv_mode_cost[0], + x->kf_uv_mode_prob, vp8_uv_mode_tree); +#endif + vp8_cost_tokens(c->mb.i8x8_mode_costs, + x->i8x8_mode_prob,vp8_i8x8_mode_tree); - vp8_cost_tokens(c->mb.intra_uv_mode_cost[1], x->fc.uv_mode_prob, vp8_uv_mode_tree); - vp8_cost_tokens(c->mb.intra_uv_mode_cost[0], x->kf_uv_mode_prob, vp8_uv_mode_tree); } diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index bf155e250..0d126067e 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -30,9 +30,13 @@ #endif #include "vpx_mem/vpx_mem.h" #include "vp8/common/swapyv12buffer.h" -#include "vp8/common/threading.h" #include "vpx_ports/vpx_timer.h" #include "temporal_filter.h" + +#include "vp8/common/seg_common.h" +#include "mbgraph.h" +#include "vp8/common/pred_common.h" + #if ARCH_ARM #include "vpx_ports/arm.h" #endif @@ -75,6 +79,14 @@ static void set_default_lf_deltas(VP8_COMP *cpi); extern const int vp8_gf_interval_table[101]; +#if CONFIG_HIGH_PRECISION_MV +#define ALTREF_HIGH_PRECISION_MV 1 /* whether to use high precision mv for altref computation */ +#define HIGH_PRECISION_MV_QTHRESH 200 /* Q threshold for use of high precision mv */ + /* Choose a very high value for now so + * that HIGH_PRECISION is always chosen + */ +#endif + #if CONFIG_INTERNAL_STATS #include "math.h" @@ -101,10 +113,14 @@ extern double vp8_calc_ssimg #endif +//#define OUTPUT_YUV_REC #ifdef OUTPUT_YUV_SRC FILE *yuv_file; #endif +#ifdef OUTPUT_YUV_REC +FILE *yuv_rec_file; +#endif #if 0 FILE *framepsnr; @@ -130,164 +146,131 @@ unsigned int tot_ef = 0; unsigned int cnt_ef = 0; #endif +#if defined(SECTIONBITS_OUTPUT) +extern unsigned __int64 Sectionbits[500]; +#endif #ifdef MODE_STATS -extern unsigned __int64 Sectionbits[50]; -extern int y_modes[5] ; -extern int uv_modes[4] ; -extern int b_modes[10] ; - -extern int inter_y_modes[10] ; -extern int inter_uv_modes[4] ; -extern unsigned int inter_b_modes[15]; +extern INT64 Sectionbits[500]; +extern int y_modes[VP8_YMODES] ; +extern int i8x8_modes[VP8_I8X8_MODES]; +extern int uv_modes[VP8_UV_MODES] ; +extern int uv_modes_y[VP8_YMODES][VP8_UV_MODES]; +extern int b_modes[B_MODE_COUNT]; +extern int inter_y_modes[MB_MODE_COUNT] ; +extern int inter_uv_modes[VP8_UV_MODES] ; +extern unsigned int inter_b_modes[B_MODE_COUNT]; #endif extern void (*vp8_short_fdct4x4)(short *input, short *output, int pitch); extern void (*vp8_short_fdct8x4)(short *input, short *output, int pitch); -extern const int vp8_bits_per_mb[2][QINDEX_RANGE]; - -extern const int qrounding_factors[129]; -extern const int qzbin_factors[129]; extern void vp8cx_init_quantizer(VP8_COMP *cpi); -extern const int vp8cx_base_skip_false_prob[128]; -#if !CONFIG_EXTEND_QRANGE + +int vp8cx_base_skip_false_prob[QINDEX_RANGE]; + // Tables relating active max Q to active min Q -static const int kf_low_motion_minq[QINDEX_RANGE] = -{ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, - 3,3,3,3,3,3,4,4,4,5,5,5,5,5,6,6, - 6,6,7,7,8,8,8,8,9,9,10,10,10,10,11,11, - 11,11,12,12,13,13,13,13,14,14,15,15,15,15,16,16, - 16,16,17,17,18,18,18,18,19,20,20,21,21,22,23,23 -}; -static const int kf_high_motion_minq[QINDEX_RANGE] = -{ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3, - 3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6, - 6,6,7,7,8,8,8,8,9,9,10,10,10,10,11,11, - 11,11,12,12,13,13,13,13,14,14,15,15,15,15,16,16, - 16,16,17,17,18,18,18,18,19,19,20,20,20,20,21,21, - 21,21,22,22,23,23,24,25,25,26,26,27,28,28,29,30 -}; -static const int gf_low_motion_minq[QINDEX_RANGE] = -{ - 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, - 3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6, - 7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10, - 11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18, - 19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26, - 27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34, - 35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42, - 43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58 -}; -static const int gf_mid_motion_minq[QINDEX_RANGE] = -{ - 0,0,0,0,1,1,1,1,1,1,2,2,3,3,3,4, - 4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9, - 9,10,10,10,10,11,11,11,12,12,12,12,13,13,13,14, - 14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21, - 22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29, - 30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37, - 38,39,39,40,40,41,41,42,42,43,43,44,45,46,47,48, - 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64 -}; -static const int gf_high_motion_minq[QINDEX_RANGE] = -{ - 0,0,0,0,1,1,1,1,1,2,2,2,3,3,3,4, - 4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9, - 9,10,10,10,11,11,12,12,13,13,14,14,15,15,16,16, - 17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, - 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32, - 33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40, - 41,41,42,42,43,44,45,46,47,48,49,50,51,52,53,54, - 55,56,57,58,59,60,62,64,66,68,70,72,74,76,78,80 -}; -static const int inter_minq[QINDEX_RANGE] = -{ - 0,0,1,1,2,3,3,4,4,5,6,6,7,8,8,9, - 9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,20, - 20,21,22,22,23,24,24,25,26,27,27,28,29,30,30,31, - 32,33,33,34,35,36,36,37,38,39,39,40,41,42,42,43, - 44,45,46,46,47,48,49,50,50,51,52,53,54,55,55,56, - 57,58,59,60,60,61,62,63,64,65,66,67,67,68,69,70, - 71,72,73,74,75,75,76,77,78,79,80,81,82,83,84,85, - 86,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100 -}; -#else -static const int kf_low_motion_minq[QINDEX_RANGE] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, - 9, 9, 9, 10,10,11,11,12,12,13,13,14,14,15,15,16, - 16,17,17,18,18,19,19,20,20,21,21,22,23,23,24,24, - 25,25,26,27,28,29,30,30,31,32,33,34,35,35,36,36, - 38,38,39,40,40,41,42,42,43,44,44,45,46,46,47,48, - 49,49,50,50,51,52,52,53,54,55,56,57,58,59,60,61, -}; -static const int kf_high_motion_minq[QINDEX_RANGE] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9,10,10, - 11,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24, - 25,26,27,28,28,29,29,30,30,31,31,32,33,33,34,34, - 35,36,37,38,39,39,40,41,41,42,43,44,45,45,46,46, - 47,47,48,48,49,49,50,50,51,51,52,52,53,53,54,54, - 55,55,56,56,57,58,59,60,61,62,63,64,65,67,69,70, -}; +static int kf_low_motion_minq[QINDEX_RANGE]; +static int kf_high_motion_minq[QINDEX_RANGE]; +static int gf_low_motion_minq[QINDEX_RANGE]; +static int gf_mid_motion_minq[QINDEX_RANGE]; +static int gf_high_motion_minq[QINDEX_RANGE]; +static int inter_minq[QINDEX_RANGE]; -static const int gf_low_motion_minq[QINDEX_RANGE] = +// Functions to compute the active minq lookup table entries based on a +// formulaic approach to facilitate easier adjustment of the Q tables. +// The formulae were derived from computing a 3rd order polynomial best +// fit to the original data (after plotting real maxq vs minq (not q index)) +int calculate_minq_index( double maxq, + double x3, double x2, double x, double c ) { - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, - 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, - 10,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17, - 17,18,18,19,19,20,21,22,23,24,25,26,27,29,29,30, - 31,32,33,34,35,36,37,38,39,40,41,41,42,42,43,43, - 44,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51, - 52,52,53,53,54,54,55,55,56,56,57,57,58,59,60,61, - 62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, -}; -static const int gf_mid_motion_minq[QINDEX_RANGE] = -{ - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, - 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9,10, - 10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18, - 18,19,19,20,20,21,22,23,24,25,26,27,28,29,30,31, - 32,33,34,35,35,36,36,37,37,38,38,39,39,40,40,41, - 41,42,42,43,43,44,44,45,45,46,46,47,48,49,50,51, - 52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67, - 68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83, -}; -static const int gf_high_motion_minq[QINDEX_RANGE] = -{ - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, - 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9,10,10, - 11,11,12,12,13,14,15,16,17,18,18,19,19,20,20,21, - 22,23,24,25,26,26,27,28,29,30,31,32,33,34,35,36, - 37,38,39,39,40,40,40,41,41,41,42,42,43,43,44,44, - 44,45,45,45,46,46,47,47,47,48,48,48,49,49,49,50, - 50,50,51,51,52,53,54,54,55,56,57,57,58,59,60,61, - 62,63,64,66,68,69,72,74,77,80,82,85,87,89,91,93, -}; + int i; + double minqtarget; + double thisq; -static const int inter_minq[QINDEX_RANGE] = + minqtarget = ( (x3 * maxq * maxq * maxq) + + (x2 * maxq * maxq) + + (x * maxq) + + c ); + + if ( minqtarget > maxq ) + minqtarget = maxq; + + for ( i = 0; i < QINDEX_RANGE; i++ ) + { + thisq = vp8_convert_qindex_to_q(i); + if ( minqtarget <= vp8_convert_qindex_to_q(i) ) + return i; + } + if ( i == QINDEX_RANGE ) + return QINDEX_RANGE-1; +} +void init_minq_luts() { - 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, - 8, 9,10,11,12,13,14,15,16,17,18,18,19,19,20,21, - 21,22,23,23,24,25,26,26,27,28,29,30,31,32,32,33, - 34,35,36,36,37,38,39,40,40,41,41,42,43,44,44,45, - 46,46,47,47,48,49,49,50,50,51,52,52,53,54,54,55, - 55,56,57,57,58,59,60,60,61,62,63,63,64,65,66,67, - 68,68,69,70,71,72,72,73,74,75,76,77,78,79,80,81, - 81,82,83,84,85,86,87,88,89,90,90,91,92,93,94,95, -}; -#endif + int i; + double maxq; + + for ( i = 0; i < QINDEX_RANGE; i++ ) + { + maxq = vp8_convert_qindex_to_q(i); + + + kf_low_motion_minq[i] = calculate_minq_index( maxq, + 0.0000003, + -0.000015, + 0.074, + 0.0 ); + + kf_high_motion_minq[i] = calculate_minq_index( maxq, + 0.00000034, + -0.000125, + 0.13, + 0.0 ); + gf_low_motion_minq[i] = calculate_minq_index( maxq, + 0.0000016, + -0.00078, + 0.315, + 0.0 ); + gf_mid_motion_minq[i] = calculate_minq_index( maxq, + 0.00000415, + -0.0017, + 0.425, + 0.0 ); + gf_high_motion_minq[i] = calculate_minq_index( maxq, + 0.00000725, + -0.00235, + 0.47, + 0.0 ); + inter_minq[i] = calculate_minq_index( maxq, + 0.00000271, + -0.00113, + 0.697, + 0.0 ); + + } +} + +void init_base_skip_probs() +{ + int i; + double q; + int skip_prob; + + for ( i = 0; i < QINDEX_RANGE; i++ ) + { + q = vp8_convert_qindex_to_q(i); + + // Exponential decay caluclation of baseline skip prob with clamping + // Based on crude best fit of old table. + skip_prob = (int)( 564.25 * pow( 2.71828, (-0.012*q) ) ); + if ( skip_prob < 1 ) + skip_prob = 1; + else if ( skip_prob > 255 ) + skip_prob = 255; + + vp8cx_base_skip_false_prob[i] = skip_prob; + } +} + void vp8_initialize() { static int init_done = 0; @@ -298,7 +281,10 @@ void vp8_initialize() vp8_initialize_common(); //vp8_dmachine_specific_config(); vp8_tokenize_initialize(); - + vp8_init_quant_tables(); + vp8_init_me_luts(); + init_minq_luts(); + init_base_skip_probs(); init_done = 1; } } @@ -308,19 +294,24 @@ extern FILE *vpxlogc; static void setup_features(VP8_COMP *cpi) { - // Set up default state for MB feature flags - cpi->mb.e_mbd.segmentation_enabled = 0; - cpi->mb.e_mbd.update_mb_segmentation_map = 0; - cpi->mb.e_mbd.update_mb_segmentation_data = 0; - vpx_memset(cpi->mb.e_mbd.mb_segment_tree_probs, 255, sizeof(cpi->mb.e_mbd.mb_segment_tree_probs)); - vpx_memset(cpi->mb.e_mbd.segment_feature_data, 0, sizeof(cpi->mb.e_mbd.segment_feature_data)); + MACROBLOCKD *xd = &cpi->mb.e_mbd; - cpi->mb.e_mbd.mode_ref_lf_delta_enabled = 0; - cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; - vpx_memset(cpi->mb.e_mbd.ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas)); - vpx_memset(cpi->mb.e_mbd.mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas)); - vpx_memset(cpi->mb.e_mbd.last_ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas)); - vpx_memset(cpi->mb.e_mbd.last_mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas)); + // Set up default state for MB feature flags + + xd->segmentation_enabled = 0; // Default segmentation disabled + + xd->update_mb_segmentation_map = 0; + xd->update_mb_segmentation_data = 0; + vpx_memset(xd->mb_segment_tree_probs, 255, sizeof(xd->mb_segment_tree_probs)); + + clearall_segfeatures( xd ); + + xd->mode_ref_lf_delta_enabled = 0; + xd->mode_ref_lf_delta_update = 0; + vpx_memset(xd->ref_lf_deltas, 0, sizeof(xd->ref_lf_deltas)); + vpx_memset(xd->mode_lf_deltas, 0, sizeof(xd->mode_lf_deltas)); + vpx_memset(xd->last_ref_lf_deltas, 0, sizeof(xd->ref_lf_deltas)); + vpx_memset(xd->last_mode_lf_deltas, 0, sizeof(xd->mode_lf_deltas)); set_default_lf_deltas(cpi); @@ -345,6 +336,8 @@ static void dealloc_compressor_data(VP8_COMP *cpi) // Delete sementation map vpx_free(cpi->segmentation_map); cpi->segmentation_map = 0; + vpx_free(cpi->common.last_frame_seg_map); + cpi->common.last_frame_seg_map = 0; vpx_free(cpi->active_map); cpi->active_map = 0; @@ -374,212 +367,239 @@ static void dealloc_compressor_data(VP8_COMP *cpi) vpx_free(cpi->mb.pip); cpi->mb.pip = 0; -#if !(CONFIG_REALTIME_ONLY) vpx_free(cpi->twopass.total_stats); cpi->twopass.total_stats = 0; + vpx_free(cpi->twopass.total_left_stats); + cpi->twopass.total_left_stats = 0; + vpx_free(cpi->twopass.this_frame_stats); cpi->twopass.this_frame_stats = 0; -#endif } -static void enable_segmentation(VP8_PTR ptr) +// Computes a q delta (in "q index" terms) to get from a starting q value +// to a target value +// target q value +static int compute_qdelta( VP8_COMP *cpi, double qstart, double qtarget ) { - VP8_COMP *cpi = (VP8_COMP *)(ptr); - - // Set the appropriate feature bit - cpi->mb.e_mbd.segmentation_enabled = 1; - cpi->mb.e_mbd.update_mb_segmentation_map = 1; - cpi->mb.e_mbd.update_mb_segmentation_data = 1; -} -static void disable_segmentation(VP8_PTR ptr) -{ - VP8_COMP *cpi = (VP8_COMP *)(ptr); - - // Clear the appropriate feature bit - cpi->mb.e_mbd.segmentation_enabled = 0; -} - -// Valid values for a segment are 0 to 3 -// Segmentation map is arrange as [Rows][Columns] -static void set_segmentation_map(VP8_PTR ptr, unsigned char *segmentation_map) -{ - VP8_COMP *cpi = (VP8_COMP *)(ptr); - - // Copy in the new segmentation map - vpx_memcpy(cpi->segmentation_map, segmentation_map, (cpi->common.mb_rows * cpi->common.mb_cols)); - - // Signal that the map should be updated. - cpi->mb.e_mbd.update_mb_segmentation_map = 1; - cpi->mb.e_mbd.update_mb_segmentation_data = 1; -} - -// The values given for each segment can be either deltas (from the default value chosen for the frame) or absolute values. -// -// Valid range for abs values is (0-127 for MB_LVL_ALT_Q) , (0-63 for SEGMENT_ALT_LF) -// Valid range for delta values are (+/-127 for MB_LVL_ALT_Q) , (+/-63 for SEGMENT_ALT_LF) -// -// abs_delta = SEGMENT_DELTADATA (deltas) abs_delta = SEGMENT_ABSDATA (use the absolute values given). -// -// -static void set_segment_data(VP8_PTR ptr, signed char *feature_data, unsigned char abs_delta) -{ - VP8_COMP *cpi = (VP8_COMP *)(ptr); - - cpi->mb.e_mbd.mb_segement_abs_delta = abs_delta; - vpx_memcpy(cpi->segment_feature_data, feature_data, sizeof(cpi->segment_feature_data)); -} - - -static void segmentation_test_function(VP8_PTR ptr) -{ - VP8_COMP *cpi = (VP8_COMP *)(ptr); - - unsigned char *seg_map; - signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; - - // Create a temporary map for segmentation data. - CHECK_MEM_ERROR(seg_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); - - // MB loop to set local segmentation map - /*for ( i = 0; i < cpi->common.mb_rows; i++ ) - { - for ( j = 0; j < cpi->common.mb_cols; j++ ) - { - //seg_map[(i*cpi->common.mb_cols) + j] = (j % 2) + ((i%2)* 2); - //if ( j < cpi->common.mb_cols/2 ) - - // Segment 1 around the edge else 0 - if ( (i == 0) || (j == 0) || (i == (cpi->common.mb_rows-1)) || (j == (cpi->common.mb_cols-1)) ) - seg_map[(i*cpi->common.mb_cols) + j] = 1; - //else if ( (i < 2) || (j < 2) || (i > (cpi->common.mb_rows-3)) || (j > (cpi->common.mb_cols-3)) ) - // seg_map[(i*cpi->common.mb_cols) + j] = 2; - //else if ( (i < 5) || (j < 5) || (i > (cpi->common.mb_rows-6)) || (j > (cpi->common.mb_cols-6)) ) - // seg_map[(i*cpi->common.mb_cols) + j] = 3; - else - seg_map[(i*cpi->common.mb_cols) + j] = 0; - } - }*/ - - // Set the segmentation Map - set_segmentation_map(ptr, seg_map); - - // Activate segmentation. - enable_segmentation(ptr); - - // Set up the quant segment data - feature_data[MB_LVL_ALT_Q][0] = 0; - feature_data[MB_LVL_ALT_Q][1] = 4; - feature_data[MB_LVL_ALT_Q][2] = 0; - feature_data[MB_LVL_ALT_Q][3] = 0; - // Set up the loop segment data - feature_data[MB_LVL_ALT_LF][0] = 0; - feature_data[MB_LVL_ALT_LF][1] = 0; - feature_data[MB_LVL_ALT_LF][2] = 0; - feature_data[MB_LVL_ALT_LF][3] = 0; - - // Initialise the feature data structure - // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 - set_segment_data(ptr, &feature_data[0][0], SEGMENT_DELTADATA); - - // Delete sementation map - vpx_free(seg_map); - - seg_map = 0; - -} - -// A simple function to cyclically refresh the background at a lower Q -static void cyclic_background_refresh(VP8_COMP *cpi, int Q, int lf_adjustment) -{ - unsigned char *seg_map; - signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; int i; - int block_count = cpi->cyclic_refresh_mode_max_mbs_perframe; - int mbs_in_frame = cpi->common.mb_rows * cpi->common.mb_cols; + int start_index = cpi->worst_quality; + int target_index = cpi->worst_quality; + int retval = 0; - // Create a temporary map for segmentation data. - CHECK_MEM_ERROR(seg_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); - - cpi->cyclic_refresh_q = Q; - - for (i = Q; i > 0; i--) + // Convert the average q value to an index. + for ( i = cpi->best_quality; i < cpi->worst_quality; i++ ) { - if (vp8_bits_per_mb[cpi->common.frame_type][i] >= ((vp8_bits_per_mb[cpi->common.frame_type][Q]*(Q + 128)) / 64)) - //if ( vp8_bits_per_mb[cpi->common.frame_type][i] >= ((vp8_bits_per_mb[cpi->common.frame_type][Q]*((2*Q)+96))/64) ) - { + start_index = i; + if ( vp8_convert_qindex_to_q(i) >= qstart ) break; - } } - cpi->cyclic_refresh_q = i; - - // Only update for inter frames - if (cpi->common.frame_type != KEY_FRAME) + // Convert the q target to an index + for ( i = cpi->best_quality; i < cpi->worst_quality; i++ ) { - // Cycle through the macro_block rows - // MB loop to set local segmentation map - for (i = cpi->cyclic_refresh_mode_index; i < mbs_in_frame; i++) - { - // If the MB is as a candidate for clean up then mark it for possible boost/refresh (segment 1) - // The segment id may get reset to 0 later if the MB gets coded anything other than last frame 0,0 - // as only (last frame 0,0) MBs are eligable for refresh : that is to say Mbs likely to be background blocks. - if (cpi->cyclic_refresh_map[i] == 0) - { - seg_map[i] = 1; - } - else - { - seg_map[i] = 0; - - // Skip blocks that have been refreshed recently anyway. - if (cpi->cyclic_refresh_map[i] < 0) - //cpi->cyclic_refresh_map[i] = cpi->cyclic_refresh_map[i] / 16; - cpi->cyclic_refresh_map[i]++; - } - - - if (block_count > 0) - block_count--; - else - break; - - } - - // If we have gone through the frame reset to the start - cpi->cyclic_refresh_mode_index = i; - - if (cpi->cyclic_refresh_mode_index >= mbs_in_frame) - cpi->cyclic_refresh_mode_index = 0; + target_index = i; + if ( vp8_convert_qindex_to_q(i) >= qtarget ) + break; } - // Set the segmentation Map - set_segmentation_map((VP8_PTR)cpi, seg_map); + return target_index - start_index; +} - // Activate segmentation. - enable_segmentation((VP8_PTR)cpi); +static void init_seg_features(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + MACROBLOCKD *xd = &cpi->mb.e_mbd; - // Set up the quant segment data - feature_data[MB_LVL_ALT_Q][0] = 0; - feature_data[MB_LVL_ALT_Q][1] = (cpi->cyclic_refresh_q - Q); - feature_data[MB_LVL_ALT_Q][2] = 0; - feature_data[MB_LVL_ALT_Q][3] = 0; + int high_q = (int)(cpi->avg_q > 48.0); + int qi_delta; - // Set up the loop segment data - feature_data[MB_LVL_ALT_LF][0] = 0; - feature_data[MB_LVL_ALT_LF][1] = lf_adjustment; - feature_data[MB_LVL_ALT_LF][2] = 0; - feature_data[MB_LVL_ALT_LF][3] = 0; + // Disable and clear down for KF + if ( cm->frame_type == KEY_FRAME ) + { + // Clear down the global segmentation map + vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols)); + xd->update_mb_segmentation_map = 0; + xd->update_mb_segmentation_data = 0; + cpi->static_mb_pct = 0; - // Initialise the feature data structure - // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 - set_segment_data((VP8_PTR)cpi, &feature_data[0][0], SEGMENT_DELTADATA); + // Disable segmentation + vp8_disable_segmentation((VP8_PTR)cpi); - // Delete sementation map - vpx_free(seg_map); + // Clear down the segment features. + clearall_segfeatures(xd); + } - seg_map = 0; + // If this is an alt ref frame + else if ( cm->refresh_alt_ref_frame ) + { + // Clear down the global segmentation map + vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols)); + xd->update_mb_segmentation_map = 0; + xd->update_mb_segmentation_data = 0; + cpi->static_mb_pct = 0; + // Disable segmentation and individual segment features by default + vp8_disable_segmentation((VP8_PTR)cpi); + clearall_segfeatures(xd); + + // Scan frames from current to arf frame. + // This function re-enables segmentation if appropriate. + vp8_update_mbgraph_stats(cpi); + + // If segmentation was enabled set those features needed for the + // arf itself. + if ( xd->segmentation_enabled ) + { + xd->update_mb_segmentation_map = 1; + xd->update_mb_segmentation_data = 1; + + qi_delta = compute_qdelta( cpi, cpi->avg_q, (cpi->avg_q * 0.875) ); + set_segdata( xd, 1, SEG_LVL_ALT_Q, (qi_delta - 2) ); + set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 ); + + enable_segfeature(xd, 1, SEG_LVL_ALT_Q); + enable_segfeature(xd, 1, SEG_LVL_ALT_LF); + + // Where relevant assume segment data is delta data + xd->mb_segment_abs_delta = SEGMENT_DELTADATA; + + } + } + // All other frames if segmentation has been enabled + else if ( xd->segmentation_enabled ) + { +/* + int i; + + // clears prior frame seg lev refs + for (i = 0; i < MAX_MB_SEGMENTS; i++) + { + // only do it if the force drop the background stuff is off + if(!segfeature_active(xd, i, SEG_LVL_MODE)) + { + disable_segfeature(xd,i,SEG_LVL_REF_FRAME); + set_segdata( xd,i, SEG_LVL_REF_FRAME, 0xffffff); + } + } +*/ + + // First normal frame in a valid gf or alt ref group + if ( cpi->common.frames_since_golden == 0 ) + { + // Set up segment features for normal frames in an af group + if ( cpi->source_alt_ref_active ) + { + xd->update_mb_segmentation_map = 0; + xd->update_mb_segmentation_data = 1; + xd->mb_segment_abs_delta = SEGMENT_DELTADATA; + + qi_delta = compute_qdelta( cpi, cpi->avg_q, + (cpi->avg_q * 1.125) ); + set_segdata( xd, 1, SEG_LVL_ALT_Q, (qi_delta + 2) ); + set_segdata( xd, 1, SEG_LVL_ALT_Q, 0 ); + enable_segfeature(xd, 1, SEG_LVL_ALT_Q); + + set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 ); + enable_segfeature(xd, 1, SEG_LVL_ALT_LF); + + // Segment coding disabled for compred testing + if ( high_q || (cpi->static_mb_pct == 100) ) + { + //set_segref(xd, 1, LAST_FRAME); + set_segref(xd, 1, ALTREF_FRAME); + enable_segfeature(xd, 1, SEG_LVL_REF_FRAME); + + set_segdata( xd, 1, SEG_LVL_MODE, ZEROMV ); + enable_segfeature(xd, 1, SEG_LVL_MODE); + + // EOB segment coding not fixed for 8x8 yet + set_segdata( xd, 1, SEG_LVL_EOB, 0 ); + enable_segfeature(xd, 1, SEG_LVL_EOB); + } + } + // Disable segmentation and clear down features if alt ref + // is not active for this group + else + { + vp8_disable_segmentation((VP8_PTR)cpi); + + vpx_memset( cpi->segmentation_map, 0, + (cm->mb_rows * cm->mb_cols)); + + xd->update_mb_segmentation_map = 0; + xd->update_mb_segmentation_data = 0; + + clearall_segfeatures(xd); + } + } + + // Special case where we are coding over the top of a previous + // alt ref frame + // Segment coding disabled for compred testing + else if ( cpi->is_src_frame_alt_ref ) + { + // Enable mode and ref frame features for segment 0 as well + enable_segfeature(xd, 0, SEG_LVL_REF_FRAME); + enable_segfeature(xd, 0, SEG_LVL_MODE); + enable_segfeature(xd, 1, SEG_LVL_REF_FRAME); + enable_segfeature(xd, 1, SEG_LVL_MODE); + + // All mbs should use ALTREF_FRAME, ZEROMV exclusively + clear_segref(xd, 0); + set_segref(xd, 0, ALTREF_FRAME); + clear_segref(xd, 1); + set_segref(xd, 1, ALTREF_FRAME); + set_segdata( xd, 0, SEG_LVL_MODE, ZEROMV ); + set_segdata( xd, 1, SEG_LVL_MODE, ZEROMV ); + + // Skip all MBs if high Q + if ( high_q ) + { + enable_segfeature(xd, 0, SEG_LVL_EOB); + set_segdata( xd, 0, SEG_LVL_EOB, 0 ); + enable_segfeature(xd, 1, SEG_LVL_EOB); + set_segdata( xd, 1, SEG_LVL_EOB, 0 ); + } + // Enable data udpate + xd->update_mb_segmentation_data = 1; + } + // All other frames. + else + { + // No updeates.. leave things as they are. + xd->update_mb_segmentation_map = 0; + xd->update_mb_segmentation_data = 0; + } + } +} + +// DEBUG: Print out the segment id of each MB in the current frame. +static void print_seg_map(VP8_COMP *cpi) +{ + VP8_COMMON *cm = & cpi->common; + int row,col; + int map_index = 0; + FILE *statsfile; + + statsfile = fopen("segmap.stt", "a"); + + fprintf(statsfile, "%10d\n", + cm->current_video_frame ); + + for ( row = 0; row < cpi->common.mb_rows; row++ ) + { + for ( col = 0; col < cpi->common.mb_cols; col++ ) + { + fprintf(statsfile, "%10d", + cpi->segmentation_map[map_index]); + map_index++; + } + fprintf(statsfile, "\n"); + } + fprintf(statsfile, "\n"); + + fclose(statsfile); } static void set_default_lf_deltas(VP8_COMP *cpi) @@ -611,6 +631,10 @@ void vp8_set_speed_features(VP8_COMP *cpi) VP8_COMMON *cm = &cpi->common; int last_improved_quant = sf->improved_quant; + // Only modes 0 and 1 supported for now in experimental code basae + if ( Mode > 1 ) + Mode = 1; + // Initialise default mode frequency sampling variables for (i = 0; i < MAX_MODES; i ++) { @@ -645,7 +669,6 @@ void vp8_set_speed_features(VP8_COMP *cpi) switch (Mode) { -#if !(CONFIG_REALTIME_ONLY) case 0: // best quality mode sf->thresh_mult[THR_ZEROMV ] = 0; sf->thresh_mult[THR_ZEROG ] = 0; @@ -662,6 +685,7 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_V_PRED ] = 1000; sf->thresh_mult[THR_H_PRED ] = 1000; sf->thresh_mult[THR_B_PRED ] = 2000; + sf->thresh_mult[THR_I8X8_PRED] = 2000; sf->thresh_mult[THR_TM ] = 1000; sf->thresh_mult[THR_NEWMV ] = 1000; @@ -672,12 +696,24 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_SPLITG ] = 5000; sf->thresh_mult[THR_SPLITA ] = 5000; + sf->thresh_mult[THR_COMP_ZEROLG ] = 0; + sf->thresh_mult[THR_COMP_NEARESTLG] = 0; + sf->thresh_mult[THR_COMP_NEARLG ] = 0; + sf->thresh_mult[THR_COMP_ZEROLA ] = 0; + sf->thresh_mult[THR_COMP_NEARESTLA] = 0; + sf->thresh_mult[THR_COMP_NEARLA ] = 0; + sf->thresh_mult[THR_COMP_ZEROGA ] = 0; + sf->thresh_mult[THR_COMP_NEARESTGA] = 0; + sf->thresh_mult[THR_COMP_NEARGA ] = 0; + + sf->thresh_mult[THR_COMP_NEWLG ] = 1000; + sf->thresh_mult[THR_COMP_NEWLA ] = 1000; + sf->thresh_mult[THR_COMP_NEWGA ] = 1000; sf->first_step = 0; sf->max_step_search_steps = MAX_MVSEARCH_STEPS; break; case 1: - case 3: sf->thresh_mult[THR_NEARESTMV] = 0; sf->thresh_mult[THR_ZEROMV ] = 0; sf->thresh_mult[THR_DC ] = 0; @@ -685,6 +721,7 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_V_PRED ] = 1000; sf->thresh_mult[THR_H_PRED ] = 1000; sf->thresh_mult[THR_B_PRED ] = 2500; + sf->thresh_mult[THR_I8X8_PRED] = 2500; sf->thresh_mult[THR_TM ] = 1000; sf->thresh_mult[THR_NEARESTG ] = 1000; @@ -695,7 +732,6 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_NEARG ] = 1000; sf->thresh_mult[THR_NEARA ] = 1000; -#if 1 sf->thresh_mult[THR_ZEROMV ] = 0; sf->thresh_mult[THR_ZEROG ] = 0; sf->thresh_mult[THR_ZEROA ] = 0; @@ -706,13 +742,6 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_NEARG ] = 0; sf->thresh_mult[THR_NEARA ] = 0; -// sf->thresh_mult[THR_DC ] = 0; - -// sf->thresh_mult[THR_V_PRED ] = 1000; -// sf->thresh_mult[THR_H_PRED ] = 1000; -// sf->thresh_mult[THR_B_PRED ] = 2000; -// sf->thresh_mult[THR_TM ] = 1000; - sf->thresh_mult[THR_NEWMV ] = 1000; sf->thresh_mult[THR_NEWG ] = 1000; sf->thresh_mult[THR_NEWA ] = 1000; @@ -720,15 +749,20 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_SPLITMV ] = 1700; sf->thresh_mult[THR_SPLITG ] = 4500; sf->thresh_mult[THR_SPLITA ] = 4500; -#else - sf->thresh_mult[THR_NEWMV ] = 1500; - sf->thresh_mult[THR_NEWG ] = 1500; - sf->thresh_mult[THR_NEWA ] = 1500; - sf->thresh_mult[THR_SPLITMV ] = 5000; - sf->thresh_mult[THR_SPLITG ] = 10000; - sf->thresh_mult[THR_SPLITA ] = 10000; -#endif + sf->thresh_mult[THR_COMP_ZEROLG ] = 0; + sf->thresh_mult[THR_COMP_NEARESTLG] = 0; + sf->thresh_mult[THR_COMP_NEARLG ] = 0; + sf->thresh_mult[THR_COMP_ZEROLA ] = 0; + sf->thresh_mult[THR_COMP_NEARESTLA] = 0; + sf->thresh_mult[THR_COMP_NEARLA ] = 0; + sf->thresh_mult[THR_COMP_ZEROGA ] = 0; + sf->thresh_mult[THR_COMP_NEARESTGA] = 0; + sf->thresh_mult[THR_COMP_NEARGA ] = 0; + + sf->thresh_mult[THR_COMP_NEWLG ] = 1000; + sf->thresh_mult[THR_COMP_NEWLA ] = 1000; + sf->thresh_mult[THR_COMP_NEWGA ] = 1000; if (Speed > 0) { @@ -754,6 +788,7 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_V_PRED ] = 1500; sf->thresh_mult[THR_H_PRED ] = 1500; sf->thresh_mult[THR_B_PRED ] = 5000; + sf->thresh_mult[THR_I8X8_PRED] = 5000; if (cpi->ref_frame_flags & VP8_LAST_FLAG) { @@ -778,6 +813,20 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_NEWA ] = 2000; sf->thresh_mult[THR_SPLITA ] = 20000; } + + sf->thresh_mult[THR_COMP_ZEROLG ] = 1500; + sf->thresh_mult[THR_COMP_NEARESTLG] = 1500; + sf->thresh_mult[THR_COMP_NEARLG ] = 1500; + sf->thresh_mult[THR_COMP_ZEROLA ] = 1500; + sf->thresh_mult[THR_COMP_NEARESTLA] = 1500; + sf->thresh_mult[THR_COMP_NEARLA ] = 1500; + sf->thresh_mult[THR_COMP_ZEROGA ] = 1500; + sf->thresh_mult[THR_COMP_NEARESTGA] = 1500; + sf->thresh_mult[THR_COMP_NEARGA ] = 1500; + + sf->thresh_mult[THR_COMP_NEWLG ] = 2000; + sf->thresh_mult[THR_COMP_NEWLA ] = 2000; + sf->thresh_mult[THR_COMP_NEWGA ] = 2000; } if (Speed > 2) @@ -790,6 +839,7 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_V_PRED ] = 2000; sf->thresh_mult[THR_H_PRED ] = 2000; sf->thresh_mult[THR_B_PRED ] = 7500; + sf->thresh_mult[THR_I8X8_PRED] = 7500; if (cpi->ref_frame_flags & VP8_LAST_FLAG) { @@ -815,6 +865,20 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_SPLITA ] = 50000; } + sf->thresh_mult[THR_COMP_ZEROLG ] = 2000; + sf->thresh_mult[THR_COMP_NEARESTLG] = 2000; + sf->thresh_mult[THR_COMP_NEARLG ] = 2000; + sf->thresh_mult[THR_COMP_ZEROLA ] = 2000; + sf->thresh_mult[THR_COMP_NEARESTLA] = 2000; + sf->thresh_mult[THR_COMP_NEARLA ] = 2000; + sf->thresh_mult[THR_COMP_ZEROGA ] = 2000; + sf->thresh_mult[THR_COMP_NEARESTGA] = 2000; + sf->thresh_mult[THR_COMP_NEARGA ] = 2000; + + sf->thresh_mult[THR_COMP_NEWLG ] = 2500; + sf->thresh_mult[THR_COMP_NEWLA ] = 2500; + sf->thresh_mult[THR_COMP_NEWGA ] = 2500; + sf->improved_quant = 0; sf->improved_dct = 0; @@ -824,368 +888,7 @@ void vp8_set_speed_features(VP8_COMP *cpi) } - if (Speed > 3) - { - sf->thresh_mult[THR_SPLITA ] = INT_MAX; - sf->thresh_mult[THR_SPLITG ] = INT_MAX; - sf->thresh_mult[THR_SPLITMV ] = INT_MAX; - - cpi->mode_check_freq[THR_V_PRED] = 0; - cpi->mode_check_freq[THR_H_PRED] = 0; - cpi->mode_check_freq[THR_B_PRED] = 0; - cpi->mode_check_freq[THR_NEARG] = 0; - cpi->mode_check_freq[THR_NEWG] = 0; - cpi->mode_check_freq[THR_NEARA] = 0; - cpi->mode_check_freq[THR_NEWA] = 0; - - sf->auto_filter = 1; - sf->recode_loop = 0; // recode loop off - sf->RD = 0; // Turn rd off - - } - - if (Speed > 4) - { - sf->auto_filter = 0; // Faster selection of loop filter - - cpi->mode_check_freq[THR_V_PRED] = 2; - cpi->mode_check_freq[THR_H_PRED] = 2; - cpi->mode_check_freq[THR_B_PRED] = 2; - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - cpi->mode_check_freq[THR_NEARG] = 2; - cpi->mode_check_freq[THR_NEWG] = 4; - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - cpi->mode_check_freq[THR_NEARA] = 2; - cpi->mode_check_freq[THR_NEWA] = 4; - } - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - sf->thresh_mult[THR_NEARESTG ] = 2000; - sf->thresh_mult[THR_ZEROG ] = 2000; - sf->thresh_mult[THR_NEARG ] = 2000; - sf->thresh_mult[THR_NEWG ] = 4000; - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - sf->thresh_mult[THR_NEARESTA ] = 2000; - sf->thresh_mult[THR_ZEROA ] = 2000; - sf->thresh_mult[THR_NEARA ] = 2000; - sf->thresh_mult[THR_NEWA ] = 4000; - } - } - break; -#endif - case 2: - sf->optimize_coefficients = 0; - sf->recode_loop = 0; - sf->auto_filter = 1; - sf->iterative_sub_pixel = 1; - sf->thresh_mult[THR_NEARESTMV] = 0; - sf->thresh_mult[THR_ZEROMV ] = 0; - sf->thresh_mult[THR_DC ] = 0; - sf->thresh_mult[THR_TM ] = 0; - sf->thresh_mult[THR_NEARMV ] = 0; - sf->thresh_mult[THR_V_PRED ] = 1000; - sf->thresh_mult[THR_H_PRED ] = 1000; - sf->thresh_mult[THR_B_PRED ] = 2500; - sf->thresh_mult[THR_NEARESTG ] = 1000; - sf->thresh_mult[THR_ZEROG ] = 1000; - sf->thresh_mult[THR_NEARG ] = 1000; - sf->thresh_mult[THR_NEARESTA ] = 1000; - sf->thresh_mult[THR_ZEROA ] = 1000; - sf->thresh_mult[THR_NEARA ] = 1000; - sf->thresh_mult[THR_NEWMV ] = 2000; - sf->thresh_mult[THR_NEWG ] = 2000; - sf->thresh_mult[THR_NEWA ] = 2000; - sf->thresh_mult[THR_SPLITMV ] = 5000; - sf->thresh_mult[THR_SPLITG ] = 10000; - sf->thresh_mult[THR_SPLITA ] = 10000; - sf->search_method = NSTEP; - - if (Speed > 0) - { - cpi->mode_check_freq[THR_SPLITG] = 4; - cpi->mode_check_freq[THR_SPLITA] = 4; - cpi->mode_check_freq[THR_SPLITMV] = 2; - - sf->thresh_mult[THR_DC ] = 0; - sf->thresh_mult[THR_TM ] = 1000; - sf->thresh_mult[THR_V_PRED ] = 2000; - sf->thresh_mult[THR_H_PRED ] = 2000; - sf->thresh_mult[THR_B_PRED ] = 5000; - - if (cpi->ref_frame_flags & VP8_LAST_FLAG) - { - sf->thresh_mult[THR_NEARESTMV] = 0; - sf->thresh_mult[THR_ZEROMV ] = 0; - sf->thresh_mult[THR_NEARMV ] = 0; - sf->thresh_mult[THR_NEWMV ] = 2000; - sf->thresh_mult[THR_SPLITMV ] = 10000; - } - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - sf->thresh_mult[THR_NEARESTG ] = 1000; - sf->thresh_mult[THR_ZEROG ] = 1000; - sf->thresh_mult[THR_NEARG ] = 1000; - sf->thresh_mult[THR_NEWG ] = 2000; - sf->thresh_mult[THR_SPLITG ] = 20000; - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - sf->thresh_mult[THR_NEARESTA ] = 1000; - sf->thresh_mult[THR_ZEROA ] = 1000; - sf->thresh_mult[THR_NEARA ] = 1000; - sf->thresh_mult[THR_NEWA ] = 2000; - sf->thresh_mult[THR_SPLITA ] = 20000; - } - - sf->improved_quant = 0; - sf->improved_dct = 0; - - sf->use_fastquant_for_pick = 1; - sf->no_skip_block4x4_search = 0; - sf->first_step = 1; - } - - if (Speed > 1) - { - cpi->mode_check_freq[THR_SPLITMV] = 7; - cpi->mode_check_freq[THR_SPLITG] = 15; - cpi->mode_check_freq[THR_SPLITA] = 15; - - sf->thresh_mult[THR_TM ] = 2000; - sf->thresh_mult[THR_V_PRED ] = 2000; - sf->thresh_mult[THR_H_PRED ] = 2000; - sf->thresh_mult[THR_B_PRED ] = 5000; - - if (cpi->ref_frame_flags & VP8_LAST_FLAG) - { - sf->thresh_mult[THR_NEWMV ] = 2000; - sf->thresh_mult[THR_SPLITMV ] = 25000; - } - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - sf->thresh_mult[THR_NEARESTG ] = 2000; - sf->thresh_mult[THR_ZEROG ] = 2000; - sf->thresh_mult[THR_NEARG ] = 2000; - sf->thresh_mult[THR_NEWG ] = 2500; - sf->thresh_mult[THR_SPLITG ] = 50000; - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - sf->thresh_mult[THR_NEARESTA ] = 2000; - sf->thresh_mult[THR_ZEROA ] = 2000; - sf->thresh_mult[THR_NEARA ] = 2000; - sf->thresh_mult[THR_NEWA ] = 2500; - sf->thresh_mult[THR_SPLITA ] = 50000; - } - - } - - if (Speed > 2) - { - sf->auto_filter = 0; // Faster selection of loop filter - - cpi->mode_check_freq[THR_V_PRED] = 2; - cpi->mode_check_freq[THR_H_PRED] = 2; - cpi->mode_check_freq[THR_B_PRED] = 2; - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - cpi->mode_check_freq[THR_NEARG] = 2; - cpi->mode_check_freq[THR_NEWG] = 4; - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - cpi->mode_check_freq[THR_NEARA] = 2; - cpi->mode_check_freq[THR_NEWA] = 4; - } - - sf->thresh_mult[THR_SPLITMV ] = INT_MAX; - sf->thresh_mult[THR_SPLITG ] = INT_MAX; - sf->thresh_mult[THR_SPLITA ] = INT_MAX; - - } - - if (Speed > 3) - { - sf->RD = 0; - - sf->auto_filter = 1; - } - - if (Speed > 4) - { - sf->auto_filter = 0; // Faster selection of loop filter - - sf->search_method = HEX; - //sf->search_method = DIAMOND; - - sf->iterative_sub_pixel = 0; - - cpi->mode_check_freq[THR_V_PRED] = 4; - cpi->mode_check_freq[THR_H_PRED] = 4; - cpi->mode_check_freq[THR_B_PRED] = 4; - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - cpi->mode_check_freq[THR_NEARG] = 2; - cpi->mode_check_freq[THR_NEWG] = 4; - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - cpi->mode_check_freq[THR_NEARA] = 2; - cpi->mode_check_freq[THR_NEWA] = 4; - } - - sf->thresh_mult[THR_TM ] = 2000; - sf->thresh_mult[THR_B_PRED ] = 5000; - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - sf->thresh_mult[THR_NEARESTG ] = 2000; - sf->thresh_mult[THR_ZEROG ] = 2000; - sf->thresh_mult[THR_NEARG ] = 2000; - sf->thresh_mult[THR_NEWG ] = 4000; - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - sf->thresh_mult[THR_NEARESTA ] = 2000; - sf->thresh_mult[THR_ZEROA ] = 2000; - sf->thresh_mult[THR_NEARA ] = 2000; - sf->thresh_mult[THR_NEWA ] = 4000; - } - } - - if (Speed > 5) - { - // Disable split MB intra prediction mode - sf->thresh_mult[THR_B_PRED] = INT_MAX; - } - - if (Speed > 6) - { - unsigned int i, sum = 0; - unsigned int total_mbs = cm->MBs; - int thresh; - int total_skip; - - int min = 2000; - - if (cpi->oxcf.encode_breakout > 2000) - min = cpi->oxcf.encode_breakout; - - min >>= 7; - - for (i = 0; i < min; i++) - { - sum += cpi->error_bins[i]; - } - - total_skip = sum; - sum = 0; - - // i starts from 2 to make sure thresh started from 2048 - for (; i < 1024; i++) - { - sum += cpi->error_bins[i]; - - if (10 * sum >= (unsigned int)(cpi->Speed - 6)*(total_mbs - total_skip)) - break; - } - - i--; - thresh = (i << 7); - - if (thresh < 2000) - thresh = 2000; - - if (cpi->ref_frame_flags & VP8_LAST_FLAG) - { - sf->thresh_mult[THR_NEWMV] = thresh; - sf->thresh_mult[THR_NEARESTMV ] = thresh >> 1; - sf->thresh_mult[THR_NEARMV ] = thresh >> 1; - } - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - sf->thresh_mult[THR_NEWG] = thresh << 1; - sf->thresh_mult[THR_NEARESTG ] = thresh; - sf->thresh_mult[THR_NEARG ] = thresh; - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - sf->thresh_mult[THR_NEWA] = thresh << 1; - sf->thresh_mult[THR_NEARESTA ] = thresh; - sf->thresh_mult[THR_NEARA ] = thresh; - } - - // Disable other intra prediction modes - sf->thresh_mult[THR_TM] = INT_MAX; - sf->thresh_mult[THR_V_PRED] = INT_MAX; - sf->thresh_mult[THR_H_PRED] = INT_MAX; - - sf->improved_mv_pred = 0; - } - - if (Speed > 8) - { - sf->quarter_pixel_search = 0; - } - - if (Speed > 9) - { - int Tmp = cpi->Speed - 8; - - if (Tmp > 4) - Tmp = 4; - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - cpi->mode_check_freq[THR_ZEROG] = 1 << (Tmp - 1); - cpi->mode_check_freq[THR_NEARESTG] = 1 << (Tmp - 1); - cpi->mode_check_freq[THR_NEARG] = 1 << Tmp; - cpi->mode_check_freq[THR_NEWG] = 1 << (Tmp + 1); - } - - if (cpi->ref_frame_flags & VP8_ALT_FLAG) - { - cpi->mode_check_freq[THR_ZEROA] = 1 << (Tmp - 1); - cpi->mode_check_freq[THR_NEARESTA] = 1 << (Tmp - 1); - cpi->mode_check_freq[THR_NEARA] = 1 << Tmp; - cpi->mode_check_freq[THR_NEWA] = 1 << (Tmp + 1); - } - - cpi->mode_check_freq[THR_NEWMV] = 1 << (Tmp - 1); - } - - cm->filter_type = NORMAL_LOOPFILTER; - - if (Speed >= 14) - cm->filter_type = SIMPLE_LOOPFILTER; - - if (Speed >= 15) - { - sf->half_pixel_search = 0; // This has a big hit on quality. Last resort - } - - vpx_memset(cpi->error_bins, 0, sizeof(cpi->error_bins)); }; /* switch */ @@ -1217,6 +920,29 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_SPLITA ] = INT_MAX; } + if ((cpi->ref_frame_flags & (VP8_LAST_FLAG | VP8_GOLD_FLAG)) != (VP8_LAST_FLAG | VP8_GOLD_FLAG)) + { + sf->thresh_mult[THR_COMP_ZEROLG ] = INT_MAX; + sf->thresh_mult[THR_COMP_NEARESTLG] = INT_MAX; + sf->thresh_mult[THR_COMP_NEARLG ] = INT_MAX; + sf->thresh_mult[THR_COMP_NEWLG ] = INT_MAX; + } + + if ((cpi->ref_frame_flags & (VP8_LAST_FLAG | VP8_ALT_FLAG)) != (VP8_LAST_FLAG | VP8_ALT_FLAG)) + { + sf->thresh_mult[THR_COMP_ZEROLA ] = INT_MAX; + sf->thresh_mult[THR_COMP_NEARESTLA] = INT_MAX; + sf->thresh_mult[THR_COMP_NEARLA ] = INT_MAX; + sf->thresh_mult[THR_COMP_NEWLA ] = INT_MAX; + } + + if ((cpi->ref_frame_flags & (VP8_GOLD_FLAG | VP8_ALT_FLAG)) != (VP8_GOLD_FLAG | VP8_ALT_FLAG)) + { + sf->thresh_mult[THR_COMP_ZEROGA ] = INT_MAX; + sf->thresh_mult[THR_COMP_NEARESTGA] = INT_MAX; + sf->thresh_mult[THR_COMP_NEARGA ] = INT_MAX; + sf->thresh_mult[THR_COMP_NEWGA ] = INT_MAX; + } // Slow quant, dct and trellis not worthwhile for first pass // so make sure they are always turned off. @@ -1238,16 +964,19 @@ void vp8_set_speed_features(VP8_COMP *cpi) if (cpi->sf.improved_dct) { + cpi->mb.vp8_short_fdct8x8 = FDCT_INVOKE(&cpi->rtcd.fdct, short8x8); cpi->mb.vp8_short_fdct8x4 = FDCT_INVOKE(&cpi->rtcd.fdct, short8x4); cpi->mb.vp8_short_fdct4x4 = FDCT_INVOKE(&cpi->rtcd.fdct, short4x4); } else { + cpi->mb.vp8_short_fdct8x8 = FDCT_INVOKE(&cpi->rtcd.fdct, short8x8); cpi->mb.vp8_short_fdct8x4 = FDCT_INVOKE(&cpi->rtcd.fdct, fast8x4); cpi->mb.vp8_short_fdct4x4 = FDCT_INVOKE(&cpi->rtcd.fdct, fast4x4); } cpi->mb.short_walsh4x4 = FDCT_INVOKE(&cpi->rtcd.fdct, walsh_short4x4); + cpi->mb.short_fhaar2x2 = FDCT_INVOKE(&cpi->rtcd.fdct, haar_short2x2); if (cpi->sf.improved_quant) { @@ -1255,6 +984,8 @@ void vp8_set_speed_features(VP8_COMP *cpi) quantb); cpi->mb.quantize_b_pair = QUANTIZE_INVOKE(&cpi->rtcd.quantize, quantb_pair); + cpi->mb.quantize_b_8x8 = QUANTIZE_INVOKE(&cpi->rtcd.quantize, quantb_8x8); + cpi->mb.quantize_b_2x2 = QUANTIZE_INVOKE(&cpi->rtcd.quantize, quantb_2x2); } else { @@ -1262,6 +993,8 @@ void vp8_set_speed_features(VP8_COMP *cpi) fastquantb); cpi->mb.quantize_b_pair = QUANTIZE_INVOKE(&cpi->rtcd.quantize, fastquantb_pair); + cpi->mb.quantize_b_8x8 = QUANTIZE_INVOKE(&cpi->rtcd.quantize, fastquantb_8x8); + cpi->mb.quantize_b_2x2 = QUANTIZE_INVOKE(&cpi->rtcd.quantize, fastquantb_2x2); } if (cpi->sf.improved_quant != last_improved_quant) vp8cx_init_quantizer(cpi); @@ -1282,19 +1015,12 @@ void vp8_set_speed_features(VP8_COMP *cpi) { cpi->find_fractional_mv_step = vp8_find_best_half_pixel_step; } - else - { - cpi->find_fractional_mv_step = vp8_skip_fractional_mv_step; - } if (cpi->sf.optimize_coefficients == 1 && cpi->pass!=1) cpi->mb.optimize = 1; else cpi->mb.optimize = 0; - if (cpi->common.full_pixel) - cpi->find_fractional_mv_step = vp8_skip_fractional_mv_step; - #ifdef SPEEDSTATS frames_at_speed[cpi->Speed]++; #endif @@ -1399,30 +1125,22 @@ void vp8_alloc_compressor_data(VP8_COMP *cpi) vpx_calloc(sizeof(unsigned int), cm->mb_rows * cm->mb_cols)); -#if !(CONFIG_REALTIME_ONLY) vpx_free(cpi->twopass.total_stats); cpi->twopass.total_stats = vpx_calloc(1, sizeof(FIRSTPASS_STATS)); + vpx_free(cpi->twopass.total_left_stats); + cpi->twopass.total_left_stats = vpx_calloc(1, sizeof(FIRSTPASS_STATS)); + vpx_free(cpi->twopass.this_frame_stats); cpi->twopass.this_frame_stats = vpx_calloc(1, sizeof(FIRSTPASS_STATS)); - if(!cpi->twopass.total_stats || !cpi->twopass.this_frame_stats) + if( !cpi->twopass.total_stats || + !cpi->twopass.total_left_stats || + !cpi->twopass.this_frame_stats) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate firstpass stats"); -#endif - -#if CONFIG_MULTITHREAD - if (width < 640) - cpi->mt_sync_range = 1; - else if (width <= 1280) - cpi->mt_sync_range = 4; - else if (width <= 2560) - cpi->mt_sync_range = 8; - else - cpi->mt_sync_range = 16; -#endif vpx_free(cpi->tplist); @@ -1430,17 +1148,22 @@ void vp8_alloc_compressor_data(VP8_COMP *cpi) } -// Quant MOD +// TODO perhaps change number of steps expose to outside world when setting +// max and min limits. Also this will likely want refining for the extended Q +// range. +// +// Table that converts 0-63 Q range values passed in outside to the Qindex +// range used internally. static const int q_trans[] = { - 0, 1, 2, 3, 4, 5, 7, 8, - 9, 10, 12, 13, 15, 17, 18, 19, - 20, 21, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 33, 35, 37, 39, 41, - 43, 45, 47, 49, 51, 53, 55, 57, - 59, 61, 64, 67, 70, 73, 76, 79, - 82, 85, 88, 91, 94, 97, 100, 103, - 106, 109, 112, 115, 118, 121, 124, 127, + 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 vp8_reverse_trans(int x) @@ -1464,6 +1187,9 @@ void vp8_new_frame_rate(VP8_COMP *cpi, double framerate) cpi->av_per_frame_bandwidth = (int)(cpi->oxcf.target_bandwidth / cpi->output_frame_rate); cpi->min_frame_bandwidth = (int)(cpi->av_per_frame_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + if (cpi->min_frame_bandwidth < FRAME_OVERHEAD_BITS ) + cpi->min_frame_bandwidth = FRAME_OVERHEAD_BITS; + // Set Maximum gf/arf interval cpi->max_gf_interval = ((int)(cpi->output_frame_rate / 2.0) + 2); @@ -1506,8 +1232,6 @@ static void init_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->oxcf = *oxcf; - cpi->auto_gold = 1; - cpi->auto_adjust_gold_quantizer = 1; cpi->goldfreq = 7; cm->version = oxcf->Version; @@ -1533,6 +1257,8 @@ static void init_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->total_actual_bits = 0; cpi->total_target_vs_actual = 0; + cpi->static_mb_pct = 0; + #if VP8_TEMPORAL_ALT_REF { int i; @@ -1567,44 +1293,12 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) switch (cpi->oxcf.Mode) { - - case MODE_REALTIME: - cpi->pass = 0; - cpi->compressor_speed = 2; - - if (cpi->oxcf.cpu_used < -16) - { - cpi->oxcf.cpu_used = -16; - } - - if (cpi->oxcf.cpu_used > 16) - cpi->oxcf.cpu_used = 16; - - break; - - case MODE_GOODQUALITY: - cpi->pass = 0; - cpi->compressor_speed = 1; - - if (cpi->oxcf.cpu_used < -5) - { - cpi->oxcf.cpu_used = -5; - } - - if (cpi->oxcf.cpu_used > 5) - cpi->oxcf.cpu_used = 5; - - break; - - case MODE_BESTQUALITY: - cpi->pass = 0; - cpi->compressor_speed = 0; - break; - + // Real time and one pass deprecated in test code base case MODE_FIRSTPASS: cpi->pass = 1; cpi->compressor_speed = 1; break; + case MODE_SECONDPASS: cpi->pass = 2; cpi->compressor_speed = 1; @@ -1618,45 +1312,18 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->oxcf.cpu_used = 5; break; + case MODE_SECONDPASS_BEST: cpi->pass = 2; cpi->compressor_speed = 0; break; } - if (cpi->pass == 0) - cpi->auto_worst_q = 1; - cpi->oxcf.worst_allowed_q = q_trans[oxcf->worst_allowed_q]; cpi->oxcf.best_allowed_q = q_trans[oxcf->best_allowed_q]; cpi->oxcf.cq_level = q_trans[cpi->oxcf.cq_level]; - if (oxcf->fixed_q >= 0) - { - if (oxcf->worst_allowed_q < 0) - cpi->oxcf.fixed_q = q_trans[0]; - else - cpi->oxcf.fixed_q = q_trans[oxcf->worst_allowed_q]; - - if (oxcf->alt_q < 0) - cpi->oxcf.alt_q = q_trans[0]; - else - cpi->oxcf.alt_q = q_trans[oxcf->alt_q]; - - if (oxcf->key_q < 0) - cpi->oxcf.key_q = q_trans[0]; - else - cpi->oxcf.key_q = q_trans[oxcf->key_q]; - - if (oxcf->gold_q < 0) - cpi->oxcf.gold_q = q_trans[0]; - else - cpi->oxcf.gold_q = q_trans[oxcf->gold_q]; - - } - - cpi->baseline_gf_interval = - cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL; + cpi->baseline_gf_interval = DEFAULT_GF_INTERVAL; cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; @@ -1666,11 +1333,10 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cm->refresh_last_frame = 1; cm->refresh_entropy_probs = 1; - if (cpi->oxcf.token_partitions >= 0 && cpi->oxcf.token_partitions <= 3) - cm->multi_token_partition = - (TOKEN_PARTITION) cpi->oxcf.token_partitions; - setup_features(cpi); +#if CONFIG_HIGH_PRECISION_MV + cpi->mb.e_mbd.allow_high_precision_mv = 0; // Default mv precision adaptation +#endif { int i; @@ -1744,9 +1410,6 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->cq_target_quality = cpi->oxcf.cq_level; - // Only allow dropped frames in buffered mode - cpi->drop_frames_allowed = cpi->oxcf.allow_df && cpi->buffered_mode; - if (!cm->use_bilinear_mc_filter) cm->mcomp_filter_type = SIXTAP; else @@ -1793,6 +1456,7 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) { cpi->last_q[0] = cpi->oxcf.fixed_q; cpi->last_q[1] = cpi->oxcf.fixed_q; + cpi->last_boosted_qindex = cpi->oxcf.fixed_q; } cpi->Speed = cpi->oxcf.cpu_used; @@ -1810,7 +1474,6 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->alt_ref_source = NULL; cpi->is_src_frame_alt_ref = 0; - #if 0 // Experimental RD Code cpi->frame_distortion = 0; @@ -1839,6 +1502,26 @@ static void cal_mvsadcosts(int *mvsadcost[2]) while (++i <= mvfp_max); } +#if CONFIG_HIGH_PRECISION_MV +static void cal_mvsadcosts_hp(int *mvsadcost[2]) +{ + int i = 1; + + mvsadcost [0] [0] = 300; + mvsadcost [1] [0] = 300; + + do + { + double z = 256 * (2 * (log2f(8 * i) + .6)); + mvsadcost [0][i] = (int) z; + mvsadcost [1][i] = (int) z; + mvsadcost [0][-i] = (int) z; + mvsadcost [1][-i] = (int) z; + } + while (++i <= mvfp_max_hp); +} +#endif + VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) { int i; @@ -1885,9 +1568,11 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) cpi->frames_till_gf_update_due = 0; cpi->gf_overspend_bits = 0; cpi->non_gf_bitrate_adjustment = 0; - cpi->prob_last_coded = 128; - cpi->prob_gf_coded = 128; - cpi->prob_intra_coded = 63; + cm->prob_last_coded = 128; + cm->prob_gf_coded = 128; + cm->prob_intra_coded = 63; + for ( i = 0; i < COMP_PRED_CONTEXTS; i++ ) + cm->prob_comppred[i] = 128; // Prime the recent reference frame useage counters. // Hereafter they will be maintained as a sort of moving average @@ -1912,50 +1597,24 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) CHECK_MEM_ERROR(cpi->lf_ref_frame, vpx_calloc((cpi->common.mb_rows+2) * (cpi->common.mb_cols+2), sizeof(int))); // Create the encoder segmentation map and set all entries to 0 - CHECK_MEM_ERROR(cpi->segmentation_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + CHECK_MEM_ERROR(cpi->segmentation_map, vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1)); + + // And a copy in common for temporal coding + CHECK_MEM_ERROR(cm->last_frame_seg_map, + vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1)); + CHECK_MEM_ERROR(cpi->active_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); vpx_memset(cpi->active_map , 1, (cpi->common.mb_rows * cpi->common.mb_cols)); cpi->active_map_enabled = 0; -#if 0 - // Experimental code for lagged and one pass - // Initialise one_pass GF frames stats - // Update stats used for GF selection - if (cpi->pass == 0) + for (i = 0; i < ( sizeof(cpi->mbgraph_stats) / + sizeof(cpi->mbgraph_stats[0]) ); i++) { - cpi->one_pass_frame_index = 0; - - for (i = 0; i < MAX_LAG_BUFFERS; i++) - { - cpi->one_pass_frame_stats[i].frames_so_far = 0; - cpi->one_pass_frame_stats[i].frame_intra_error = 0.0; - cpi->one_pass_frame_stats[i].frame_coded_error = 0.0; - cpi->one_pass_frame_stats[i].frame_pcnt_inter = 0.0; - cpi->one_pass_frame_stats[i].frame_pcnt_motion = 0.0; - cpi->one_pass_frame_stats[i].frame_mvr = 0.0; - cpi->one_pass_frame_stats[i].frame_mvr_abs = 0.0; - cpi->one_pass_frame_stats[i].frame_mvc = 0.0; - cpi->one_pass_frame_stats[i].frame_mvc_abs = 0.0; - } + CHECK_MEM_ERROR(cpi->mbgraph_stats[i].mb_stats, + vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols * + sizeof(*cpi->mbgraph_stats[i].mb_stats), + 1)); } -#endif - - // Should we use the cyclic refresh method. - // Currently this is tied to error resilliant mode - cpi->cyclic_refresh_mode_enabled = cpi->oxcf.error_resilient_mode; - cpi->cyclic_refresh_mode_max_mbs_perframe = (cpi->common.mb_rows * cpi->common.mb_cols) / 40; - cpi->cyclic_refresh_mode_index = 0; - cpi->cyclic_refresh_q = 32; - - if (cpi->cyclic_refresh_mode_enabled) - { - CHECK_MEM_ERROR(cpi->cyclic_refresh_map, vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1)); - } - else - cpi->cyclic_refresh_map = (signed char *) NULL; - - // Test function for segmentation - //segmentation_test_function((VP8_PTR) cpi); #ifdef ENTROPY_STATS init_context_counters(); @@ -2018,13 +1677,10 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) cpi->ni_av_qi = cpi->oxcf.worst_allowed_q; cpi->ni_tot_qi = 0; cpi->ni_frames = 0; + cpi->tot_q = 0.0; + cpi->avg_q = vp8_convert_qindex_to_q( cpi->oxcf.worst_allowed_q ); cpi->total_byte_count = 0; - cpi->drop_frame = 0; - cpi->drop_count = 0; - cpi->max_drop_count = 0; - cpi->max_consec_dropped_frames = 4; - cpi->rate_correction_factor = 1.0; cpi->key_frame_rate_correction_factor = 1.0; cpi->gf_rate_correction_factor = 1.0; @@ -2037,6 +1693,15 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) cal_mvsadcosts(cpi->mb.mvsadcost); +#if CONFIG_HIGH_PRECISION_MV + cpi->mb.mvcost_hp[0] = &cpi->mb.mvcosts_hp[0][mv_max_hp+1]; + cpi->mb.mvcost_hp[1] = &cpi->mb.mvcosts_hp[1][mv_max_hp+1]; + cpi->mb.mvsadcost_hp[0] = &cpi->mb.mvsadcosts_hp[0][mvfp_max_hp+1]; + cpi->mb.mvsadcost_hp[1] = &cpi->mb.mvsadcosts_hp[1][mvfp_max_hp+1]; + + cal_mvsadcosts_hp(cpi->mb.mvsadcost_hp); +#endif + for (i = 0; i < KEY_FRAME_CONTEXT; i++) { cpi->prior_key_frame_distance[i] = (int)cpi->output_frame_rate; @@ -2045,6 +1710,9 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) #ifdef OUTPUT_YUV_SRC yuv_file = fopen("bd.yuv", "ab"); #endif +#ifdef OUTPUT_YUV_REC + yuv_rec_file = fopen("rec.yuv", "wb"); +#endif #if 0 framepsnr = fopen("framepsnr.stt", "a"); @@ -2053,8 +1721,6 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) cpi->output_pkt_list = oxcf->output_pkt_list; -#if !(CONFIG_REALTIME_ONLY) - if (cpi->pass == 1) { vp8_init_first_pass(cpi); @@ -2071,15 +1737,6 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) vp8_init_second_pass(cpi); } -#endif - - if (cpi->compressor_speed == 2) - { - cpi->cpu_freq = 0; //vp8_get_processor_freq(); - cpi->avg_encode_time = 0; - cpi->avg_pick_mode_time = 0; - } - vp8_set_speed_features(cpi); // Set starting values of RD threshold multipliers (128 = *1) @@ -2092,10 +1749,6 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) init_mv_ref_counts(); #endif -#if CONFIG_MULTITHREAD - vp8cx_create_encoder_threads(cpi); -#endif - cpi->fn_ptr[BLOCK_16X16].sdf = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x16); cpi->fn_ptr[BLOCK_16X16].vf = VARIANCE_INVOKE(&cpi->rtcd.variance, var16x16); cpi->fn_ptr[BLOCK_16X16].svf = VARIANCE_INVOKE(&cpi->rtcd.variance, subpixvar16x16); @@ -2168,6 +1821,12 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) vp8_loop_filter_init(cm); cpi->common.error.setjmp = 0; + +#if CONFIG_UVINTRA + vp8_zero(cpi->y_uv_mode_count) +#endif + + return (VP8_PTR) cpi; } @@ -2176,21 +1835,18 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) void vp8_remove_compressor(VP8_PTR *ptr) { VP8_COMP *cpi = (VP8_COMP *)(*ptr); + int i; if (!cpi) return; if (cpi && (cpi->common.current_video_frame > 0)) { -#if !(CONFIG_REALTIME_ONLY) - if (cpi->pass == 2) { vp8_end_second_pass(cpi); } -#endif - #ifdef ENTROPY_STATS print_context_counters(); print_tree_update_probs(); @@ -2199,6 +1855,9 @@ void vp8_remove_compressor(VP8_PTR *ptr) #if CONFIG_INTERNAL_STATS + vp8_clear_system_state(); + + printf("\n8x8-4x4:%d-%d\n", cpi->t8x8_count, cpi->t4x4_count); if (cpi->pass != 1) { FILE *f = fopen("opsnr.stt", "a"); @@ -2206,7 +1865,9 @@ void vp8_remove_compressor(VP8_PTR *ptr) - cpi->first_time_stamp_ever) / 10000000.000; double total_encode_time = (cpi->time_receive_data + cpi->time_compress_data) / 1000.000; double dr = (double)cpi->bytes * (double) 8 / (double)1000 / time_encoded; - +#if defined(MODE_STATS) + print_mode_contexts(&cpi->common); +#endif if (cpi->b_calculate_psnr) { YV12_BUFFER_CONFIG *lst_yv12 = &cpi->common.yv12_fb[cpi->common.lst_fb_idx]; @@ -2219,6 +1880,9 @@ void vp8_remove_compressor(VP8_PTR *ptr) fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%8.0f\n", dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim, total_encode_time); +// fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%8.0f %10ld\n", +// dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim, +// total_encode_time, cpi->tot_recode_hits); } if (cpi->b_calculate_ssimg) @@ -2227,33 +1891,11 @@ void vp8_remove_compressor(VP8_PTR *ptr) fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f\n", dr, cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count, cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time); +// fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f %10ld\n", dr, +// cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count, +// cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time, cpi->tot_recode_hits); } - fclose(f); -#if 0 - f = fopen("qskip.stt", "a"); - fprintf(f, "minq:%d -maxq:%d skipture:skipfalse = %d:%d\n", cpi->oxcf.best_allowed_q, cpi->oxcf.worst_allowed_q, skiptruecount, skipfalsecount); - fclose(f); -#endif - - } - -#endif - - -#ifdef SPEEDSTATS - - if (cpi->compressor_speed == 2) - { - int i; - FILE *f = fopen("cxspeed.stt", "a"); - cnt_pm /= cpi->common.MBs; - - for (i = 0; i < 16; i++) - fprintf(f, "%5d", frames_at_speed[i]); - - fprintf(f, "\n"); - //fprintf(f, "%10d PM %10d %10d %10d EF %10d %10d %10d\n", cpi->Speed, cpi->avg_pick_mode_time, (tot_pm/cnt_pm), cnt_pm, cpi->avg_encode_time, 0, 0); fclose(f); } @@ -2263,11 +1905,35 @@ void vp8_remove_compressor(VP8_PTR *ptr) #ifdef MODE_STATS { extern int count_mb_seg[4]; - FILE *f = fopen("modes.stt", "a"); - double dr = (double)cpi->oxcf.frame_rate * (double)bytes * (double)8 / (double)count / (double)1000 ; + char modes_stats_file[250]; + FILE *f; + double dr = (double)cpi->oxcf.frame_rate * (double)cpi->bytes * (double)8 / (double)cpi->count / (double)1000 ; + sprintf(modes_stats_file, "modes_q%03d.stt",cpi->common.base_qindex); + f = fopen(modes_stats_file, "w"); fprintf(f, "intra_mode in Intra Frames:\n"); - fprintf(f, "Y: %8d, %8d, %8d, %8d, %8d\n", y_modes[0], y_modes[1], y_modes[2], y_modes[3], y_modes[4]); + fprintf(f, "Y: %8d, %8d, %8d, %8d, %8d, %8d\n", y_modes[0], y_modes[1], y_modes[2], y_modes[3], y_modes[4], y_modes[5]); + fprintf(f, "I8:%8d, %8d, %8d, %8d\n", i8x8_modes[0], i8x8_modes[1], i8x8_modes[2], i8x8_modes[3]); fprintf(f, "UV:%8d, %8d, %8d, %8d\n", uv_modes[0], uv_modes[1], uv_modes[2], uv_modes[3]); + fprintf(f, "KeyFrame Y-UV:\n"); + { + int i; + for(i=0;iy_uv_mode_count[i][0], + cpi->y_uv_mode_count[i][1], cpi->y_uv_mode_count[i][2], cpi->y_uv_mode_count[i][3]); + } + } +#endif fprintf(f, "B: "); { int i; @@ -2280,10 +1946,14 @@ void vp8_remove_compressor(VP8_PTR *ptr) } fprintf(f, "Modes in Inter Frames:\n"); - fprintf(f, "Y: %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d\n", - inter_y_modes[0], inter_y_modes[1], inter_y_modes[2], inter_y_modes[3], inter_y_modes[4], - inter_y_modes[5], inter_y_modes[6], inter_y_modes[7], inter_y_modes[8], inter_y_modes[9]); - fprintf(f, "UV:%8d, %8d, %8d, %8d\n", inter_uv_modes[0], inter_uv_modes[1], inter_uv_modes[2], inter_uv_modes[3]); + fprintf(f, + "Y: %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d\n", + inter_y_modes[0], inter_y_modes[1], inter_y_modes[2], + inter_y_modes[3], inter_y_modes[4], inter_y_modes[5], + inter_y_modes[6], inter_y_modes[7], inter_y_modes[8], + inter_y_modes[9], inter_y_modes[10]); + fprintf(f, "UV:%8d, %8d, %8d, %8d\n", inter_uv_modes[0], + inter_uv_modes[1], inter_uv_modes[2], inter_uv_modes[3]); fprintf(f, "B: "); { int i; @@ -2296,9 +1966,6 @@ void vp8_remove_compressor(VP8_PTR *ptr) } fprintf(f, "P:%8d, %8d, %8d, %8d\n", count_mb_seg[0], count_mb_seg[1], count_mb_seg[2], count_mb_seg[3]); fprintf(f, "PB:%8d, %8d, %8d, %8d\n", inter_b_modes[LEFT4X4], inter_b_modes[ABOVE4X4], inter_b_modes[ZERO4X4], inter_b_modes[NEW4X4]); - - - fclose(f); } #endif @@ -2370,14 +2037,14 @@ void vp8_remove_compressor(VP8_PTR *ptr) } -#if CONFIG_MULTITHREAD - vp8cx_remove_encoder_threads(cpi); -#endif - dealloc_compressor_data(cpi); vpx_free(cpi->mb.ss); vpx_free(cpi->tok); - vpx_free(cpi->cyclic_refresh_map); + + for (i = 0; i < sizeof(cpi->mbgraph_stats) / sizeof(cpi->mbgraph_stats[0]); i++) + { + vpx_free(cpi->mbgraph_stats[i].mb_stats); + } vp8_remove_common(&cpi->common); vpx_free(cpi); @@ -2386,6 +2053,9 @@ void vp8_remove_compressor(VP8_PTR *ptr) #ifdef OUTPUT_YUV_SRC fclose(yuv_file); #endif +#ifdef OUTPUT_YUV_REC + fclose(yuv_rec_file); +#endif #if 0 @@ -2596,10 +2266,9 @@ int vp8_update_entropy(VP8_PTR comp, int update) } -#if OUTPUT_YUV_SRC -void vp8_write_yuv_frame(const char *name, YV12_BUFFER_CONFIG *s) +#ifdef OUTPUT_YUV_SRC +void vp8_write_yuv_frame(YV12_BUFFER_CONFIG *s) { - FILE *yuv_file = fopen(name, "ab"); unsigned char *src = s->y_buffer; int h = s->y_height; @@ -2629,113 +2298,49 @@ void vp8_write_yuv_frame(const char *name, YV12_BUFFER_CONFIG *s) src += s->uv_stride; } while (--h); - - fclose(yuv_file); } #endif - -static void scale_and_extend_source(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) +#ifdef OUTPUT_YUV_REC +void vp8_write_yuv_rec_frame(VP8_COMMON *cm) { - VP8_COMMON *cm = &cpi->common; + YV12_BUFFER_CONFIG *s = cm->frame_to_show; + unsigned char *src = s->y_buffer; + int h = cm->Height; - // are we resizing the image - if (cm->horiz_scale != 0 || cm->vert_scale != 0) + do { -#if CONFIG_SPATIAL_RESAMPLING - int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); - int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); - int tmp_height; - - if (cm->vert_scale == 3) - tmp_height = 9; - else - tmp_height = 11; - - Scale2Ratio(cm->horiz_scale, &hr, &hs); - Scale2Ratio(cm->vert_scale, &vr, &vs); - - vp8_scale_frame(sd, &cpi->scaled_source, cm->temp_scale_frame.y_buffer, - tmp_height, hs, hr, vs, vr, 0); - - vp8_yv12_extend_frame_borders(&cpi->scaled_source); - cpi->Source = &cpi->scaled_source; -#endif + fwrite(src, s->y_width, 1, yuv_rec_file); + src += s->y_stride; } - else - cpi->Source = sd; -} + while (--h); + src = s->u_buffer; + h = (cm->Height+1)/2; -static void resize_key_frame(VP8_COMP *cpi) -{ -#if CONFIG_SPATIAL_RESAMPLING - VP8_COMMON *cm = &cpi->common; - - // Do we need to apply resampling for one pass cbr. - // In one pass this is more limited than in two pass cbr - // The test and any change is only made one per key frame sequence - if (cpi->oxcf.allow_spatial_resampling && (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) + do { - int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); - int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); - int new_width, new_height; - - // If we are below the resample DOWN watermark then scale down a notch. - if (cpi->buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100)) - { - cm->horiz_scale = (cm->horiz_scale < ONETWO) ? cm->horiz_scale + 1 : ONETWO; - cm->vert_scale = (cm->vert_scale < ONETWO) ? cm->vert_scale + 1 : ONETWO; - } - // Should we now start scaling back up - else if (cpi->buffer_level > (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100)) - { - cm->horiz_scale = (cm->horiz_scale > NORMAL) ? cm->horiz_scale - 1 : NORMAL; - cm->vert_scale = (cm->vert_scale > NORMAL) ? cm->vert_scale - 1 : NORMAL; - } - - // Get the new hieght and width - Scale2Ratio(cm->horiz_scale, &hr, &hs); - Scale2Ratio(cm->vert_scale, &vr, &vs); - new_width = ((hs - 1) + (cpi->oxcf.Width * hr)) / hs; - new_height = ((vs - 1) + (cpi->oxcf.Height * vr)) / vs; - - // If the image size has changed we need to reallocate the buffers - // and resample the source image - if ((cm->Width != new_width) || (cm->Height != new_height)) - { - cm->Width = new_width; - cm->Height = new_height; - vp8_alloc_compressor_data(cpi); - scale_and_extend_source(cpi->un_scaled_source, cpi); - } + fwrite(src, s->uv_width, 1, yuv_rec_file); + src += s->uv_stride; } + while (--h); -#endif + src = s->v_buffer; + h = (cm->Height+1)/2; + + do + { + fwrite(src, s->uv_width, 1, yuv_rec_file); + src += s->uv_stride; + } + while (--h); } - +#endif static void update_alt_ref_frame_stats(VP8_COMP *cpi) { VP8_COMMON *cm = &cpi->common; - // Select an interval before next GF or altref - if (!cpi->auto_gold) - cpi->frames_till_gf_update_due = cpi->goldfreq; - - if ((cpi->pass != 2) && cpi->frames_till_gf_update_due) - { - cpi->current_gf_interval = cpi->frames_till_gf_update_due; - - // Set the bits per frame that we should try and recover in subsequent inter frames - // to account for the extra GF spend... note that his does not apply for GF updates - // that occur coincident with a key frame as the extra cost of key frames is dealt - // with elsewhere. - - cpi->gf_overspend_bits += cpi->projected_frame_size; - cpi->non_gf_bitrate_adjustment = cpi->gf_overspend_bits / cpi->frames_till_gf_update_due; - } - // Update data structure that monitors level of reference to last GF vpx_memset(cpi->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); cpi->gf_active_count = cm->mb_rows * cm->mb_cols; @@ -2758,29 +2363,6 @@ static void update_golden_frame_stats(VP8_COMP *cpi) // Update the Golden frame usage counts. if (cm->refresh_golden_frame) { - // Select an interval before next GF - if (!cpi->auto_gold) - cpi->frames_till_gf_update_due = cpi->goldfreq; - - if ((cpi->pass != 2) && (cpi->frames_till_gf_update_due > 0)) - { - cpi->current_gf_interval = cpi->frames_till_gf_update_due; - - // Set the bits per frame that we should try and recover in subsequent inter frames - // to account for the extra GF spend... note that his does not apply for GF updates - // that occur coincident with a key frame as the extra cost of key frames is dealt - // with elsewhere. - if ((cm->frame_type != KEY_FRAME) && !cpi->source_alt_ref_active) - { - // Calcluate GF bits to be recovered - // Projected size - av frame bits available for inter frames for clip as a whole - cpi->gf_overspend_bits += (cpi->projected_frame_size - cpi->inter_frame_target); - } - - cpi->non_gf_bitrate_adjustment = cpi->gf_overspend_bits / cpi->frames_till_gf_update_due; - - } - // Update data structure that monitors level of reference to last GF vpx_memset(cpi->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); cpi->gf_active_count = cm->mb_rows * cm->mb_cols; @@ -2843,120 +2425,6 @@ static void update_golden_frame_stats(VP8_COMP *cpi) } } -// This function updates the reference frame probability estimates that -// will be used during mode selection -static void update_rd_ref_frame_probs(VP8_COMP *cpi) -{ - VP8_COMMON *cm = &cpi->common; - -#if 0 - const int *const rfct = cpi->recent_ref_frame_usage; - const int rf_intra = rfct[INTRA_FRAME]; - const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; - - if (cm->frame_type == KEY_FRAME) - { - cpi->prob_intra_coded = 255; - cpi->prob_last_coded = 128; - cpi->prob_gf_coded = 128; - } - else if (!(rf_intra + rf_inter)) - { - // This is a trap in case this function is called with cpi->recent_ref_frame_usage[] blank. - cpi->prob_intra_coded = 63; - cpi->prob_last_coded = 128; - cpi->prob_gf_coded = 128; - } - else - { - cpi->prob_intra_coded = (rf_intra * 255) / (rf_intra + rf_inter); - - if (cpi->prob_intra_coded < 1) - cpi->prob_intra_coded = 1; - - if ((cm->frames_since_golden > 0) || cpi->source_alt_ref_active) - { - cpi->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; - - if (cpi->prob_last_coded < 1) - cpi->prob_last_coded = 1; - - cpi->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) - ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; - - if (cpi->prob_gf_coded < 1) - cpi->prob_gf_coded = 1; - } - } - -#else - const int *const rfct = cpi->count_mb_ref_frame_usage; - const int rf_intra = rfct[INTRA_FRAME]; - const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; - - if (cm->frame_type == KEY_FRAME) - { - cpi->prob_intra_coded = 255; - cpi->prob_last_coded = 128; - cpi->prob_gf_coded = 128; - } - else if (!(rf_intra + rf_inter)) - { - // This is a trap in case this function is called with cpi->recent_ref_frame_usage[] blank. - cpi->prob_intra_coded = 63; - cpi->prob_last_coded = 128; - cpi->prob_gf_coded = 128; - } - else - { - cpi->prob_intra_coded = (rf_intra * 255) / (rf_intra + rf_inter); - - if (cpi->prob_intra_coded < 1) - cpi->prob_intra_coded = 1; - - cpi->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; - - if (cpi->prob_last_coded < 1) - cpi->prob_last_coded = 1; - - cpi->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) - ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; - - if (cpi->prob_gf_coded < 1) - cpi->prob_gf_coded = 1; - } - - // update reference frame costs since we can do better than what we got last frame. - - if (cpi->common.refresh_alt_ref_frame) - { - cpi->prob_intra_coded += 40; - cpi->prob_last_coded = 200; - cpi->prob_gf_coded = 1; - } - else if (cpi->common.frames_since_golden == 0) - { - cpi->prob_last_coded = 214; - cpi->prob_gf_coded = 1; - } - else if (cpi->common.frames_since_golden == 1) - { - cpi->prob_last_coded = 192; - cpi->prob_gf_coded = 220; - } - else if (cpi->source_alt_ref_active) - { - //int dist = cpi->common.frames_till_alt_ref_frame + cpi->common.frames_since_golden; - cpi->prob_gf_coded -= 20; - - if (cpi->prob_gf_coded < 10) - cpi->prob_gf_coded = 10; - } - -#endif -} - - // 1 = key, 0 = inter static int decide_key_frame(VP8_COMP *cpi) { @@ -2972,50 +2440,6 @@ static int decide_key_frame(VP8_COMP *cpi) // Clear down mmx registers vp8_clear_system_state(); //__asm emms; - if ((cpi->compressor_speed == 2) && (cpi->Speed >= 5) && (cpi->sf.RD == 0)) - { - double change = 1.0 * abs((int)(cpi->intra_error - cpi->last_intra_error)) / (1 + cpi->last_intra_error); - double change2 = 1.0 * abs((int)(cpi->prediction_error - cpi->last_prediction_error)) / (1 + cpi->last_prediction_error); - double minerror = cm->MBs * 256; - -#if 0 - - if (10 * cpi->intra_error / (1 + cpi->prediction_error) < 15 - && cpi->prediction_error > minerror - && (change > .25 || change2 > .25)) - { - FILE *f = fopen("intra_inter.stt", "a"); - - if (cpi->prediction_error <= 0) - cpi->prediction_error = 1; - - fprintf(f, "%d %d %d %d %14.4f\n", - cm->current_video_frame, - (int) cpi->prediction_error, - (int) cpi->intra_error, - (int)((10 * cpi->intra_error) / cpi->prediction_error), - change); - - fclose(f); - } - -#endif - - cpi->last_intra_error = cpi->intra_error; - cpi->last_prediction_error = cpi->prediction_error; - - if (10 * cpi->intra_error / (1 + cpi->prediction_error) < 15 - && cpi->prediction_error > minerror - && (change > .25 || change2 > .25)) - { - /*(change > 1.4 || change < .75)&& cpi->this_frame_percent_intra > cpi->last_frame_percent_intra + 3*/ - return TRUE; - } - - return FALSE; - - } - // If the following are true we might as well code a key frame if (((cpi->this_frame_percent_intra == 100) && (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra + 2))) || @@ -3041,27 +2465,37 @@ static int decide_key_frame(VP8_COMP *cpi) return code_key_frame; } -#if !CONFIG_EXTEND_QRANGE -#define FIRSTPASS_QINDEX 26 -#else -#define FIRSTPASS_QINDEX 49 -#endif +int find_fp_qindex() +{ + int i; + + for ( i = 0; i < QINDEX_RANGE; i++ ) + { + if ( vp8_convert_qindex_to_q(i) >= 30.0 ) + { + break; + } + } + + if ( i == QINDEX_RANGE ) + i--; + + return i; +} -#if !(CONFIG_REALTIME_ONLY) static void Pass1Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, unsigned int *frame_flags) { (void) size; (void) dest; (void) frame_flags; - vp8_set_quantizer(cpi, 26); - scale_and_extend_source(cpi->un_scaled_source, cpi); + + vp8_set_quantizer(cpi, find_fp_qindex()); vp8_first_pass(cpi); } -#endif - -#if 0 +//#define WRITE_RECON_BUFFER 1 +#if WRITE_RECON_BUFFER void write_cx_frame_to_file(YV12_BUFFER_CONFIG *frame, int this_frame) { @@ -3074,26 +2508,28 @@ void write_cx_frame_to_file(YV12_BUFFER_CONFIG *frame, int this_frame) yframe = fopen(filename, "wb"); for (i = 0; i < frame->y_height; i++) - fwrite(frame->y_buffer + i * frame->y_stride, frame->y_width, 1, yframe); + fwrite(frame->y_buffer + i * frame->y_stride, + frame->y_width, 1, yframe); fclose(yframe); sprintf(filename, "cx\\u%04d.raw", this_frame); yframe = fopen(filename, "wb"); for (i = 0; i < frame->uv_height; i++) - fwrite(frame->u_buffer + i * frame->uv_stride, frame->uv_width, 1, yframe); + fwrite(frame->u_buffer + i * frame->uv_stride, + frame->uv_width, 1, yframe); fclose(yframe); sprintf(filename, "cx\\v%04d.raw", this_frame); yframe = fopen(filename, "wb"); for (i = 0; i < frame->uv_height; i++) - fwrite(frame->v_buffer + i * frame->uv_stride, frame->uv_width, 1, yframe); + fwrite(frame->v_buffer + i * frame->uv_stride, + frame->uv_width, 1, yframe); fclose(yframe); } #endif -// return of 0 means drop frame // Function to test for conditions that indeicate we should loop // back and recode a frame. @@ -3257,11 +2693,6 @@ void loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm) cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer); } -#if CONFIG_MULTITHREAD - if (cpi->b_multi_threaded) - sem_post(&cpi->h_event_end_lpf); /* signal that we have set filter_level */ -#endif - if (cm->filter_level > 0) { vp8cx_set_alt_lf_level(cpi, cm->filter_level); @@ -3272,6 +2703,106 @@ void loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm) } +// This function updates the reference frame prediction stats +static void update_refpred_stats( VP8_COMP *cpi ) +{ + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & cpi->mb.e_mbd; + + int mb_row, mb_col; + int i; + int tot_count; + int ref_pred_count[PREDICTION_PROBS][2]; + vp8_prob new_pred_probs[PREDICTION_PROBS]; + unsigned char pred_context; + unsigned char pred_flag; + + int old_cost, new_cost; + + // Clear the prediction hit counters + vpx_memset(ref_pred_count, 0, sizeof(ref_pred_count)); + + // Set the prediction probability structures to defaults + if ( cm->frame_type == KEY_FRAME ) + { + // Set the prediction probabilities to defaults + cm->ref_pred_probs[0] = 120; + cm->ref_pred_probs[1] = 80; + cm->ref_pred_probs[2] = 40; + + vpx_memset(cpi->ref_pred_probs_update, 0, + sizeof(cpi->ref_pred_probs_update) ); + } + else + { + // For non-key frames....... + + // Scan through the macroblocks and collate prediction counts. + xd->mode_info_context = cm->mi; + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + // Get the prediction context and status + pred_flag = get_pred_flag( xd, PRED_REF ); + pred_context = get_pred_context( cm, xd, PRED_REF ); + + // Count prediction success + ref_pred_count[pred_context][pred_flag]++; + + // Step on to the next mb + xd->mode_info_context++; + } + + // this is to account for the border in mode_info_context + xd->mode_info_context++; + } + + // From the prediction counts set the probabilities for each context + for ( i = 0; i < PREDICTION_PROBS; i++ ) + { + // MB reference frame not relevent to key frame encoding + if ( cm->frame_type != KEY_FRAME ) + { + // Work out the probabilities for the reference frame predictor + tot_count = ref_pred_count[i][0] + ref_pred_count[i][1]; + if ( tot_count ) + { + new_pred_probs[i] = + ( ref_pred_count[i][0] * 255 ) / tot_count; + + // Clamp to minimum allowed value + new_pred_probs[i] += !new_pred_probs[i]; + } + else + new_pred_probs[i] = 128; + } + else + new_pred_probs[i] = 128; + + // Decide whether or not to update the reference frame probs. + // Returned costs are in 1/256 bit units. + old_cost = + (ref_pred_count[i][0] * vp8_cost_zero(cm->ref_pred_probs[i])) + + (ref_pred_count[i][1] * vp8_cost_one(cm->ref_pred_probs[i])); + + new_cost = + (ref_pred_count[i][0] * vp8_cost_zero(new_pred_probs[i])) + + (ref_pred_count[i][1] * vp8_cost_one(new_pred_probs[i])); + + // Cost saving must be >= 8 bits (2048 in these units) + if ( (old_cost - new_cost) >= 2048 ) + { + cpi->ref_pred_probs_update[i] = 1; + cm->ref_pred_probs[i] = new_pred_probs[i]; + } + else + cpi->ref_pred_probs_update[i] = 0; + + } + } +} + static void encode_frame_to_data_rate ( VP8_COMP *cpi, @@ -3280,6 +2811,9 @@ static void encode_frame_to_data_rate unsigned int *frame_flags ) { + VP8_COMMON *cm = &cpi->common; + MACROBLOCKD *xd = &cpi->mb.e_mbd; + int Q; int frame_over_shoot_limit; int frame_under_shoot_limit; @@ -3295,50 +2829,22 @@ static void encode_frame_to_data_rate int zbin_oq_low = 0; int top_index; int bottom_index; - VP8_COMMON *cm = &cpi->common; int active_worst_qchanged = FALSE; int overshoot_seen = FALSE; int undershoot_seen = FALSE; - int drop_mark = cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100; - int drop_mark75 = drop_mark * 2 / 3; - int drop_mark50 = drop_mark / 4; - int drop_mark25 = drop_mark / 8; - // Clear down mmx registers to allow floating point in what follows vp8_clear_system_state(); - // Test code for segmentation of gf/arf (0,0) - //segmentation_test_function((VP8_PTR) cpi); - - if (cpi->compressor_speed == 2) + // For an alt ref frame in 2 pass we skip the call to the second + // pass function that sets the target bandwidth so must set it here + if (cpi->common.refresh_alt_ref_frame) { - if(cpi->oxcf.auto_key && cm->frame_type != KEY_FRAME) - { - if(cpi->force_next_frame_intra) - { - cm->frame_type = KEY_FRAME; /* delayed intra frame */ - } - } - cpi->force_next_frame_intra = 0; + cpi->per_frame_bandwidth = cpi->twopass.gf_bits; // Per frame bit target for the alt ref frame + cpi->target_bandwidth = cpi->twopass.gf_bits * cpi->output_frame_rate; // per second target bitrate } - // For an alt ref frame in 2 pass we skip the call to the second pass function that sets the target bandwidth -#if !(CONFIG_REALTIME_ONLY) - - if (cpi->pass == 2) - { - if (cpi->common.refresh_alt_ref_frame) - { - cpi->per_frame_bandwidth = cpi->twopass.gf_bits; // Per frame bit target for the alt ref frame - cpi->target_bandwidth = cpi->twopass.gf_bits * cpi->output_frame_rate; // per second target bitrate - } - } - else -#endif - cpi->per_frame_bandwidth = (int)(cpi->target_bandwidth / cpi->output_frame_rate); - // Default turn off buffer to buffer copying cm->copy_buffer_to_gf = 0; cm->copy_buffer_to_arf = 0; @@ -3352,12 +2858,9 @@ static void encode_frame_to_data_rate // is above a threshold cpi->zbin_mode_boost = 0; cpi->zbin_mode_boost_enabled = TRUE; - if (cpi->pass == 2) + if ( cpi->gfu_boost <= 400 ) { - if ( cpi->gfu_boost <= 400 ) - { - cpi->zbin_mode_boost_enabled = FALSE; - } + cpi->zbin_mode_boost_enabled = FALSE; } // Current default encoder behaviour for the altref sign bias @@ -3376,10 +2879,8 @@ static void encode_frame_to_data_rate cm->frame_type = KEY_FRAME; } - // Set default state for segment and mode based loop filter update flags - cpi->mb.e_mbd.update_mb_segmentation_map = 0; - cpi->mb.e_mbd.update_mb_segmentation_data = 0; - cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; + // Set default state for segment based loop filter update flags + xd->mode_ref_lf_delta_update = 0; // Set various flags etc to special state if it is a key frame if (cm->frame_type == KEY_FRAME) @@ -3390,10 +2891,10 @@ static void encode_frame_to_data_rate setup_features(cpi); // If segmentation is enabled force a map update for key frames - if (cpi->mb.e_mbd.segmentation_enabled) + if (xd->segmentation_enabled) { - cpi->mb.e_mbd.update_mb_segmentation_map = 1; - cpi->mb.e_mbd.update_mb_segmentation_data = 1; + xd->update_mb_segmentation_map = 1; + xd->update_mb_segmentation_data = 1; } // The alternate reference frame cannot be active for a key frame @@ -3406,107 +2907,14 @@ static void encode_frame_to_data_rate } } - // Test code for segmentation - //if ( (cm->frame_type == KEY_FRAME) || ((cm->current_video_frame % 2) == 0)) - //if ( (cm->current_video_frame % 2) == 0 ) - // enable_segmentation((VP8_PTR)cpi); - //else - // disable_segmentation((VP8_PTR)cpi); +//#if !CONFIG_COMPRED + // This function has been deprecated for now but we may want to do + // something here at a late date + //update_rd_ref_frame_probs(cpi); +//#endif -#if 0 - // Experimental code for lagged compress and one pass - // Initialise one_pass GF frames stats - // Update stats used for GF selection - //if ( cpi->pass == 0 ) - { - cpi->one_pass_frame_index = cm->current_video_frame % MAX_LAG_BUFFERS; - - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frames_so_far = 0; - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_intra_error = 0.0; - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_coded_error = 0.0; - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_pcnt_inter = 0.0; - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_pcnt_motion = 0.0; - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvr = 0.0; - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvr_abs = 0.0; - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvc = 0.0; - cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvc_abs = 0.0; - } -#endif - - update_rd_ref_frame_probs(cpi); - - if (cpi->drop_frames_allowed) - { - // The reset to decimation 0 is only done here for one pass. - // Once it is set two pass leaves decimation on till the next kf. - if ((cpi->buffer_level > drop_mark) && (cpi->decimation_factor > 0)) - cpi->decimation_factor --; - - if (cpi->buffer_level > drop_mark75 && cpi->decimation_factor > 0) - cpi->decimation_factor = 1; - - else if (cpi->buffer_level < drop_mark25 && (cpi->decimation_factor == 2 || cpi->decimation_factor == 3)) - { - cpi->decimation_factor = 3; - } - else if (cpi->buffer_level < drop_mark50 && (cpi->decimation_factor == 1 || cpi->decimation_factor == 2)) - { - cpi->decimation_factor = 2; - } - else if (cpi->buffer_level < drop_mark75 && (cpi->decimation_factor == 0 || cpi->decimation_factor == 1)) - { - cpi->decimation_factor = 1; - } - - //vpx_log("Encoder: Decimation Factor: %d \n",cpi->decimation_factor); - } - - // The following decimates the frame rate according to a regular pattern (i.e. to 1/2 or 2/3 frame rate) - // This can be used to help prevent buffer under-run in CBR mode. Alternatively it might be desirable in - // some situations to drop frame rate but throw more bits at each frame. - // - // Note that dropping a key frame can be problematic if spatial resampling is also active - if (cpi->decimation_factor > 0) - { - switch (cpi->decimation_factor) - { - case 1: - cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 3 / 2; - break; - case 2: - cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 5 / 4; - break; - case 3: - cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 5 / 4; - break; - } - - // Note that we should not throw out a key frame (especially when spatial resampling is enabled). - if ((cm->frame_type == KEY_FRAME)) // && cpi->oxcf.allow_spatial_resampling ) - { - cpi->decimation_count = cpi->decimation_factor; - } - else if (cpi->decimation_count > 0) - { - cpi->decimation_count --; - cpi->bits_off_target += cpi->av_per_frame_bandwidth; - if (cpi->bits_off_target > cpi->oxcf.maximum_buffer_size) - cpi->bits_off_target = cpi->oxcf.maximum_buffer_size; - - cm->current_video_frame++; - cpi->frames_since_key++; - -#if CONFIG_INTERNAL_STATS - cpi->count ++; -#endif - - cpi->buffer_level = cpi->bits_off_target; - - return; - } - else - cpi->decimation_count = cpi->decimation_factor; - } + // Test code for new segment features + init_seg_features( cpi ); // Decide how big to make the frame if (!vp8_pick_frame_size(cpi)) @@ -3516,149 +2924,83 @@ static void encode_frame_to_data_rate return; } - // Reduce active_worst_allowed_q for CBR if our buffer is getting too full. - // This has a knock on effect on active best quality as well. - // For CBR if the buffer reaches its maximum level then we can no longer - // save up bits for later frames so we might as well use them up - // on the current frame. - if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && - (cpi->buffer_level >= cpi->oxcf.optimal_buffer_level) && cpi->buffered_mode) - { - int Adjustment = cpi->active_worst_quality / 4; // Max adjustment is 1/4 - - if (Adjustment) - { - int buff_lvl_step; - - if (cpi->buffer_level < cpi->oxcf.maximum_buffer_size) - { - buff_lvl_step = (cpi->oxcf.maximum_buffer_size - cpi->oxcf.optimal_buffer_level) / Adjustment; - - if (buff_lvl_step) - Adjustment = (cpi->buffer_level - cpi->oxcf.optimal_buffer_level) / buff_lvl_step; - else - Adjustment = 0; - } - - cpi->active_worst_quality -= Adjustment; - - if(cpi->active_worst_quality < cpi->active_best_quality) - cpi->active_worst_quality = cpi->active_best_quality; - } - } + vp8_clear_system_state(); // Set an active best quality and if necessary active worst quality - // There is some odd behaviour for one pass here that needs attention. - if ( (cpi->pass == 2) || (cpi->ni_frames > 150)) + Q = cpi->active_worst_quality; + + if ( cm->frame_type == KEY_FRAME ) { - vp8_clear_system_state(); - - Q = cpi->active_worst_quality; - - if ( cm->frame_type == KEY_FRAME ) - { - if ( cpi->pass == 2 ) - { - if (cpi->gfu_boost > 600) - cpi->active_best_quality = kf_low_motion_minq[Q]; - else - cpi->active_best_quality = kf_high_motion_minq[Q]; - - // Special case for key frames forced because we have reached - // the maximum key frame interval. Here force the Q to a range - // based on the ambient Q to reduce the risk of popping - if ( cpi->this_key_frame_forced ) - { - if ( cpi->active_best_quality > cpi->avg_frame_qindex * 7/8) - cpi->active_best_quality = cpi->avg_frame_qindex * 7/8; - else if ( cpi->active_best_quality < cpi->avg_frame_qindex >> 2 ) - cpi->active_best_quality = cpi->avg_frame_qindex >> 2; - } - } - // One pass more conservative - else - cpi->active_best_quality = kf_high_motion_minq[Q]; - } - - else if (cm->refresh_golden_frame || cpi->common.refresh_alt_ref_frame) - { - // Use the lower of cpi->active_worst_quality and recent - // average Q as basis for GF/ARF Q limit unless last frame was - // a key frame. - if ( (cpi->frames_since_key > 1) && - (cpi->avg_frame_qindex < cpi->active_worst_quality) ) - { - Q = cpi->avg_frame_qindex; - - if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && - (Q < cpi->oxcf.cq_level) ) - { - Q = cpi->oxcf.cq_level; - } - } - - if ( cpi->pass == 2 ) - { - if ( cpi->gfu_boost > 1000 ) - cpi->active_best_quality = gf_low_motion_minq[Q]; - else if ( cpi->gfu_boost < 400 ) - cpi->active_best_quality = gf_high_motion_minq[Q]; - else - cpi->active_best_quality = gf_mid_motion_minq[Q]; - } - // One pass more conservative - else - cpi->active_best_quality = gf_high_motion_minq[Q]; - } + if (cpi->gfu_boost > 600) + cpi->active_best_quality = kf_low_motion_minq[Q]; else - { - cpi->active_best_quality = inter_minq[Q]; + cpi->active_best_quality = kf_high_motion_minq[Q]; - // For the constant/constrained quality mode we dont want - // the quality to rise above the cq level. - if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && - (cpi->active_best_quality < cpi->cq_target_quality) ) - { - // If we are strongly undershooting the target rate in the last - // frames then use the user passed in cq value not the auto - // cq value. - if ( cpi->rolling_actual_bits < cpi->min_frame_bandwidth ) - cpi->active_best_quality = cpi->oxcf.cq_level; - else - cpi->active_best_quality = cpi->cq_target_quality; - } - } - - // If CBR and the buffer is as full then it is reasonable to allow - // higher quality on the frames to prevent bits just going to waste. - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + // Special case for key frames forced because we have reached + // the maximum key frame interval. Here force the Q to a range + // based on the ambient Q to reduce the risk of popping + if ( cpi->this_key_frame_forced ) { - // Note that the use of >= here elliminates the risk of a devide - // by 0 error in the else if clause - if (cpi->buffer_level >= cpi->oxcf.maximum_buffer_size) + int delta_qindex; + int qindex = cpi->last_boosted_qindex; + + delta_qindex = compute_qdelta( cpi, qindex, + (qindex * 0.75) ); + + cpi->active_best_quality = qindex + delta_qindex; + if (cpi->active_best_quality < cpi->best_quality) cpi->active_best_quality = cpi->best_quality; - - else if (cpi->buffer_level > cpi->oxcf.optimal_buffer_level) - { - int Fraction = ((cpi->buffer_level - cpi->oxcf.optimal_buffer_level) * 128) / (cpi->oxcf.maximum_buffer_size - cpi->oxcf.optimal_buffer_level); - int min_qadjustment = ((cpi->active_best_quality - cpi->best_quality) * Fraction) / 128; - - cpi->active_best_quality -= min_qadjustment; - } } } - // Make sure constrained quality mode limits are adhered to for the first - // few frames of one pass encodes - else if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) + + else if (cm->refresh_golden_frame || cpi->common.refresh_alt_ref_frame) { - if ( (cm->frame_type == KEY_FRAME) || - cm->refresh_golden_frame || cpi->common.refresh_alt_ref_frame ) + // Use the lower of cpi->active_worst_quality and recent + // average Q as basis for GF/ARF Q limit unless last frame was + // a key frame. + if ( (cpi->frames_since_key > 1) && + (cpi->avg_frame_qindex < cpi->active_worst_quality) ) { - cpi->active_best_quality = cpi->best_quality; + Q = cpi->avg_frame_qindex; } - else if (cpi->active_best_quality < cpi->cq_target_quality) + + // For constrained quality dont allow Q less than the cq level + if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (Q < cpi->cq_target_quality) ) { - cpi->active_best_quality = cpi->cq_target_quality; + Q = cpi->cq_target_quality; + } + + if ( cpi->gfu_boost > 1000 ) + cpi->active_best_quality = gf_low_motion_minq[Q]; + else if ( cpi->gfu_boost < 400 ) + cpi->active_best_quality = gf_high_motion_minq[Q]; + else + cpi->active_best_quality = gf_mid_motion_minq[Q]; + + // Constrained quality use slightly lower active best. + if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY ) + { + cpi->active_best_quality = + cpi->active_best_quality * 15/16; + } + } + else + { + cpi->active_best_quality = inter_minq[Q]; + + // For the constant/constrained quality mode we dont want + // q to fall below the cq level. + if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (cpi->active_best_quality < cpi->cq_target_quality) ) + { + // If we are strongly undershooting the target rate in the last + // frames then use the user passed in cq value not the auto + // cq value. + if ( cpi->rolling_actual_bits < cpi->min_frame_bandwidth ) + cpi->active_best_quality = cpi->oxcf.cq_level; + else + cpi->active_best_quality = cpi->cq_target_quality; } } @@ -3668,11 +3010,23 @@ static void encode_frame_to_data_rate if (cpi->active_best_quality < cpi->best_quality) cpi->active_best_quality = cpi->best_quality; - else if (cpi->active_best_quality > cpi->active_worst_quality) - cpi->active_best_quality = cpi->active_worst_quality; - // Determine initial Q to try - Q = vp8_regulate_q(cpi, cpi->this_frame_target); + if (cpi->active_best_quality > cpi->worst_quality) + cpi->active_best_quality = cpi->worst_quality; + + if ( cpi->active_worst_quality < cpi->active_best_quality ) + cpi->active_worst_quality = cpi->active_best_quality; + + // Specuial case code to try and match quality with forced key frames + if ( (cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced ) + { + Q = cpi->last_boosted_qindex; + } + else + { + // Determine initial Q to try + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + } last_zbin_oq = cpi->zbin_over_quant; // Set highest allowed value for Zbin over quant @@ -3683,10 +3037,6 @@ static void encode_frame_to_data_rate else zbin_oq_high = ZBIN_OQ_MAX; - // Setup background Q adjustment for error resilliant mode - if (cpi->cyclic_refresh_mode_enabled) - cyclic_background_refresh(cpi, Q, 0); - vp8_compute_frame_size_bounds(cpi, &frame_under_shoot_limit, &frame_over_shoot_limit); // Limit Q range for the adaptive loop. @@ -3699,9 +3049,15 @@ static void encode_frame_to_data_rate loop_count = 0; +#if CONFIG_HIGH_PRECISION_MV + /* Decide this based on various factors */ + if (cm->frame_type != KEY_FRAME) + { + xd->allow_high_precision_mv = (Q < HIGH_PRECISION_MV_QTHRESH); + } +#endif - scale_and_extend_source(cpi->un_scaled_source, cpi); -#if !(CONFIG_REALTIME_ONLY) && CONFIG_POSTPROC +#if CONFIG_POSTPROC if (cpi->oxcf.noise_sensitivity > 0) { @@ -3758,11 +3114,6 @@ static void encode_frame_to_data_rate { vp8_clear_system_state(); //__asm emms; - /* - if(cpi->is_src_frame_alt_ref) - Q = 127; - */ - vp8_set_quantizer(cpi, Q); this_q = Q; @@ -3810,7 +3161,8 @@ static void encode_frame_to_data_rate */ } - //as this is for cost estimate, let's make sure it does not go extreme eitehr way + // as this is for cost estimate, let's make sure it does not + // get extreme either way if (cpi->prob_skip_false < 5) cpi->prob_skip_false = 5; @@ -3822,25 +3174,13 @@ static void encode_frame_to_data_rate } - -#if 0 - - if (cpi->pass != 1) - { - FILE *f = fopen("skip.stt", "a"); - fprintf(f, "%d, %d, %4d ", cpi->common.refresh_golden_frame, cpi->common.refresh_alt_ref_frame, cpi->prob_skip_false); - fclose(f); - } - -#endif - } + // Set up entropy depending on frame type. if (cm->frame_type == KEY_FRAME) - { - resize_key_frame(cpi); vp8_setup_key_frame(cpi); - } + else + vp8_setup_inter_frame(cpi); // transform / motion compensation build reconstruction frame vp8_encode_frame(cpi); @@ -3850,96 +3190,11 @@ static void encode_frame_to_data_rate vp8_clear_system_state(); //__asm emms; -#if 0 - if (cpi->pass != 1) - { - FILE *f = fopen("q_used.stt", "a"); - fprintf(f, "%4d, %4d, %8d\n", cpi->common.current_video_frame, - cpi->common.base_qindex, cpi->projected_frame_size); - fclose(f); - } -#endif - - - // Test to see if the stats generated for this frame indicate that we should have coded a key frame - // (assuming that we didn't)! - if (cpi->pass != 2 && cpi->oxcf.auto_key && cm->frame_type != KEY_FRAME) - { - int key_frame_decision = decide_key_frame(cpi); - - if (cpi->compressor_speed == 2) - { - /* we don't do re-encoding in realtime mode - * if key frame is decided than we force it on next frame */ - cpi->force_next_frame_intra = key_frame_decision; - } - else if (key_frame_decision) - { - // Reset all our sizing numbers and recode - cm->frame_type = KEY_FRAME; - - vp8_pick_frame_size(cpi); - - // Clear the Alt reference frame active flag when we have a key frame - cpi->source_alt_ref_active = FALSE; - - // Reset the loop filter deltas and segmentation map - setup_features(cpi); - - // If segmentation is enabled force a map update for key frames - if (cpi->mb.e_mbd.segmentation_enabled) - { - cpi->mb.e_mbd.update_mb_segmentation_map = 1; - cpi->mb.e_mbd.update_mb_segmentation_data = 1; - } - - vp8_restore_coding_context(cpi); - - Q = vp8_regulate_q(cpi, cpi->this_frame_target); - - vp8_compute_frame_size_bounds(cpi, &frame_under_shoot_limit, &frame_over_shoot_limit); - - // Limit Q range for the adaptive loop. - bottom_index = cpi->active_best_quality; - top_index = cpi->active_worst_quality; - q_low = cpi->active_best_quality; - q_high = cpi->active_worst_quality; - - loop_count++; - Loop = TRUE; - - continue; - } - } - - vp8_clear_system_state(); - if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1; - // Are we are overshooting and up against the limit of active max Q. - if (((cpi->pass != 2) || (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) && - (Q == cpi->active_worst_quality) && - (cpi->active_worst_quality < cpi->worst_quality) && - (cpi->projected_frame_size > frame_over_shoot_limit)) - { - int over_size_percent = ((cpi->projected_frame_size - frame_over_shoot_limit) * 100) / frame_over_shoot_limit; + active_worst_qchanged = FALSE; - // If so is there any scope for relaxing it - while ((cpi->active_worst_quality < cpi->worst_quality) && (over_size_percent > 0)) - { - cpi->active_worst_quality++; - top_index = cpi->active_worst_quality; - over_size_percent = (int)(over_size_percent * 0.96); // Assume 1 qstep = about 4% on frame size. - } - - // If we have updated the active max Q do not call vp8_update_rate_correction_factors() this loop. - active_worst_qchanged = TRUE; - } - else - active_worst_qchanged = FALSE; - -#if !(CONFIG_REALTIME_ONLY) // Special case handling for forced key frames if ( (cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced ) { @@ -3948,23 +3203,35 @@ static void encode_frame_to_data_rate &cm->yv12_fb[cm->new_fb_idx], IF_RTCD(&cpi->rtcd.variance)); + int high_err_target = cpi->ambient_err; + int low_err_target = ((cpi->ambient_err * 3) >> 2); + + // Prevent possible divide by zero error below for perfect KF + kf_err += (!kf_err); + // The key frame is not good enough - if ( kf_err > ((cpi->ambient_err * 7) >> 3) ) + if ( (kf_err > high_err_target) && + (cpi->projected_frame_size <= frame_over_shoot_limit) ) { // Lower q_high q_high = (Q > q_low) ? (Q - 1) : q_low; // Adjust Q - Q = (q_high + q_low) >> 1; + Q = (Q * high_err_target) / kf_err; + if ( Q < ((q_high + q_low) >> 1)) + Q = (q_high + q_low) >> 1; } // The key frame is much better than the previous frame - else if ( kf_err < (cpi->ambient_err >> 1) ) + else if ( (kf_err < low_err_target) && + (cpi->projected_frame_size >= frame_under_shoot_limit) ) { // Raise q_low q_low = (Q < q_high) ? (Q + 1) : q_high; // Adjust Q - Q = (q_high + q_low + 1) >> 1; + Q = (Q * low_err_target) / kf_err; + if ( Q > ((q_high + q_low + 1) >> 1)) + Q = (q_high + q_low + 1) >> 1; } // Clamp Q to upper and lower limits: @@ -3990,14 +3257,12 @@ static void encode_frame_to_data_rate // Frame is too large if (cpi->projected_frame_size > cpi->this_frame_target) { - //if ( cpi->zbin_over_quant == 0 ) q_low = (Q < q_high) ? (Q + 1) : q_high; // Raise Qlow as to at least the current value if (cpi->zbin_over_quant > 0) // If we are using over quant do the same for zbin_oq_low zbin_oq_low = (cpi->zbin_over_quant < zbin_oq_high) ? (cpi->zbin_over_quant + 1) : zbin_oq_high; - //if ( undershoot_seen || (Q == MAXQ) ) - if (undershoot_seen) + if ( undershoot_seen || (loop_count > 1) ) { // Update rate_correction_factor unless cpi->active_worst_quality has changed. if (!active_worst_qchanged) @@ -4040,7 +3305,7 @@ static void encode_frame_to_data_rate else // else lower zbin_oq_high zbin_oq_high = (cpi->zbin_over_quant > zbin_oq_low) ? (cpi->zbin_over_quant - 1) : zbin_oq_low; - if (overshoot_seen) + if ( overshoot_seen || (loop_count > 1) ) { // Update rate_correction_factor unless cpi->active_worst_quality has changed. if (!active_worst_qchanged) @@ -4097,7 +3362,6 @@ static void encode_frame_to_data_rate last_zbin_oq = cpi->zbin_over_quant; } else -#endif Loop = FALSE; if (cpi->is_src_frame_alt_ref) @@ -4190,47 +3454,45 @@ static void encode_frame_to_data_rate // For inter frames the current default behavior is that when // cm->refresh_golden_frame is set we copy the old GF over to the ARF buffer // This is purely an encoder decision at present. - if (!cpi->oxcf.error_resilient_mode && cm->refresh_golden_frame) + if (cm->refresh_golden_frame) cm->copy_buffer_to_arf = 2; - else - cm->copy_buffer_to_arf = 0; cm->frame_to_show = &cm->yv12_fb[cm->new_fb_idx]; -#if CONFIG_MULTITHREAD - if (cpi->b_multi_threaded) - { - sem_post(&cpi->h_event_start_lpf); /* start loopfilter in separate thread */ - } +#if WRITE_RECON_BUFFER + if(cm->show_frame) + write_cx_frame_to_file(cm->frame_to_show, + cm->current_video_frame); else + write_cx_frame_to_file(cm->frame_to_show, + cm->current_video_frame+1000); #endif + { loopfilter_frame(cpi, cm); } update_reference_frames(cm); - if (cpi->oxcf.error_resilient_mode) + // Work out the segment probabilites if segmentation is enabled and + // the map is due to be updated + if (xd->segmentation_enabled && xd->update_mb_segmentation_map) { - cm->refresh_entropy_probs = 0; + // Select the coding strategy for the segment map (temporal or spatial) + choose_segmap_coding_method( cpi ); + + // Take a copy of the segment map if it changed for future comparison + vpx_memcpy( cm->last_frame_seg_map, + cpi->segmentation_map, cm->MBs ); } -#if CONFIG_MULTITHREAD - /* wait that filter_level is picked so that we can continue with stream packing */ - if (cpi->b_multi_threaded) - sem_wait(&cpi->h_event_end_lpf); -#endif + // Update the common prediction model probabilities to reflect + // the what was seen in the current frame. + update_refpred_stats( cpi ); // build the bitstream vp8_pack_bitstream(cpi, dest, size); -#if CONFIG_MULTITHREAD - /* wait for loopfilter thread done */ - if (cpi->b_multi_threaded) - { - sem_wait(&cpi->h_event_end_lpf); - } -#endif /* Move storing frame_type out of the above loop since it is also * needed in motion search besides loopfilter */ @@ -4245,6 +3507,20 @@ static void encode_frame_to_data_rate cpi->last_q[cm->frame_type] = cm->base_qindex; + // Keep record of last boosted (KF/KF/ARF) Q value. + // If the current frame is coded at a lower Q then we also update it. + // If all mbs in this group are skipped only update if the Q value is + // better than that already stored. + // This is used to help set quality in forced key frames to reduce popping + if ( (cm->base_qindex < cpi->last_boosted_qindex) || + ( (cpi->static_mb_pct < 100) && + ( (cm->frame_type == KEY_FRAME) || + cm->refresh_alt_ref_frame || + (cm->refresh_golden_frame && !cpi->is_src_frame_alt_ref) ) ) ) + { + cpi->last_boosted_qindex = cm->base_qindex; + } + if (cm->frame_type == KEY_FRAME) { vp8_adjust_key_frame_context(cpi); @@ -4258,63 +3534,13 @@ static void encode_frame_to_data_rate if ((cm->frame_type != KEY_FRAME) && !cm->refresh_golden_frame && !cm->refresh_alt_ref_frame) { cpi->ni_frames++; + cpi->tot_q += vp8_convert_qindex_to_q(Q); + cpi->avg_q = cpi->tot_q / (double)cpi->ni_frames; // Calculate the average Q for normal inter frames (not key or GFU // frames). - if ( cpi->pass == 2 ) - { - cpi->ni_tot_qi += Q; - cpi->ni_av_qi = (cpi->ni_tot_qi / cpi->ni_frames); - } - else - { - // Damp value for first few frames - if (cpi->ni_frames > 150 ) - { - cpi->ni_tot_qi += Q; - cpi->ni_av_qi = (cpi->ni_tot_qi / cpi->ni_frames); - } - // For one pass, early in the clip ... average the current frame Q - // value with the worstq entered by the user as a dampening measure - else - { - cpi->ni_tot_qi += Q; - cpi->ni_av_qi = ((cpi->ni_tot_qi / cpi->ni_frames) + cpi->worst_quality + 1) / 2; - } - - // If the average Q is higher than what was used in the last frame - // (after going through the recode loop to keep the frame size within range) - // then use the last frame value - 1. - // The -1 is designed to stop Q and hence the data rate, from progressively - // falling away during difficult sections, but at the same time reduce the number of - // itterations around the recode loop. - if (Q > cpi->ni_av_qi) - cpi->ni_av_qi = Q - 1; - } - } - -#if 0 - - // If the frame was massively oversize and we are below optimal buffer level drop next frame - if ((cpi->drop_frames_allowed) && - (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && - (cpi->buffer_level < cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100) && - (cpi->projected_frame_size > (4 * cpi->this_frame_target))) - { - cpi->drop_frame = TRUE; - } - -#endif - - // Set the count for maximum consequative dropped frames based upon the ratio of - // this frame size to the target average per frame bandwidth. - // (cpi->av_per_frame_bandwidth > 0) is just a sanity check to prevent / 0. - if (cpi->drop_frames_allowed && (cpi->av_per_frame_bandwidth > 0)) - { - cpi->max_drop_count = cpi->projected_frame_size / cpi->av_per_frame_bandwidth; - - if (cpi->max_drop_count > cpi->max_consec_dropped_frames) - cpi->max_drop_count = cpi->max_consec_dropped_frames; + cpi->ni_tot_qi += Q; + cpi->ni_av_qi = (cpi->ni_tot_qi / cpi->ni_frames); } // Update the buffer level variable. @@ -4324,7 +3550,7 @@ static void encode_frame_to_data_rate else cpi->bits_off_target += cpi->av_per_frame_bandwidth - cpi->projected_frame_size; - // Clip the buffer level to the maximum specified buffer size + // Clip the buffer level at the maximum buffer size if (cpi->bits_off_target > cpi->oxcf.maximum_buffer_size) cpi->bits_off_target = cpi->oxcf.maximum_buffer_size; @@ -4387,45 +3613,64 @@ static void encode_frame_to_data_rate vp8_clear_system_state(); //__asm emms; - if (cpi->twopass.total_coded_error_left != 0.0) - fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d %6d %6d" - "%6d %6d %6d %5d %5d %5d %8d %8.2f %10d %10.3f" + if (cpi->twopass.total_left_stats->coded_error != 0.0) + fprintf(f, "%10d %10d %10d %10d %10d %10d %10d" + "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f" + "%6d %5d %5d %5d %8d %8.2f %10d %10.3f" "%10.3f %8d\n", cpi->common.current_video_frame, cpi->this_frame_target, cpi->projected_frame_size, (cpi->projected_frame_size - cpi->this_frame_target), (int)cpi->total_target_vs_actual, (cpi->oxcf.starting_buffer_level-cpi->bits_off_target), - (int)cpi->total_actual_bits, cm->base_qindex, - cpi->active_best_quality, cpi->active_worst_quality, - cpi->ni_av_qi, cpi->cq_target_quality, cpi->zbin_over_quant, + (int)cpi->total_actual_bits, + vp8_convert_qindex_to_q(cm->base_qindex), + (double)vp8_dc_quant(cm->base_qindex,0)/4.0, + vp8_convert_qindex_to_q(cpi->active_best_quality), + vp8_convert_qindex_to_q(cpi->active_worst_quality), + cpi->avg_q, + vp8_convert_qindex_to_q(cpi->ni_av_qi), + vp8_convert_qindex_to_q(cpi->cq_target_quality), + cpi->zbin_over_quant, //cpi->avg_frame_qindex, cpi->zbin_over_quant, cm->refresh_golden_frame, cm->refresh_alt_ref_frame, cm->frame_type, cpi->gfu_boost, - cpi->twopass.est_max_qcorrection_factor, (int)cpi->twopass.bits_left, - cpi->twopass.total_coded_error_left, - (double)cpi->twopass.bits_left / cpi->twopass.total_coded_error_left, + cpi->twopass.est_max_qcorrection_factor, + (int)cpi->twopass.bits_left, + cpi->twopass.total_left_stats->coded_error, + (double)cpi->twopass.bits_left / + cpi->twopass.total_left_stats->coded_error, cpi->tot_recode_hits); else - fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d %6d %6d" - "%6d %6d %6d %5d %5d %5d %8d %8.2f %10d %10.3f" + fprintf(f, "%10d %10d %10d %10d %10d %10d %10d" + "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f" + "%6d %5d %5d %5d %8d %8.2f %10d %10.3f" "%8d\n", cpi->common.current_video_frame, cpi->this_frame_target, cpi->projected_frame_size, (cpi->projected_frame_size - cpi->this_frame_target), (int)cpi->total_target_vs_actual, (cpi->oxcf.starting_buffer_level-cpi->bits_off_target), - (int)cpi->total_actual_bits, cm->base_qindex, - cpi->active_best_quality, cpi->active_worst_quality, - cpi->ni_av_qi, cpi->cq_target_quality, cpi->zbin_over_quant, + (int)cpi->total_actual_bits, + vp8_convert_qindex_to_q(cm->base_qindex), + (double)vp8_dc_quant(cm->base_qindex,0)/4.0, + vp8_convert_qindex_to_q(cpi->active_best_quality), + vp8_convert_qindex_to_q(cpi->active_worst_quality), + cpi->avg_q, + vp8_convert_qindex_to_q(cpi->ni_av_qi), + vp8_convert_qindex_to_q(cpi->cq_target_quality), + cpi->zbin_over_quant, //cpi->avg_frame_qindex, cpi->zbin_over_quant, cm->refresh_golden_frame, cm->refresh_alt_ref_frame, cm->frame_type, cpi->gfu_boost, - cpi->twopass.est_max_qcorrection_factor, (int)cpi->twopass.bits_left, - cpi->twopass.total_coded_error_left, cpi->tot_recode_hits); + cpi->twopass.est_max_qcorrection_factor, + (int)cpi->twopass.bits_left, + cpi->twopass.total_left_stats->coded_error, + cpi->tot_recode_hits); fclose(f); + if ( 0 ) { FILE *fmodes = fopen("Modes.stt", "a"); int i; @@ -4446,6 +3691,11 @@ static void encode_frame_to_data_rate #endif +#if 0 + // Debug stats for segment feature experiments. + print_seg_map(cpi); +#endif + // If this was a kf or Gf note the Q if ((cm->frame_type == KEY_FRAME) || cm->refresh_golden_frame || cm->refresh_alt_ref_frame) cm->last_kf_gf_q = cm->base_qindex; @@ -4487,16 +3737,12 @@ static void encode_frame_to_data_rate if (cpi->gold_is_alt) cpi->ref_frame_flags &= ~VP8_ALT_FLAG; - - if (!cpi->oxcf.error_resilient_mode) - { - if (cpi->oxcf.play_alternate && cm->refresh_alt_ref_frame && (cm->frame_type != KEY_FRAME)) - // Update the alternate reference frame stats as appropriate. - update_alt_ref_frame_stats(cpi); - else - // Update the Golden frame stats as appropriate. - update_golden_frame_stats(cpi); - } + if (cpi->oxcf.play_alternate && cm->refresh_alt_ref_frame && (cm->frame_type != KEY_FRAME)) + // Update the alternate reference frame stats as appropriate. + update_alt_ref_frame_stats(cpi); + else + // Update the Golden frame stats as appropriate. + update_golden_frame_stats(cpi); if (cm->frame_type == KEY_FRAME) { @@ -4516,9 +3762,9 @@ static void encode_frame_to_data_rate } // Clear the one shot update flags for segmentation map and mode/ref loop filter deltas. - cpi->mb.e_mbd.update_mb_segmentation_map = 0; - cpi->mb.e_mbd.update_mb_segmentation_data = 0; - cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; + xd->update_mb_segmentation_map = 0; + xd->update_mb_segmentation_data = 0; + xd->mode_ref_lf_delta_update = 0; // Dont increment frame counters if this was an altref buffer update not a real frame @@ -4543,16 +3789,20 @@ static void encode_frame_to_data_rate fclose(recon_file); } #endif -#if 0 - // DEBUG - if(cm->current_video_frame>173 && cm->current_video_frame<178) - { - char filename[512]; - sprintf(filename, "enc%04d.yuv", (int) cm->current_video_frame); - vp8_write_yuv_frame(filename, cm->frame_to_show); - } +#ifdef OUTPUT_YUV_REC + vp8_write_yuv_rec_frame(cm); #endif + if(cm->show_frame) + { + vpx_memcpy(cm->prev_mip, cm->mip, + (cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO)); + } + else + { + vpx_memset(cm->prev_mip, 0, + (cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO)); + } } @@ -4610,7 +3860,6 @@ static void check_gf_quality(VP8_COMP *cpi) #endif } -#if !(CONFIG_REALTIME_ONLY) static void Pass2Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, unsigned int *frame_flags) { @@ -4622,12 +3871,16 @@ static void Pass2Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, if (!cpi->common.refresh_alt_ref_frame) { + double lower_bounds_min_rate = FRAME_OVERHEAD_BITS*cpi->oxcf.frame_rate; double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth *cpi->oxcf.two_pass_vbrmin_section / 100); + + if (two_pass_min_rate < lower_bounds_min_rate) + two_pass_min_rate = lower_bounds_min_rate; + cpi->twopass.bits_left += (int64_t)(two_pass_min_rate / cpi->oxcf.frame_rate); } } -#endif //For ARM NEON, d8-d15 are callee-saved registers, and need to be saved by us. #if HAVE_ARMV7 @@ -4718,10 +3971,11 @@ int vp8_get_compressed_data(VP8_PTR ptr, unsigned int *frame_flags, unsigned lon cpi->source = NULL; -#if !(CONFIG_REALTIME_ONLY) +#if CONFIG_HIGH_PRECISION_MV + cpi->mb.e_mbd.allow_high_precision_mv = ALTREF_HIGH_PRECISION_MV; +#endif // Should we code an alternate reference frame - if (cpi->oxcf.error_resilient_mode == 0 && - cpi->oxcf.play_alternate && + if (cpi->oxcf.play_alternate && cpi->source_alt_ref_pending) { if ((cpi->source = vp8_lookahead_peek(cpi->lookahead, @@ -4743,7 +3997,6 @@ int vp8_get_compressed_data(VP8_PTR ptr, unsigned int *frame_flags, unsigned lon cpi->is_src_frame_alt_ref = 0; } } -#endif if (!cpi->source) { @@ -4770,16 +4023,12 @@ int vp8_get_compressed_data(VP8_PTR ptr, unsigned int *frame_flags, unsigned lon else { *size = 0; -#if !(CONFIG_REALTIME_ONLY) - if (flush && cpi->pass == 1 && !cpi->twopass.first_pass_done) { vp8_end_first_pass(cpi); /* get last stats packet */ cpi->twopass.first_pass_done = 1; } -#endif - #if HAVE_ARMV7 #if CONFIG_RUNTIME_CPU_DETECT if (cm->rtcd.flags & HAS_NEON) @@ -4848,13 +4097,6 @@ int vp8_get_compressed_data(VP8_PTR ptr, unsigned int *frame_flags, unsigned lon cpi->last_end_time_stamp_seen = cpi->source->ts_end; } - if (cpi->compressor_speed == 2) - { - check_gf_quality(cpi); - vpx_usec_timer_start(&tsctimer); - vpx_usec_timer_start(&ticktimer); - } - // start with a 0 size frame *size = 0; @@ -4893,8 +4135,6 @@ int vp8_get_compressed_data(VP8_PTR ptr, unsigned int *frame_flags, unsigned lon assert(i < NUM_YV12_BUFFERS ); } -#if !(CONFIG_REALTIME_ONLY) - if (cpi->pass == 1) { Pass1Encode(cpi, size, dest, frame_flags); @@ -4904,43 +4144,14 @@ int vp8_get_compressed_data(VP8_PTR ptr, unsigned int *frame_flags, unsigned lon Pass2Encode(cpi, size, dest, frame_flags); } else -#endif encode_frame_to_data_rate(cpi, size, dest, frame_flags); - if (cpi->compressor_speed == 2) + if(cm->refresh_entropy_probs) { - unsigned int duration, duration2; - vpx_usec_timer_mark(&tsctimer); - vpx_usec_timer_mark(&ticktimer); - - duration = vpx_usec_timer_elapsed(&ticktimer); - duration2 = (unsigned int)((double)duration / 2); - - if (cm->frame_type != KEY_FRAME) - { - if (cpi->avg_encode_time == 0) - cpi->avg_encode_time = duration; - else - cpi->avg_encode_time = (7 * cpi->avg_encode_time + duration) >> 3; - } - - if (duration2) - { - //if(*frame_flags!=1) - { - - if (cpi->avg_pick_mode_time == 0) - cpi->avg_pick_mode_time = duration2; - else - cpi->avg_pick_mode_time = (7 * cpi->avg_pick_mode_time + duration2) >> 3; - } - } - - } - - if (cm->refresh_entropy_probs == 0) - { - vpx_memcpy(&cm->fc, &cm->lfc, sizeof(cm->fc)); + if(cm->refresh_alt_ref_frame) + vpx_memcpy(&cm->lfc_a, &cm->fc, sizeof(cm->fc)); + else + vpx_memcpy(&cm->lfc, &cm->fc, sizeof(cm->fc)); } // if its a dropped frame honor the requests on subsequent frames @@ -5070,29 +4281,6 @@ int vp8_get_compressed_data(VP8_PTR ptr, unsigned int *frame_flags, unsigned lon } } -#if 0 - - if (cpi->common.frame_type != 0 && cpi->common.base_qindex == cpi->oxcf.worst_allowed_q) - { - skiptruecount += cpi->skip_true_count; - skipfalsecount += cpi->skip_false_count; - } - -#endif -#if 0 - - if (cpi->pass != 1) - { - FILE *f = fopen("skip.stt", "a"); - fprintf(f, "frame:%4d flags:%4x Q:%4d P:%4d Size:%5d\n", cpi->common.current_video_frame, *frame_flags, cpi->common.base_qindex, cpi->prob_skip_false, *size); - - if (cpi->is_src_frame_alt_ref == 1) - fprintf(f, "skipcount: %4d framesize: %d\n", cpi->skip_true_count , *size); - - fclose(f); - } - -#endif #endif #if HAVE_ARMV7 @@ -5142,43 +4330,59 @@ int vp8_get_preview_raw_frame(VP8_PTR comp, YV12_BUFFER_CONFIG *dest, vp8_ppflag int vp8_set_roimap(VP8_PTR comp, unsigned char *map, unsigned int rows, unsigned int cols, int delta_q[4], int delta_lf[4], unsigned int threshold[4]) { VP8_COMP *cpi = (VP8_COMP *) comp; - signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; + signed char feature_data[SEG_LVL_MAX][MAX_MB_SEGMENTS]; + MACROBLOCKD *xd = &cpi->mb.e_mbd; + int i; if (cpi->common.mb_rows != rows || cpi->common.mb_cols != cols) return -1; if (!map) { - disable_segmentation((VP8_PTR)cpi); + vp8_disable_segmentation((VP8_PTR)cpi); return 0; } // Set the segmentation Map - set_segmentation_map((VP8_PTR)cpi, map); + vp8_set_segmentation_map((VP8_PTR)cpi, map); // Activate segmentation. - enable_segmentation((VP8_PTR)cpi); + vp8_enable_segmentation((VP8_PTR)cpi); // Set up the quant segment data - feature_data[MB_LVL_ALT_Q][0] = delta_q[0]; - feature_data[MB_LVL_ALT_Q][1] = delta_q[1]; - feature_data[MB_LVL_ALT_Q][2] = delta_q[2]; - feature_data[MB_LVL_ALT_Q][3] = delta_q[3]; + feature_data[SEG_LVL_ALT_Q][0] = delta_q[0]; + feature_data[SEG_LVL_ALT_Q][1] = delta_q[1]; + feature_data[SEG_LVL_ALT_Q][2] = delta_q[2]; + feature_data[SEG_LVL_ALT_Q][3] = delta_q[3]; // Set up the loop segment data s - feature_data[MB_LVL_ALT_LF][0] = delta_lf[0]; - feature_data[MB_LVL_ALT_LF][1] = delta_lf[1]; - feature_data[MB_LVL_ALT_LF][2] = delta_lf[2]; - feature_data[MB_LVL_ALT_LF][3] = delta_lf[3]; + feature_data[SEG_LVL_ALT_LF][0] = delta_lf[0]; + feature_data[SEG_LVL_ALT_LF][1] = delta_lf[1]; + feature_data[SEG_LVL_ALT_LF][2] = delta_lf[2]; + feature_data[SEG_LVL_ALT_LF][3] = delta_lf[3]; cpi->segment_encode_breakout[0] = threshold[0]; cpi->segment_encode_breakout[1] = threshold[1]; cpi->segment_encode_breakout[2] = threshold[2]; cpi->segment_encode_breakout[3] = threshold[3]; + // Enable the loop and quant changes in the feature mask + for ( i = 0; i < 4; i++ ) + { + if (delta_q[i]) + enable_segfeature(xd, i, SEG_LVL_ALT_Q); + else + disable_segfeature(xd, i, SEG_LVL_ALT_Q); + + if (delta_lf[i]) + enable_segfeature(xd, i, SEG_LVL_ALT_LF); + else + disable_segfeature(xd, i, SEG_LVL_ALT_LF); + } + // Initialise the feature data structure // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 - set_segment_data((VP8_PTR)cpi, &feature_data[0][0], SEGMENT_DELTADATA); + vp8_set_segment_data((VP8_PTR)cpi, &feature_data[0][0], SEGMENT_DELTADATA); return 0; } diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index 968ebf833..9c655b845 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -13,7 +13,7 @@ #define __INC_VP8_INT_H #include -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vp8/common/onyx.h" #include "treewriter.h" #include "tokenize.h" @@ -23,7 +23,6 @@ #include "encodemb.h" #include "quantize.h" #include "vp8/common/entropy.h" -#include "vp8/common/threading.h" #include "vpx_ports/mem.h" #include "vpx/internal/vpx_codec_internal.h" #include "mcomp.h" @@ -37,12 +36,12 @@ #define KEY_FRAME_CONTEXT 5 -#define MAX_LAG_BUFFERS (CONFIG_REALTIME_ONLY? 1 : 25) +#define MAX_LAG_BUFFERS 25 #define AF_THRESH 25 #define AF_THRESH2 100 #define ARF_DECAY_THRESH 12 -#define MAX_MODES 20 +#define MAX_MODES 33 #define MIN_THRESHMULT 32 #define MAX_THRESHMULT 512 @@ -52,9 +51,7 @@ #define MV_ZBIN_BOOST 4 #define ZBIN_OQ_MAX 192 -#if !(CONFIG_REALTIME_ONLY) #define VP8_TEMPORAL_ALT_REF 1 -#endif typedef struct { @@ -67,21 +64,39 @@ typedef struct MV_CONTEXT mvc[2]; int mvcosts[2][MVvals+1]; +#if CONFIG_HIGH_PRECISION_MV + MV_CONTEXT_HP mvc_hp[2]; + int mvcosts_hp[2][MVvals_hp+1]; +#endif #ifdef MODE_STATS // Stats - int y_modes[5]; - int uv_modes[4]; - int b_modes[10]; - int inter_y_modes[10]; - int inter_uv_modes[4]; - int inter_b_modes[10]; + int y_modes[VP8_YMODES]; + int uv_modes[VP8_UV_MODES]; + int i8x8_modes[VP8_I8X8_MODES]; + int b_modes[B_MODE_COUNT]; + int inter_y_modes[MB_MODE_COUNT]; + int inter_uv_modes[VP8_UV_MODES]; + int inter_b_modes[B_MODE_COUNT]; +#endif + /* interframe intra mode probs */ + vp8_prob ymode_prob[VP8_YMODES-1]; + /* keyframe intra mode probs */ +#if CONFIG_QIMODE + vp8_prob kf_ymode_prob[8][VP8_YMODES-1]; +#else + vp8_prob kf_ymode_prob[VP8_YMODES-1]; #endif - vp8_prob ymode_prob[4], uv_mode_prob[3]; /* interframe intra mode probs */ - vp8_prob kf_ymode_prob[4], kf_uv_mode_prob[3]; /* keyframe "" */ - - int ymode_count[5], uv_mode_count[4]; /* intra MB type cts this frame */ +#if CONFIG_UVINTRA + vp8_prob kf_uv_mode_prob[VP8_YMODES][VP8_UV_MODES-1]; + vp8_prob uv_mode_prob[VP8_YMODES][VP8_UV_MODES-1]; +#else + vp8_prob kf_uv_mode_prob[VP8_UV_MODES-1]; + vp8_prob uv_mode_prob[VP8_UV_MODES-1]; +#endif + /* intra MB type cts this frame */ + int ymode_count[VP8_YMODES], uv_mode_count[VP8_UV_MODES]; int count_mb_ref_frame_usage[MAX_REF_FRAMES]; @@ -108,6 +123,7 @@ typedef struct double MVrv; double MVcv; double mv_in_out_count; + double new_mv_count; double duration; double count; } @@ -127,6 +143,21 @@ typedef struct } ONEPASS_FRAMESTATS; +typedef struct +{ + struct { + int err; + union { + int_mv mv; + MB_PREDICTION_MODE mode; + } m; + } ref[MAX_REF_FRAMES]; +} MBGRAPH_MB_STATS; + +typedef struct +{ + MBGRAPH_MB_STATS *mb_stats; +} MBGRAPH_FRAME_STATS; typedef enum { @@ -158,6 +189,23 @@ typedef enum THR_SPLITA = 18, THR_B_PRED = 19, + THR_I8X8_PRED = 20, + + THR_COMP_ZEROLG = 21, + THR_COMP_NEARESTLG = 22, + THR_COMP_NEARLG = 23, + + THR_COMP_ZEROLA = 24, + THR_COMP_NEARESTLA = 25, + THR_COMP_NEARLA = 26, + + THR_COMP_ZEROGA = 27, + THR_COMP_NEARESTGA = 28, + THR_COMP_NEARGA = 29, + + THR_COMP_NEWLG = 30, + THR_COMP_NEWLA = 31, + THR_COMP_NEWGA = 32, } THR_MODES; @@ -193,7 +241,6 @@ typedef struct typedef struct { MACROBLOCK mb; - int segment_counts[MAX_MB_SEGMENTS]; int totalrate; } MB_ROW_COMP; @@ -310,6 +357,10 @@ typedef struct VP8_COMP int rd_thresh_mult[MAX_MODES]; int rd_baseline_thresh[MAX_MODES]; int rd_threshes[MAX_MODES]; + int64_t rd_single_diff, rd_comp_diff, rd_hybrid_diff; + int rd_prediction_type_threshes[4][NB_PREDICTION_TYPES]; + int comp_pred_count[COMP_PRED_CONTEXTS]; + int single_pred_count[COMP_PRED_CONTEXTS]; int RDMULT; int RDDIV ; @@ -325,6 +376,7 @@ typedef struct VP8_COMP int this_frame_target; int projected_frame_size; int last_q[2]; // Separate values for Intra/Inter + int last_boosted_qindex; // Last boosted GF/KF/ARF q double rate_correction_factor; double key_frame_rate_correction_factor; @@ -358,6 +410,8 @@ typedef struct VP8_COMP int ni_tot_qi; int ni_frames; int avg_frame_qindex; + double tot_q; + double avg_q; int zbin_over_quant; int zbin_mode_boost; @@ -386,23 +440,22 @@ typedef struct VP8_COMP int cq_target_quality; - int drop_frames_allowed; // Are we permitted to drop frames? - int drop_frame; // Drop this frame? - int drop_count; // How many frames have we dropped? - int max_drop_count; // How many frames should we drop? - int max_consec_dropped_frames; // Limit number of consecutive frames that can be dropped. - - int ymode_count [VP8_YMODES]; /* intra MB type cts this frame */ int uv_mode_count[VP8_UV_MODES]; /* intra MB type cts this frame */ unsigned int MVcount [2] [MVvals]; /* (row,col) MV cts this frame */ +#if CONFIG_HIGH_PRECISION_MV + unsigned int MVcount_hp [2] [MVvals_hp]; /* (row,col) MV cts this frame */ +#endif unsigned int coef_counts [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; /* for this frame */ //DECLARE_ALIGNED(16, int, coef_counts_backup [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]); //not used any more //save vp8_tree_probs_from_distribution result for each frame to avoid repeat calculation vp8_prob frame_coef_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES]; unsigned int frame_branch_ct [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES][2]; + unsigned int coef_counts_8x8 [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; /* for this frame */ + vp8_prob frame_coef_probs_8x8 [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES]; + unsigned int frame_branch_ct_8x8 [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES][2]; int gfu_boost; int kf_boost; @@ -416,6 +469,9 @@ typedef struct VP8_COMP ONEPASS_FRAMESTATS one_pass_frame_stats[MAX_LAG_BUFFERS]; int one_pass_frame_index; #endif + MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS]; + int mbgraph_n_frames; // number of frames filled in the above + int static_mb_pct; // % forced skip mbs by segmentation int decimation_factor; int decimation_count; @@ -428,8 +484,6 @@ typedef struct VP8_COMP int compressor_speed; int interquantizer; - int auto_gold; - int auto_adjust_gold_quantizer; int goldfreq; int auto_worst_q; int cpu_used; @@ -437,21 +491,18 @@ typedef struct VP8_COMP int vert_scale; int pass; - - int prob_intra_coded; - int prob_last_coded; - int prob_gf_coded; int prob_skip_false; int last_skip_false_probs[3]; int last_skip_probs_q[3]; - int recent_ref_frame_usage[MAX_REF_FRAMES]; + int recent_ref_frame_usage[MAX_REF_FRAMES]; int count_mb_ref_frame_usage[MAX_REF_FRAMES]; int this_frame_percent_intra; int last_frame_percent_intra; - int ref_frame_flags; + unsigned char ref_pred_probs_update[PREDICTION_PROBS]; + SPEED_FEATURES sf; int error_bins[1024]; @@ -461,46 +512,22 @@ typedef struct VP8_COMP int gf_update_recommended; int skip_true_count; int skip_false_count; + int t4x4_count; + int t8x8_count; + +#if CONFIG_UVINTRA + int y_uv_mode_count[VP8_YMODES][VP8_UV_MODES]; +#endif unsigned char *segmentation_map; - signed char segment_feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; // Segment data (can be deltas or absolute values) - int segment_encode_breakout[MAX_MB_SEGMENTS]; // segment threashold for encode breakout + + // segment threashold for encode breakout + int segment_encode_breakout[MAX_MB_SEGMENTS]; unsigned char *active_map; unsigned int active_map_enabled; - // Video conferencing cyclic refresh mode flags etc - // This is a mode designed to clean up the background over time in live encoding scenarious. It uses segmentation - int cyclic_refresh_mode_enabled; - int cyclic_refresh_mode_max_mbs_perframe; - int cyclic_refresh_mode_index; - int cyclic_refresh_q; - signed char *cyclic_refresh_map; - -#if CONFIG_MULTITHREAD - // multithread data - int * mt_current_mb_col; - int mt_sync_range; - int b_multi_threaded; - int encoding_thread_count; - - pthread_t *h_encoding_thread; - pthread_t h_filter_thread; - - MB_ROW_COMP *mb_row_ei; - ENCODETHREAD_DATA *en_thread_data; - LPFTHREAD_DATA lpf_thread_data; - - //events - sem_t *h_event_start_encoding; - sem_t h_event_end_encoding; - sem_t h_event_start_lpf; - sem_t h_event_end_lpf; -#endif TOKENLIST *tplist; - unsigned int partition_sz[MAX_PARTITIONS]; - // end of multithread data - fractional_mv_step_fp *find_fractional_mv_step; vp8_full_search_fn_t full_search_sad; @@ -512,7 +539,7 @@ typedef struct VP8_COMP unsigned int time_pick_lpf; unsigned int time_encode_mb_row; - int base_skip_false_prob[128]; + int base_skip_false_prob[QINDEX_RANGE]; struct twopass_rc { @@ -523,6 +550,7 @@ typedef struct VP8_COMP FIRSTPASS_STATS *total_stats; FIRSTPASS_STATS *this_frame_stats; FIRSTPASS_STATS *stats_in, *stats_in_end, *stats_in_start; + FIRSTPASS_STATS *total_left_stats; int first_pass_done; int64_t bits_left; int64_t clip_bits_total; @@ -530,10 +558,6 @@ typedef struct VP8_COMP double modified_error_total; double modified_error_used; double modified_error_left; - double total_error_left; - double total_intra_error_left; - double total_coded_error_left; - double start_tot_err_left; double kf_intra_err_min; double gf_intra_err_min; int frames_to_key; diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c deleted file mode 100644 index 34e08cad8..000000000 --- a/vp8/encoder/pickinter.c +++ /dev/null @@ -1,937 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -#include -#include "vpx_config.h" -#include "onyx_int.h" -#include "modecosts.h" -#include "encodeintra.h" -#include "vp8/common/entropymode.h" -#include "pickinter.h" -#include "vp8/common/findnearmv.h" -#include "encodemb.h" -#include "vp8/common/reconinter.h" -#include "vp8/common/reconintra.h" -#include "vp8/common/reconintra4x4.h" -#include "vp8/common/g_common.h" -#include "variance.h" -#include "mcomp.h" -#include "rdopt.h" -#include "vpx_mem/vpx_mem.h" - -#if CONFIG_RUNTIME_CPU_DETECT -#define IF_RTCD(x) (x) -#else -#define IF_RTCD(x) NULL -#endif - -extern int VP8_UVSSE(MACROBLOCK *x, const vp8_variance_rtcd_vtable_t *rtcd); - -#ifdef SPEEDSTATS -extern unsigned int cnt_pm; -#endif - -extern const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES]; -extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; - -extern unsigned int (*vp8_get4x4sse_cs)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); -extern int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]); - - -int vp8_skip_fractional_mv_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d, - int_mv *bestmv, int_mv *ref_mv, - int error_per_bit, - const vp8_variance_fn_ptr_t *vfp, - int *mvcost[2], int *distortion, - unsigned int *sse) -{ - (void) b; - (void) d; - (void) ref_mv; - (void) error_per_bit; - (void) vfp; - (void) mvcost; - (void) distortion; - (void) sse; - bestmv->as_mv.row <<= 3; - bestmv->as_mv.col <<= 3; - return 0; -} - - -static int get_inter_mbpred_error(MACROBLOCK *mb, - const vp8_variance_fn_ptr_t *vfp, - unsigned int *sse, - int_mv this_mv) -{ - - BLOCK *b = &mb->block[0]; - BLOCKD *d = &mb->e_mbd.block[0]; - unsigned char *what = (*(b->base_src) + b->src); - int what_stride = b->src_stride; - unsigned char *in_what = *(d->base_pre) + d->pre ; - int in_what_stride = d->pre_stride; - int xoffset = this_mv.as_mv.col & 7; - int yoffset = this_mv.as_mv.row & 7; - - in_what += (this_mv.as_mv.row >> 3) * d->pre_stride + (this_mv.as_mv.col >> 3); - - if (xoffset | yoffset) - { - return vfp->svf(in_what, in_what_stride, xoffset, yoffset, what, what_stride, sse); - } - else - { - return vfp->vf(what, what_stride, in_what, in_what_stride, sse); - } - -} - - -unsigned int vp8_get4x4sse_cs_c -( - const unsigned char *src_ptr, - int source_stride, - const unsigned char *ref_ptr, - int recon_stride -) -{ - int distortion = 0; - int r, c; - - for (r = 0; r < 4; r++) - { - for (c = 0; c < 4; c++) - { - int diff = src_ptr[c] - ref_ptr[c]; - distortion += diff * diff; - } - - src_ptr += source_stride; - ref_ptr += recon_stride; - } - - return distortion; -} - -static int get_prediction_error(BLOCK *be, BLOCKD *b, const vp8_variance_rtcd_vtable_t *rtcd) -{ - unsigned char *sptr; - unsigned char *dptr; - sptr = (*(be->base_src) + be->src); - dptr = b->predictor; - - return VARIANCE_INVOKE(rtcd, get4x4sse_cs)(sptr, be->src_stride, dptr, 16); - -} - -static int pick_intra4x4block( - const VP8_ENCODER_RTCD *rtcd, - MACROBLOCK *x, - int ib, - B_PREDICTION_MODE *best_mode, - unsigned int *mode_costs, - - int *bestrate, - int *bestdistortion) -{ - - BLOCKD *b = &x->e_mbd.block[ib]; - BLOCK *be = &x->block[ib]; - B_PREDICTION_MODE mode; - int best_rd = INT_MAX; // 1<<30 - int rate; - int distortion; - - for (mode = B_DC_PRED; mode <= B_HE_PRED /*B_HU_PRED*/; mode++) - { - int this_rd; - - rate = mode_costs[mode]; - RECON_INVOKE(&rtcd->common->recon, intra4x4_predict) - (b, mode, b->predictor); - distortion = get_prediction_error(be, b, &rtcd->variance); - this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); - - if (this_rd < best_rd) - { - *bestrate = rate; - *bestdistortion = distortion; - best_rd = this_rd; - *best_mode = mode; - } - } - - b->bmi.as_mode = (B_PREDICTION_MODE)(*best_mode); - vp8_encode_intra4x4block(rtcd, x, ib); - return best_rd; -} - - -static int pick_intra4x4mby_modes -( - const VP8_ENCODER_RTCD *rtcd, - MACROBLOCK *mb, - int *Rate, - int *best_dist -) -{ - MACROBLOCKD *const xd = &mb->e_mbd; - int i; - int cost = mb->mbmode_cost [xd->frame_type] [B_PRED]; - int error; - int distortion = 0; - unsigned int *bmode_costs; - - vp8_intra_prediction_down_copy(xd); - - bmode_costs = mb->inter_bmode_costs; - - for (i = 0; i < 16; i++) - { - MODE_INFO *const mic = xd->mode_info_context; - const int mis = xd->mode_info_stride; - - B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); - int UNINITIALIZED_IS_SAFE(r), UNINITIALIZED_IS_SAFE(d); - - if (mb->e_mbd.frame_type == KEY_FRAME) - { - const B_PREDICTION_MODE A = above_block_mode(mic, i, mis); - const B_PREDICTION_MODE L = left_block_mode(mic, i); - - bmode_costs = mb->bmode_costs[A][L]; - } - - - pick_intra4x4block(rtcd, mb, i, &best_mode, bmode_costs, &r, &d); - - cost += r; - distortion += d; - mic->bmi[i].as_mode = best_mode; - - // Break out case where we have already exceeded best so far value - // that was passed in - if (distortion > *best_dist) - break; - } - - *Rate = cost; - - if (i == 16) - { - *best_dist = distortion; - error = RDCOST(mb->rdmult, mb->rddiv, cost, distortion); - } - else - { - *best_dist = INT_MAX; - error = INT_MAX; - } - - return error; -} - -static void pick_intra_mbuv_mode(MACROBLOCK *mb) -{ - - MACROBLOCKD *x = &mb->e_mbd; - unsigned char *uabove_row = x->dst.u_buffer - x->dst.uv_stride; - unsigned char *vabove_row = x->dst.v_buffer - x->dst.uv_stride; - unsigned char *usrc_ptr = (mb->block[16].src + *mb->block[16].base_src); - unsigned char *vsrc_ptr = (mb->block[20].src + *mb->block[20].base_src); - int uvsrc_stride = mb->block[16].src_stride; - unsigned char uleft_col[8]; - unsigned char vleft_col[8]; - unsigned char utop_left = uabove_row[-1]; - unsigned char vtop_left = vabove_row[-1]; - int i, j; - int expected_udc; - int expected_vdc; - int shift; - int Uaverage = 0; - int Vaverage = 0; - int diff; - int pred_error[4] = {0, 0, 0, 0}, best_error = INT_MAX; - MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); - - - for (i = 0; i < 8; i++) - { - uleft_col[i] = x->dst.u_buffer [i* x->dst.uv_stride -1]; - vleft_col[i] = x->dst.v_buffer [i* x->dst.uv_stride -1]; - } - - if (!x->up_available && !x->left_available) - { - expected_udc = 128; - expected_vdc = 128; - } - else - { - shift = 2; - - if (x->up_available) - { - - for (i = 0; i < 8; i++) - { - Uaverage += uabove_row[i]; - Vaverage += vabove_row[i]; - } - - shift ++; - - } - - if (x->left_available) - { - for (i = 0; i < 8; i++) - { - Uaverage += uleft_col[i]; - Vaverage += vleft_col[i]; - } - - shift ++; - - } - - expected_udc = (Uaverage + (1 << (shift - 1))) >> shift; - expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift; - } - - - for (i = 0; i < 8; i++) - { - for (j = 0; j < 8; j++) - { - - int predu = uleft_col[i] + uabove_row[j] - utop_left; - int predv = vleft_col[i] + vabove_row[j] - vtop_left; - int u_p, v_p; - - u_p = usrc_ptr[j]; - v_p = vsrc_ptr[j]; - - if (predu < 0) - predu = 0; - - if (predu > 255) - predu = 255; - - if (predv < 0) - predv = 0; - - if (predv > 255) - predv = 255; - - - diff = u_p - expected_udc; - pred_error[DC_PRED] += diff * diff; - diff = v_p - expected_vdc; - pred_error[DC_PRED] += diff * diff; - - - diff = u_p - uabove_row[j]; - pred_error[V_PRED] += diff * diff; - diff = v_p - vabove_row[j]; - pred_error[V_PRED] += diff * diff; - - - diff = u_p - uleft_col[i]; - pred_error[H_PRED] += diff * diff; - diff = v_p - vleft_col[i]; - pred_error[H_PRED] += diff * diff; - - - diff = u_p - predu; - pred_error[TM_PRED] += diff * diff; - diff = v_p - predv; - pred_error[TM_PRED] += diff * diff; - - - } - - usrc_ptr += uvsrc_stride; - vsrc_ptr += uvsrc_stride; - - if (i == 3) - { - usrc_ptr = (mb->block[18].src + *mb->block[18].base_src); - vsrc_ptr = (mb->block[22].src + *mb->block[22].base_src); - } - - - - } - - - for (i = DC_PRED; i <= TM_PRED; i++) - { - if (best_error > pred_error[i]) - { - best_error = pred_error[i]; - best_mode = (MB_PREDICTION_MODE)i; - } - } - - - mb->e_mbd.mode_info_context->mbmi.uv_mode = best_mode; - -} - -static void update_mvcount(VP8_COMP *cpi, MACROBLOCKD *xd, int_mv *best_ref_mv) -{ - /* Split MV modes currently not supported when RD is nopt enabled, - * therefore, only need to modify MVcount in NEWMV mode. */ - if (xd->mode_info_context->mbmi.mode == NEWMV) - { - cpi->MVcount[0][mv_max+((xd->mode_info_context->mbmi.mv.as_mv.row - - best_ref_mv->as_mv.row) >> 1)]++; - cpi->MVcount[1][mv_max+((xd->mode_info_context->mbmi.mv.as_mv.col - - best_ref_mv->as_mv.col) >> 1)]++; - } -} - -void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, - int recon_uvoffset, int *returnrate, - int *returndistortion, int *returnintra) -{ - BLOCK *b = &x->block[0]; - BLOCKD *d = &x->e_mbd.block[0]; - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO best_mbmode; - - int_mv best_ref_mv; - int_mv mode_mv[MB_MODE_COUNT]; - MB_PREDICTION_MODE this_mode; - int num00; - int mdcounts[4]; - int best_rd = INT_MAX; // 1 << 30; - int best_intra_rd = INT_MAX; - int mode_index; - int rate; - int rate2; - int distortion2; - int bestsme; - //int all_rds[MAX_MODES]; // Experimental debug code. - int best_mode_index = 0; - unsigned int sse = INT_MAX, best_sse = INT_MAX; - - int_mv mvp; - int near_sadidx[8] = {0, 1, 2, 3, 4, 5, 6, 7}; - int saddone=0; - int sr=0; //search range got from mv_pred(). It uses step_param levels. (0-7) - - int_mv nearest_mv[4]; - int_mv near_mv[4]; - int_mv frame_best_ref_mv[4]; - int MDCounts[4][4]; - unsigned char *y_buffer[4]; - unsigned char *u_buffer[4]; - unsigned char *v_buffer[4]; - - int skip_mode[4] = {0, 0, 0, 0}; - - int have_subp_search = cpi->sf.half_pixel_search; /* In real-time mode, when Speed >= 15, no sub-pixel search. */ - - vpx_memset(mode_mv, 0, sizeof(mode_mv)); - vpx_memset(nearest_mv, 0, sizeof(nearest_mv)); - vpx_memset(near_mv, 0, sizeof(near_mv)); - vpx_memset(&best_mbmode, 0, sizeof(best_mbmode)); - - - // set up all the refframe dependent pointers. - if (cpi->ref_frame_flags & VP8_LAST_FLAG) - { - YV12_BUFFER_CONFIG *lst_yv12 = &cpi->common.yv12_fb[cpi->common.lst_fb_idx]; - - vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &nearest_mv[LAST_FRAME], &near_mv[LAST_FRAME], - &frame_best_ref_mv[LAST_FRAME], MDCounts[LAST_FRAME], LAST_FRAME, cpi->common.ref_frame_sign_bias); - - y_buffer[LAST_FRAME] = lst_yv12->y_buffer + recon_yoffset; - u_buffer[LAST_FRAME] = lst_yv12->u_buffer + recon_uvoffset; - v_buffer[LAST_FRAME] = lst_yv12->v_buffer + recon_uvoffset; - } - else - skip_mode[LAST_FRAME] = 1; - - if (cpi->ref_frame_flags & VP8_GOLD_FLAG) - { - YV12_BUFFER_CONFIG *gld_yv12 = &cpi->common.yv12_fb[cpi->common.gld_fb_idx]; - - vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &nearest_mv[GOLDEN_FRAME], &near_mv[GOLDEN_FRAME], - &frame_best_ref_mv[GOLDEN_FRAME], MDCounts[GOLDEN_FRAME], GOLDEN_FRAME, cpi->common.ref_frame_sign_bias); - - y_buffer[GOLDEN_FRAME] = gld_yv12->y_buffer + recon_yoffset; - u_buffer[GOLDEN_FRAME] = gld_yv12->u_buffer + recon_uvoffset; - v_buffer[GOLDEN_FRAME] = gld_yv12->v_buffer + recon_uvoffset; - } - else - skip_mode[GOLDEN_FRAME] = 1; - - if (cpi->ref_frame_flags & VP8_ALT_FLAG && cpi->source_alt_ref_active) - { - YV12_BUFFER_CONFIG *alt_yv12 = &cpi->common.yv12_fb[cpi->common.alt_fb_idx]; - - vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &nearest_mv[ALTREF_FRAME], &near_mv[ALTREF_FRAME], - &frame_best_ref_mv[ALTREF_FRAME], MDCounts[ALTREF_FRAME], ALTREF_FRAME, cpi->common.ref_frame_sign_bias); - - y_buffer[ALTREF_FRAME] = alt_yv12->y_buffer + recon_yoffset; - u_buffer[ALTREF_FRAME] = alt_yv12->u_buffer + recon_uvoffset; - v_buffer[ALTREF_FRAME] = alt_yv12->v_buffer + recon_uvoffset; - } - else - skip_mode[ALTREF_FRAME] = 1; - - cpi->mbs_tested_so_far++; // Count of the number of MBs tested so far this frame - - *returnintra = INT_MAX; - x->skip = 0; - - x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; - - // if we encode a new mv this is important - // find the best new motion vector - for (mode_index = 0; mode_index < MAX_MODES; mode_index++) - { - int frame_cost; - int this_rd = INT_MAX; - - if (best_rd <= cpi->rd_threshes[mode_index]) - continue; - - x->e_mbd.mode_info_context->mbmi.ref_frame = vp8_ref_frame_order[mode_index]; - - if (skip_mode[x->e_mbd.mode_info_context->mbmi.ref_frame]) - continue; - - // Check to see if the testing frequency for this mode is at its max - // If so then prevent it from being tested and increase the threshold for its testing - if (cpi->mode_test_hit_counts[mode_index] && (cpi->mode_check_freq[mode_index] > 1)) - { - //if ( (cpi->mbs_tested_so_far / cpi->mode_test_hit_counts[mode_index]) <= cpi->mode_check_freq[mode_index] ) - if (cpi->mbs_tested_so_far <= (cpi->mode_check_freq[mode_index] * cpi->mode_test_hit_counts[mode_index])) - { - // Increase the threshold for coding this mode to make it less likely to be chosen - cpi->rd_thresh_mult[mode_index] += 4; - - if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) - cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; - - cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; - - continue; - } - } - - // We have now reached the point where we are going to test the current mode so increment the counter for the number of times it has been tested - cpi->mode_test_hit_counts[mode_index] ++; - - rate2 = 0; - distortion2 = 0; - - this_mode = vp8_mode_order[mode_index]; - - // Experimental debug code. - //all_rds[mode_index] = -1; - - x->e_mbd.mode_info_context->mbmi.mode = this_mode; - x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; - - // Work out the cost assosciated with selecting the reference frame - frame_cost = - x->e_mbd.ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; - rate2 += frame_cost; - - // everything but intra - if (x->e_mbd.mode_info_context->mbmi.ref_frame) - { - x->e_mbd.pre.y_buffer = y_buffer[x->e_mbd.mode_info_context->mbmi.ref_frame]; - x->e_mbd.pre.u_buffer = u_buffer[x->e_mbd.mode_info_context->mbmi.ref_frame]; - x->e_mbd.pre.v_buffer = v_buffer[x->e_mbd.mode_info_context->mbmi.ref_frame]; - mode_mv[NEARESTMV] = nearest_mv[x->e_mbd.mode_info_context->mbmi.ref_frame]; - mode_mv[NEARMV] = near_mv[x->e_mbd.mode_info_context->mbmi.ref_frame]; - best_ref_mv = frame_best_ref_mv[x->e_mbd.mode_info_context->mbmi.ref_frame]; - memcpy(mdcounts, MDCounts[x->e_mbd.mode_info_context->mbmi.ref_frame], sizeof(mdcounts)); - } - - // Only consider ZEROMV/ALTREF_FRAME for alt ref frame, - // unless ARNR filtering is enabled in which case we want - // an unfiltered alternative - if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) - { - if (this_mode != ZEROMV || x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME) - continue; - } - - switch (this_mode) - { - case B_PRED: - // Pass best so far to pick_intra4x4mby_modes to use as breakout - distortion2 = best_sse; - pick_intra4x4mby_modes(IF_RTCD(&cpi->rtcd), x, &rate, &distortion2); - - if (distortion2 == INT_MAX) - { - this_rd = INT_MAX; - } - else - { - rate2 += rate; - distortion2 = VARIANCE_INVOKE - (&cpi->rtcd.variance, var16x16)( - *(b->base_src), b->src_stride, - x->e_mbd.predictor, 16, &sse); - this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); - - if (this_rd < best_intra_rd) - { - best_intra_rd = this_rd; - *returnintra = distortion2; - } - } - - break; - - case SPLITMV: - - // Split MV modes currently not supported when RD is nopt enabled. - break; - - case DC_PRED: - case V_PRED: - case H_PRED: - case TM_PRED: - RECON_INVOKE(&cpi->common.rtcd.recon, build_intra_predictors_mby) - (&x->e_mbd); - distortion2 = VARIANCE_INVOKE(&cpi->rtcd.variance, var16x16) - (*(b->base_src), b->src_stride, - x->e_mbd.predictor, 16, &sse); - rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode]; - this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); - - if (this_rd < best_intra_rd) - { - best_intra_rd = this_rd; - *returnintra = distortion2; - } - break; - - case NEWMV: - { - int thissme; - int step_param; - int further_steps; - int n = 0; - int sadpb = x->sadperbit16; - int_mv mvp_full; - - int col_min = (best_ref_mv.as_mv.col>>3) - MAX_FULL_PEL_VAL + ((best_ref_mv.as_mv.col & 7)?1:0); - int row_min = (best_ref_mv.as_mv.row>>3) - MAX_FULL_PEL_VAL + ((best_ref_mv.as_mv.row & 7)?1:0); - int col_max = (best_ref_mv.as_mv.col>>3) + MAX_FULL_PEL_VAL; - int row_max = (best_ref_mv.as_mv.row>>3) + MAX_FULL_PEL_VAL; - - int tmp_col_min = x->mv_col_min; - int tmp_col_max = x->mv_col_max; - int tmp_row_min = x->mv_row_min; - int tmp_row_max = x->mv_row_max; - - int speed_adjust = (cpi->Speed > 5) ? ((cpi->Speed >= 8)? 3 : 2) : 1; - - // Further step/diamond searches as necessary - step_param = cpi->sf.first_step + speed_adjust; - - if(cpi->sf.improved_mv_pred) - { - if(!saddone) - { - vp8_cal_sad(cpi,xd,x, recon_yoffset ,&near_sadidx[0] ); - saddone = 1; - } - - vp8_mv_pred(cpi, &x->e_mbd, x->e_mbd.mode_info_context, &mvp, - x->e_mbd.mode_info_context->mbmi.ref_frame, cpi->common.ref_frame_sign_bias, &sr, &near_sadidx[0]); - - sr += speed_adjust; - //adjust search range according to sr from mv prediction - if(sr > step_param) - step_param = sr; - - mvp_full.as_mv.col = mvp.as_mv.col>>3; - mvp_full.as_mv.row = mvp.as_mv.row>>3; - - }else - { - mvp.as_int = best_ref_mv.as_int; - mvp_full.as_mv.col = best_ref_mv.as_mv.col>>3; - mvp_full.as_mv.row = best_ref_mv.as_mv.row>>3; - } - - // Get intersection of UMV window and valid MV window to reduce # of checks in diamond search. - if (x->mv_col_min < col_min ) - x->mv_col_min = col_min; - if (x->mv_col_max > col_max ) - x->mv_col_max = col_max; - if (x->mv_row_min < row_min ) - x->mv_row_min = row_min; - if (x->mv_row_max > row_max ) - x->mv_row_max = row_max; - - further_steps = (cpi->Speed >= 8)? 0: (cpi->sf.max_step_search_steps - 1 - step_param); - - if (cpi->sf.search_method == HEX) - { - bestsme = vp8_hex_search(x, b, d, &mvp_full, &d->bmi.mv, step_param, - sadpb, &cpi->fn_ptr[BLOCK_16X16], - x->mvsadcost, x->mvcost, &best_ref_mv); - mode_mv[NEWMV].as_int = d->bmi.mv.as_int; - } - else - { - bestsme = cpi->diamond_search_sad(x, b, d, &mvp_full, &d->bmi.mv, - step_param, sadpb, &num00, - &cpi->fn_ptr[BLOCK_16X16], - x->mvcost, &best_ref_mv); - mode_mv[NEWMV].as_int = d->bmi.mv.as_int; - - // Further step/diamond searches as necessary - n = 0; - //further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; - - n = num00; - num00 = 0; - - while (n < further_steps) - { - n++; - - if (num00) - num00--; - else - { - thissme = - cpi->diamond_search_sad(x, b, d, &mvp_full, - &d->bmi.mv, - step_param + n, - sadpb, &num00, - &cpi->fn_ptr[BLOCK_16X16], - x->mvcost, &best_ref_mv); - if (thissme < bestsme) - { - bestsme = thissme; - mode_mv[NEWMV].as_int = d->bmi.mv.as_int; - } - else - { - d->bmi.mv.as_int = mode_mv[NEWMV].as_int; - } - } - } - } - - x->mv_col_min = tmp_col_min; - x->mv_col_max = tmp_col_max; - x->mv_row_min = tmp_row_min; - x->mv_row_max = tmp_row_max; - - if (bestsme < INT_MAX) - cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv, &best_ref_mv, - x->errorperbit, - &cpi->fn_ptr[BLOCK_16X16], - cpi->mb.mvcost, - &distortion2,&sse); - - mode_mv[NEWMV].as_int = d->bmi.mv.as_int; - - // mv cost; - rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, cpi->mb.mvcost, 128); - } - - case NEARESTMV: - case NEARMV: - - if (mode_mv[this_mode].as_int == 0) - continue; - - case ZEROMV: - - // Trap vectors that reach beyond the UMV borders - // Note that ALL New MV, Nearest MV Near MV and Zero MV code drops through to this point - // because of the lack of break statements in the previous two cases. - if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) || - ((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max)) - continue; - - rate2 += vp8_cost_mv_ref(this_mode, mdcounts); - x->e_mbd.mode_info_context->mbmi.mv.as_int = - mode_mv[this_mode].as_int; - - /* Exit early and don't compute the distortion if this macroblock is marked inactive. */ - if (cpi->active_map_enabled && x->active_ptr[0] == 0) - { - sse = 0; - distortion2 = 0; - x->skip = 1; - break; - } - - if((this_mode != NEWMV) || - !(have_subp_search) || cpi->common.full_pixel==1) - distortion2 = get_inter_mbpred_error(x, - &cpi->fn_ptr[BLOCK_16X16], - &sse, mode_mv[this_mode]); - - this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); - - if (sse < x->encode_breakout) - { - // Check u and v to make sure skip is ok - int sse2 = 0; - - sse2 = VP8_UVSSE(x, IF_RTCD(&cpi->rtcd.variance)); - - if (sse2 * 2 < x->encode_breakout) - x->skip = 1; - else - x->skip = 0; - } - - break; - default: - break; - } - - // Experimental debug code. - //all_rds[mode_index] = this_rd; - - if (this_rd < best_rd || x->skip) - { - // Note index of best mode - best_mode_index = mode_index; - - *returnrate = rate2; - *returndistortion = distortion2; - best_sse = sse; - best_rd = this_rd; - vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); - - // Testing this mode gave rise to an improvement in best error score. Lower threshold a bit for next time - cpi->rd_thresh_mult[mode_index] = (cpi->rd_thresh_mult[mode_index] >= (MIN_THRESHMULT + 2)) ? cpi->rd_thresh_mult[mode_index] - 2 : MIN_THRESHMULT; - cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; - } - - // If the mode did not help improve the best error case then raise the threshold for testing that mode next time around. - else - { - cpi->rd_thresh_mult[mode_index] += 4; - - if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) - cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; - - cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; - } - - if (x->skip) - break; - } - - // Reduce the activation RD thresholds for the best choice mode - if ((cpi->rd_baseline_thresh[best_mode_index] > 0) && (cpi->rd_baseline_thresh[best_mode_index] < (INT_MAX >> 2))) - { - int best_adjustment = (cpi->rd_thresh_mult[best_mode_index] >> 3); - - cpi->rd_thresh_mult[best_mode_index] = (cpi->rd_thresh_mult[best_mode_index] >= (MIN_THRESHMULT + best_adjustment)) ? cpi->rd_thresh_mult[best_mode_index] - best_adjustment : MIN_THRESHMULT; - cpi->rd_threshes[best_mode_index] = (cpi->rd_baseline_thresh[best_mode_index] >> 7) * cpi->rd_thresh_mult[best_mode_index]; - } - - - { - int this_rdbin = (*returndistortion >> 7); - - if (this_rdbin >= 1024) - { - this_rdbin = 1023; - } - - cpi->error_bins[this_rdbin] ++; - } - - if (cpi->is_src_frame_alt_ref && - (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) - { - x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; - x->e_mbd.mode_info_context->mbmi.ref_frame = ALTREF_FRAME; - x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; - x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; - x->e_mbd.mode_info_context->mbmi.mb_skip_coeff = - (cpi->common.mb_no_coeff_skip) ? 1 : 0; - x->e_mbd.mode_info_context->mbmi.partitioning = 0; - - return; - } - - /* set to the best mb mode */ - vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mbmode, sizeof(MB_MODE_INFO)); - - if (best_mbmode.mode <= B_PRED) - { - /* set mode_info_context->mbmi.uv_mode */ - pick_intra_mbuv_mode(x); - } - - update_mvcount(cpi, &x->e_mbd, &frame_best_ref_mv[xd->mode_info_context->mbmi.ref_frame]); -} - - -void vp8_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate_) -{ - int error4x4, error16x16 = INT_MAX; - int rate, best_rate = 0, distortion, best_sse; - MB_PREDICTION_MODE mode, best_mode = DC_PRED; - int this_rd; - unsigned int sse; - BLOCK *b = &x->block[0]; - - x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; - - pick_intra_mbuv_mode(x); - - for (mode = DC_PRED; mode <= TM_PRED; mode ++) - { - x->e_mbd.mode_info_context->mbmi.mode = mode; - RECON_INVOKE(&cpi->common.rtcd.recon, build_intra_predictors_mby) - (&x->e_mbd); - distortion = VARIANCE_INVOKE(&cpi->rtcd.variance, var16x16) - (*(b->base_src), b->src_stride, x->e_mbd.predictor, 16, &sse); - rate = x->mbmode_cost[x->e_mbd.frame_type][mode]; - this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); - - if (error16x16 > this_rd) - { - error16x16 = this_rd; - best_mode = mode; - best_sse = sse; - best_rate = rate; - } - } - x->e_mbd.mode_info_context->mbmi.mode = best_mode; - - error4x4 = pick_intra4x4mby_modes(IF_RTCD(&cpi->rtcd), x, &rate, - &best_sse); - if (error4x4 < error16x16) - { - x->e_mbd.mode_info_context->mbmi.mode = B_PRED; - best_rate = rate; - } - - *rate_ = best_rate; -} diff --git a/vp8/encoder/picklpf.c b/vp8/encoder/picklpf.c index beefe8d8e..171ec3a4d 100644 --- a/vp8/encoder/picklpf.c +++ b/vp8/encoder/picklpf.c @@ -36,6 +36,15 @@ extern void (*vp8_yv12_copy_partial_frame_ptr)(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction); + +extern void vp8_loop_filter_frame_segment +( + VP8_COMMON *cm, + MACROBLOCKD *xd, + int default_filt_lvl, + int segment +); + void vp8_yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction) { @@ -63,7 +72,6 @@ vp8_yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst vpx_memcpy(dst_y, src_y, ystride *(linestocopy + 16)); } - static int vp8_calc_partial_ssl_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, int Fraction, const vp8_variance_rtcd_vtable_t *rtcd) { int i, j; @@ -107,18 +115,21 @@ static int vp8_calc_partial_ssl_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONF static int get_min_filter_level(VP8_COMP *cpi, int base_qindex) { int min_filter_level; + /*int q = (int) vp8_convert_qindex_to_q(base_qindex); if (cpi->source_alt_ref_active && cpi->common.refresh_golden_frame && !cpi->common.refresh_alt_ref_frame) min_filter_level = 0; else { - if (base_qindex <= 6) + if (q <= 10) min_filter_level = 0; - else if (base_qindex <= 16) + else if (q <= 64) min_filter_level = 1; else - min_filter_level = (base_qindex / 8); + min_filter_level = (q >> 6); } + */ + min_filter_level = 0; return min_filter_level; } @@ -256,15 +267,230 @@ void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) // Stub function for now Alt LF not used void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val) { - MACROBLOCKD *mbd = &cpi->mb.e_mbd; - (void) filt_val; +} +#if CONFIG_FEATUREUPDATES +void vp8cx_pick_filter_level_sg(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi, int segment) +{ + VP8_COMMON *cm = &cpi->common; - mbd->segment_feature_data[MB_LVL_ALT_LF][0] = cpi->segment_feature_data[MB_LVL_ALT_LF][0]; - mbd->segment_feature_data[MB_LVL_ALT_LF][1] = cpi->segment_feature_data[MB_LVL_ALT_LF][1]; - mbd->segment_feature_data[MB_LVL_ALT_LF][2] = cpi->segment_feature_data[MB_LVL_ALT_LF][2]; - mbd->segment_feature_data[MB_LVL_ALT_LF][3] = cpi->segment_feature_data[MB_LVL_ALT_LF][3]; + int best_err = 0; + int filt_err = 0; + int min_filter_level = get_min_filter_level(cpi, cm->base_qindex); + int max_filter_level = get_max_filter_level(cpi, cm->base_qindex); + + int filter_step; + int filt_high = 0; + int filt_mid = cm->filter_level; // Start search at previous frame filter level + int filt_low = 0; + int filt_best; + int filt_direction = 0; + + int Bias = 0; // Bias against raising loop filter and in favour of lowering it + + // Make a copy of the unfiltered / processed recon buffer +#if HAVE_ARMV7 +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->rtcd.flags & HAS_NEON) +#endif + { + vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(cm->frame_to_show, &cpi->last_frame_uf); + } +#if CONFIG_RUNTIME_CPU_DETECT + else +#endif +#endif +#if !HAVE_ARMV7 || CONFIG_RUNTIME_CPU_DETECT + { + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cpi->last_frame_uf); + } +#endif + + if (cm->frame_type == KEY_FRAME) + cm->sharpness_level = 0; + else + cm->sharpness_level = cpi->oxcf.Sharpness; + + // Start the search at the previous frame filter level unless it is now out of range. + filt_mid = cm->filter_level; + + if (filt_mid < min_filter_level) + filt_mid = min_filter_level; + else if (filt_mid > max_filter_level) + filt_mid = max_filter_level; + + // Define the initial step size + filter_step = (filt_mid < 16) ? 4 : filt_mid / 4; + + // Get baseline error score + vp8cx_set_alt_lf_level(cpi, filt_mid); + vp8_loop_filter_frame_segment(cm, &cpi->mb.e_mbd, filt_mid,segment); + + best_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance)); + filt_best = filt_mid; + + // Re-instate the unfiltered frame +#if HAVE_ARMV7 +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->rtcd.flags & HAS_NEON) +#endif + { + vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show); + } +#if CONFIG_RUNTIME_CPU_DETECT + else +#endif +#endif +#if !HAVE_ARMV7 || CONFIG_RUNTIME_CPU_DETECT + { + vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show); + } +#endif + + while (filter_step > 0) + { + Bias = (best_err >> (15 - (filt_mid / 8))) * filter_step; //PGW change 12/12/06 for small images + + // jbb chg: 20100118 - in sections with lots of new material coming in don't bias as much to a low filter value + if (cpi->twopass.section_intra_rating < 20) + Bias = Bias * cpi->twopass.section_intra_rating / 20; + + // yx, bias less for large block size + if(cpi->common.txfm_mode == ALLOW_8X8) + Bias >>= 1; + + filt_high = ((filt_mid + filter_step) > max_filter_level) ? max_filter_level : (filt_mid + filter_step); + filt_low = ((filt_mid - filter_step) < min_filter_level) ? min_filter_level : (filt_mid - filter_step); + + if ((filt_direction <= 0) && (filt_low != filt_mid)) + { + // Get Low filter error score + vp8cx_set_alt_lf_level(cpi, filt_low); + vp8_loop_filter_frame_segment(cm, &cpi->mb.e_mbd, filt_low, segment); + + filt_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance)); + + // Re-instate the unfiltered frame +#if HAVE_ARMV7 +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->rtcd.flags & HAS_NEON) +#endif + { + vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show); + } +#if CONFIG_RUNTIME_CPU_DETECT + else +#endif +#endif +#if !HAVE_ARMV7 || CONFIG_RUNTIME_CPU_DETECT + { + vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show); + } +#endif + + // If value is close to the best so far then bias towards a lower loop filter value. + if ((filt_err - Bias) < best_err) + { + // Was it actually better than the previous best? + if (filt_err < best_err) + best_err = filt_err; + + filt_best = filt_low; + } + } + + // Now look at filt_high + if ((filt_direction >= 0) && (filt_high != filt_mid)) + { + vp8cx_set_alt_lf_level(cpi, filt_high); + vp8_loop_filter_frame_segment(cm, &cpi->mb.e_mbd, filt_high, segment); + + filt_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance)); + + // Re-instate the unfiltered frame +#if HAVE_ARMV7 +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->rtcd.flags & HAS_NEON) +#endif + { + vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show); + } +#if CONFIG_RUNTIME_CPU_DETECT + else +#endif +#endif +#if !HAVE_ARMV7 || CONFIG_RUNTIME_CPU_DETECT + { + vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show); + } +#endif + + // Was it better than the previous best? + if (filt_err < (best_err - Bias)) + { + best_err = filt_err; + filt_best = filt_high; + } + } + + // Half the step distance if the best filter value was the same as last time + if (filt_best == filt_mid) + { + filter_step = filter_step / 2; + filt_direction = 0; + } + else + { + filt_direction = (filt_best < filt_mid) ? -1 : 1; + filt_mid = filt_best; + } + } + + cm->filter_level = filt_best; } +void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) +{ + VP8_COMMON *oci = &cpi->common; + MODE_INFO *mi = oci->mi; + int filt_lev[2]; + int i, j; + MACROBLOCKD * const xd = &cpi->mb.e_mbd; + int max_seg; + int mb_index = 0; + + // pick the loop filter for each segment after segment 0 + for (i = 1; i < MAX_MB_SEGMENTS; i++) + { + // if the segment loop filter is active + if (segfeature_active(xd, i, SEG_LVL_ALT_LF)) + { + set_segdata(xd, i, SEG_LVL_ALT_LF, 0); + vp8cx_pick_filter_level_sg(sd, cpi, i); + filt_lev[i] = oci->filter_level; + } + } + + // do the 0 segment ( this filter also picks the filter value for all + // the not enabled features ) + + // TODO : Fix the code if segment 0 is the one with seg_lvl_alt_lf on + // right now assumes segment 0 gets base loop filter and the rest are + // deltas off of segment 0. + set_segdata(xd, 0, SEG_LVL_ALT_LF, 0); + vp8cx_pick_filter_level_sg(sd, cpi, 0); + filt_lev[0] = oci->filter_level; + + // convert the best filter level for the mbs of the segment to + // a delta from 0 + for (i = 1; i < MAX_MB_SEGMENTS; i++) + if (segfeature_active(xd, i, SEG_LVL_ALT_LF)) + { + set_segdata(xd, i, SEG_LVL_ALT_LF, filt_lev[i] - filt_lev[0]); + xd->update_mb_segmentation_data != + segfeature_changed( xd,i,SEG_LVL_ALT_LF); + } +} +#else void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) { VP8_COMMON *cm = &cpi->common; @@ -350,6 +576,10 @@ void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) if (cpi->twopass.section_intra_rating < 20) Bias = Bias * cpi->twopass.section_intra_rating / 20; + // yx, bias less for large block size + if(cpi->common.txfm_mode == ALLOW_8X8) + Bias >>= 1; + filt_high = ((filt_mid + filter_step) > max_filter_level) ? max_filter_level : (filt_mid + filter_step); filt_low = ((filt_mid - filter_step) < min_filter_level) ? min_filter_level : (filt_mid - filter_step); @@ -439,3 +669,5 @@ void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) cm->filter_level = filt_best; } +#endif + diff --git a/vp8/encoder/ppc/csystemdependent.c b/vp8/encoder/ppc/csystemdependent.c index 63f235784..49b1dd6a9 100644 --- a/vp8/encoder/ppc/csystemdependent.c +++ b/vp8/encoder/ppc/csystemdependent.c @@ -48,8 +48,6 @@ void (*vp8_subtract_mby)(short *diff, unsigned char *src, unsigned char *pred, i void (*vp8_subtract_mbuv)(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); void (*vp8_fast_quantize_b)(BLOCK *b, BLOCKD *d); -unsigned int (*vp8_get4x4sse_cs)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); - // c imports extern int block_error_c(short *coeff, short *dqcoeff); extern int vp8_mbblock_error_c(MACROBLOCK *mb, int dc); @@ -85,7 +83,6 @@ extern sub_pixel_variance_function sub_pixel_variance16x8_c; extern sub_pixel_variance_function sub_pixel_variance16x16_c; extern unsigned int vp8_get_mb_ss_c(short *); -extern unsigned int vp8_get4x4sse_cs_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); // ppc extern int vp8_block_error_ppc(short *coeff, short *dqcoeff); @@ -143,7 +140,6 @@ void vp8_cmachine_specific_config(void) vp8_sub_pixel_variance16x16 = vp8_sub_pixel_variance16x16_ppc; vp8_get_mb_ss = vp8_get_mb_ss_c; - vp8_get4x4sse_cs = vp8_get4x4sse_cs_c; vp8_sad16x16 = vp8_sad16x16_ppc; vp8_sad16x8 = vp8_sad16x8_ppc; diff --git a/vp8/encoder/quantize.c b/vp8/encoder/quantize.c index 503d24123..636ed3a67 100644 --- a/vp8/encoder/quantize.c +++ b/vp8/encoder/quantize.c @@ -16,60 +16,16 @@ #include "quantize.h" #include "vp8/common/quant_common.h" +#include "vp8/common/seg_common.h" + +#ifdef ENC_DEBUG +extern int enc_debug; +#endif + #define EXACT_QUANT - -#ifdef EXACT_FASTQUANT void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d) { - int i, rc, eob; - int zbin; - int x, y, z, sz; - short *coeff_ptr = b->coeff; - short *zbin_ptr = b->zbin; - short *round_ptr = b->round; - short *quant_ptr = b->quant_fast; - unsigned char *quant_shift_ptr = b->quant_shift; - short *qcoeff_ptr = d->qcoeff; - short *dqcoeff_ptr = d->dqcoeff; - short *dequant_ptr = d->dequant; - - vpx_memset(qcoeff_ptr, 0, 32); - vpx_memset(dqcoeff_ptr, 0, 32); - - eob = -1; - - for (i = 0; i < 16; i++) - { - rc = vp8_default_zig_zag1d[i]; - z = coeff_ptr[rc]; - zbin = zbin_ptr[rc] ; - - sz = (z >> 31); // sign of z - x = (z ^ sz) - sz; // x = abs(z) - - if (x >= zbin) - { - x += round_ptr[rc]; - y = (((x * quant_ptr[rc]) >> 16) + x) - >> quant_shift_ptr[rc]; // quantize (x) - x = (y ^ sz) - sz; // get the sign back - qcoeff_ptr[rc] = x; // write to destination - dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value - - if (y) - { - eob = i; // last nonzero coeffs - } - } - } - d->eob = eob + 1; -} - -#else - -void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d) -{ - int i, rc, eob; + int i, rc, eob, nonzeros; int x, y, z, sz; short *coeff_ptr = b->coeff; short *round_ptr = b->round; @@ -78,6 +34,9 @@ void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d) short *dqcoeff_ptr = d->dqcoeff; short *dequant_ptr = d->dequant; + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + eob = -1; for (i = 0; i < 16; i++) { @@ -100,7 +59,7 @@ void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d) d->eob = eob + 1; } -#endif + #ifdef EXACT_QUANT void vp8_regular_quantize_b(BLOCK *b, BLOCKD *d) @@ -124,7 +83,7 @@ void vp8_regular_quantize_b(BLOCK *b, BLOCKD *d) eob = -1; - for (i = 0; i < 16; i++) + for (i = 0; i < b->eob_max_offset; i++) { rc = vp8_default_zig_zag1d[i]; z = coeff_ptr[rc]; @@ -268,11 +227,14 @@ void vp8_regular_quantize_b(BLOCK *b, BLOCKD *d) } #endif +//EXACT_QUANT + void vp8_quantize_mby_c(MACROBLOCK *x) { int i; int has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != I8X8_PRED && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); for (i = 0; i < 16; i++) @@ -286,6 +248,7 @@ void vp8_quantize_mb_c(MACROBLOCK *x) { int i; int has_2nd_order=(x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != I8X8_PRED && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); for (i = 0; i < 24+has_2nd_order; i++) @@ -301,6 +264,394 @@ void vp8_quantize_mbuv_c(MACROBLOCK *x) x->quantize_b(&x->block[i], &x->e_mbd.block[i]); } + + + +void vp8_fast_quantize_b_2x2_c(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *coeff_ptr = b->coeff; + short *zbin_ptr = b->zbin; + short *round_ptr = b->round; + short *quant_ptr = b->quant; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + //double q2nd = 4; + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + + eob = -1; + + for (i = 0; i < 4; i++) + { + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + //zbin = zbin_ptr[rc]/q2nd; + zbin = zbin_ptr[rc]; + + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + //y = ((int)((x + round_ptr[rc]/q2nd) * quant_ptr[rc] * q2nd)) >> 16; // quantize (x) + y = ((int)((x + round_ptr[rc]) * quant_ptr[rc])) >> 16; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + //dqcoeff_ptr[rc] = x * dequant_ptr[rc] / q2nd; // dequantized value + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value + dqcoeff_ptr[rc] = (dqcoeff_ptr[rc]+2)>>2; + + if (y) + { + eob = i; // last nonzero coeffs + } + } + } + d->eob = eob + 1; + //if (d->eob > 4) printf("Flag Fast 2 (%d)\n", d->eob); +} + +void vp8_fast_quantize_b_8x8_c(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *coeff_ptr = b->coeff; + short *zbin_ptr = b->zbin; + short *round_ptr = b->round; + short *quant_ptr = b->quant; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + //double q1st = 2; + vpx_memset(qcoeff_ptr, 0, 64*sizeof(short)); + vpx_memset(dqcoeff_ptr, 0, 64*sizeof(short)); + + eob = -1; + + + + for (i = 0; i < 64; i++) + { + + rc = vp8_default_zig_zag1d_8x8[i]; + z = coeff_ptr[rc]; + //zbin = zbin_ptr[rc!=0]/q1st ; + zbin = zbin_ptr[rc!=0] ; + + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + //y = ((int)((x + round_ptr[rc!=0] / q1st) * quant_ptr[rc!=0] * q1st)) >> 16; + y = ((int)((x + round_ptr[rc!=0]) * quant_ptr[rc!=0])) >> 16; + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + //dqcoeff_ptr[rc] = x * dequant_ptr[rc!=0] / q1st; // dequantized value + dqcoeff_ptr[rc] = x * dequant_ptr[rc!=0]; // dequantized value + dqcoeff_ptr[rc] = (dqcoeff_ptr[rc]+2)>>2; + + if (y) + { + eob = i; // last nonzero coeffs + } + } + } + d->eob = eob + 1; +} + + + + +void vp8_regular_quantize_b_2x2(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *zbin_boost_ptr = b->zrun_zbin_boost; + short *coeff_ptr = b->coeff; + short *zbin_ptr = b->zbin; + short *round_ptr = b->round; + short *quant_ptr = b->quant; + unsigned char *quant_shift_ptr = b->quant_shift; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + short zbin_oq_value = b->zbin_extra; + //double q2nd = 4; + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + + eob = -1; + + for (i = 0; i < b->eob_max_offset_8x8; i++) + { + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + + //zbin = (zbin_ptr[rc] + *zbin_boost_ptr + zbin_oq_value)/q2nd; + zbin = (zbin_ptr[rc] + *zbin_boost_ptr + zbin_oq_value); + + zbin_boost_ptr ++; + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + //x += (round_ptr[rc]/q2nd); + x += (round_ptr[rc]); + y = ((int)((int)(x * quant_ptr[rc]) >> 16) + x) + >> quant_shift_ptr[rc]; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + //dqcoeff_ptr[rc] = x * dequant_ptr[rc]/q2nd; // dequantized value + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value + + + if (y) + { + eob = i; // last nonzero coeffs + zbin_boost_ptr = &b->zrun_zbin_boost[0]; // reset zero runlength + } + } + } + + d->eob = eob + 1; +} + +void vp8_regular_quantize_b_8x8(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *zbin_boost_ptr = b->zrun_zbin_boost; + short *coeff_ptr = b->coeff; + short *zbin_ptr = b->zbin; + short *round_ptr = b->round; + short *quant_ptr = b->quant; + unsigned char *quant_shift_ptr = b->quant_shift; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + short zbin_oq_value = b->zbin_extra; + //double q1st = 2; + + vpx_memset(qcoeff_ptr, 0, 64*sizeof(short)); + vpx_memset(dqcoeff_ptr, 0, 64*sizeof(short)); + + eob = -1; + + for (i = 0; i < b->eob_max_offset_8x8; i++) + { + + rc = vp8_default_zig_zag1d_8x8[i]; + z = coeff_ptr[rc]; + + //zbin = (zbin_ptr[rc!=0] + *zbin_boost_ptr + zbin_oq_value)/q1st; + zbin = (zbin_ptr[rc!=0] + *zbin_boost_ptr + zbin_oq_value); + //TODO: 8x8 zbin boost needs be done properly + if(zbin_boost_ptr < &b->zrun_zbin_boost[15]) + zbin_boost_ptr ++; + + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + //x += (round_ptr[rc!=0]/q1st); + //y = ((int)(((int)(x * quant_ptr[rc!=0] * q1st) >> 16) + x)) + // >> quant_shift_ptr[rc!=0]; // quantize (x) + x += (round_ptr[rc!=0]); + y = ((int)(((int)(x * quant_ptr[rc!=0]) >> 16) + x)) + >> quant_shift_ptr[rc!=0]; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + //dqcoeff_ptr[rc] = x * dequant_ptr[rc!=0] / q1st; // dequantized value + dqcoeff_ptr[rc] = x * dequant_ptr[rc!=0]; // dequantized value + + if (y) + { + eob = i; // last nonzero coeffs + zbin_boost_ptr = &b->zrun_zbin_boost[0]; // reset zero runlength + } + } + } + + d->eob = eob + 1; +} + +void vp8_strict_quantize_b_2x2(BLOCK *b, BLOCKD *d) +{ + int i; + int rc; + int eob; + int x; + int y; + int z; + int sz; + short *coeff_ptr; + short *quant_ptr; + unsigned char *quant_shift_ptr; + short *qcoeff_ptr; + short *dqcoeff_ptr; + short *dequant_ptr; + //double q2nd = 4; + coeff_ptr = b->coeff; + quant_ptr = b->quant; + quant_shift_ptr = b->quant_shift; + qcoeff_ptr = d->qcoeff; + dqcoeff_ptr = d->dqcoeff; + dequant_ptr = d->dequant; + eob = - 1; + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + for (i = 0; i < 4; i++) + { + int dq; + int round; + + /*TODO: These arrays should be stored in zig-zag order.*/ + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + //z = z * q2nd; + //dq = dequant_ptr[rc]/q2nd; + dq = dequant_ptr[rc]; + round = dq >> 1; + /* Sign of z. */ + sz = -(z < 0); + x = (z + sz) ^ sz; + x += round; + if (x >= dq) + { + /* Quantize x */ + y = (((x * quant_ptr[rc]) >> 16) + x) >> quant_shift_ptr[rc]; + /* Put the sign back. */ + x = (y + sz) ^ sz; + /* Save * the * coefficient and its dequantized value. */ + qcoeff_ptr[rc] = x; + dqcoeff_ptr[rc] = x * dq; + /* Remember the last non-zero coefficient. */ + if (y) + eob = i; + } + } + d->eob = eob + 1; +} + +void vp8_strict_quantize_b_8x8(BLOCK *b, BLOCKD *d) +{ + int i; + int rc; + int eob; + int x; + int y; + int z; + int sz; + short *coeff_ptr; + short *quant_ptr; + unsigned char *quant_shift_ptr; + short *qcoeff_ptr; + short *dqcoeff_ptr; + short *dequant_ptr; + //double q1st = 2; + printf("call strict quantizer\n"); + coeff_ptr = b->coeff; + quant_ptr = b->quant; + quant_shift_ptr = b->quant_shift; + qcoeff_ptr = d->qcoeff; + dqcoeff_ptr = d->dqcoeff; + dequant_ptr = d->dequant; + eob = - 1; + vpx_memset(qcoeff_ptr, 0, 64*sizeof(short)); + vpx_memset(dqcoeff_ptr, 0, 64*sizeof(short)); + for (i = 0; i < 64; i++) + { + int dq; + int round; + + /*TODO: These arrays should be stored in zig-zag order.*/ + rc = vp8_default_zig_zag1d_8x8[i]; + z = coeff_ptr[rc]; + //z = z * q1st; + //dq = dequant_ptr[rc!=0]/q1st; + dq = dequant_ptr[rc!=0]; + round = dq >> 1; + /* Sign of z. */ + sz = -(z < 0); + x = (z + sz) ^ sz; + x += round; + if (x >= dq) + { + /* Quantize x. */ + y = ((int)(((int)((x * quant_ptr[rc!=0])) >> 16) + x)) >> quant_shift_ptr[rc!=0]; + /* Put the sign back. */ + x = (y + sz) ^ sz; + /* Save the coefficient and its dequantized value. * */ + qcoeff_ptr[rc] = x; + dqcoeff_ptr[rc] = x * dq; + /* Remember the last non-zero coefficient. */ + if (y) + eob = i; + } + } + d->eob = eob + 1; +} + + + +void vp8_quantize_mby_8x8(MACROBLOCK *x) +{ + int i; + int has_2nd_order=(x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); + for(i = 0; i < 16; i ++) + { + x->e_mbd.block[i].eob = 0; + } + x->e_mbd.block[24].eob = 0; + for (i = 0; i < 16; i+=4) + x->quantize_b_8x8(&x->block[i], &x->e_mbd.block[i]); + + if (has_2nd_order) + x->quantize_b_2x2(&x->block[24], &x->e_mbd.block[24]); + +} + +void vp8_quantize_mb_8x8(MACROBLOCK *x) +{ + int i; + int has_2nd_order=(x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); + for(i = 0; i < 25; i ++) + { + x->e_mbd.block[i].eob = 0; + } + for (i = 0; i < 24; i+=4) + x->quantize_b_8x8(&x->block[i], &x->e_mbd.block[i]); + + if (has_2nd_order) + x->quantize_b_2x2(&x->block[24], &x->e_mbd.block[24]); +} + +void vp8_quantize_mbuv_8x8(MACROBLOCK *x) +{ + int i; + + for(i = 16; i < 24; i ++) + { + x->e_mbd.block[i].eob = 0; + } + for (i = 16; i < 24; i+=4) + x->quantize_b_8x8(&x->block[i], &x->e_mbd.block[i]); +} + + + /* quantize_b_pair function pointer in MACROBLOCK structure is set to one of * these two C functions if corresponding optimized routine is not available. * NEON optimized version implements currently the fast quantization for pair @@ -318,94 +669,6 @@ void vp8_fast_quantize_b_pair_c(BLOCK *b1, BLOCK *b2, BLOCKD *d1, BLOCKD *d2) } -static const int qrounding_factors[129] = -{ - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48 -}; - - -static const int qzbin_factors[129] = -{ - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80 -}; - - -static const int qrounding_factors_y2[129] = -{ - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48 -}; - - -static const int qzbin_factors_y2[129] = -{ - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80 -}; - - #define EXACT_QUANT #ifdef EXACT_QUANT static void invert_quant(int improved_quant, short *quant, @@ -435,18 +698,21 @@ void vp8cx_init_quantizer(VP8_COMP *cpi) int i; int quant_val; int Q; - - int zbin_boost[16] = {0, 0, 8, 10, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 44, 44}; + int zbin_boost[16] = { 0, 0, 8, 10, 12, 14, 16, 20, + 24, 28, 32, 36, 40, 44, 44, 44}; + int qrounding_factor = 48; for (Q = 0; Q < QINDEX_RANGE; Q++) { + int qzbin_factor = (vp8_dc_quant(Q,0) < 148) ? 84 : 80; + // dc values quant_val = vp8_dc_quant(Q, cpi->common.y1dc_delta_q); cpi->Y1quant_fast[Q][0] = (1 << 16) / quant_val; invert_quant(cpi->sf.improved_quant, cpi->Y1quant[Q] + 0, cpi->Y1quant_shift[Q] + 0, quant_val); - cpi->Y1zbin[Q][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; - cpi->Y1round[Q][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->Y1zbin[Q][0] = ((qzbin_factor * quant_val) + 64) >> 7; + cpi->Y1round[Q][0] = (qrounding_factor * quant_val) >> 7; cpi->common.Y1dequant[Q][0] = quant_val; cpi->zrun_zbin_boost_y1[Q][0] = (quant_val * zbin_boost[0]) >> 7; @@ -454,8 +720,8 @@ void vp8cx_init_quantizer(VP8_COMP *cpi) cpi->Y2quant_fast[Q][0] = (1 << 16) / quant_val; invert_quant(cpi->sf.improved_quant, cpi->Y2quant[Q] + 0, cpi->Y2quant_shift[Q] + 0, quant_val); - cpi->Y2zbin[Q][0] = ((qzbin_factors_y2[Q] * quant_val) + 64) >> 7; - cpi->Y2round[Q][0] = (qrounding_factors_y2[Q] * quant_val) >> 7; + cpi->Y2zbin[Q][0] = ((qzbin_factor * quant_val) + 64) >> 7; + cpi->Y2round[Q][0] = (qrounding_factor * quant_val) >> 7; cpi->common.Y2dequant[Q][0] = quant_val; cpi->zrun_zbin_boost_y2[Q][0] = (quant_val * zbin_boost[0]) >> 7; @@ -463,8 +729,8 @@ void vp8cx_init_quantizer(VP8_COMP *cpi) cpi->UVquant_fast[Q][0] = (1 << 16) / quant_val; invert_quant(cpi->sf.improved_quant, cpi->UVquant[Q] + 0, cpi->UVquant_shift[Q] + 0, quant_val); - cpi->UVzbin[Q][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7;; - cpi->UVround[Q][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->UVzbin[Q][0] = ((qzbin_factor * quant_val) + 64) >> 7;; + cpi->UVround[Q][0] = (qrounding_factor * quant_val) >> 7; cpi->common.UVdequant[Q][0] = quant_val; cpi->zrun_zbin_boost_uv[Q][0] = (quant_val * zbin_boost[0]) >> 7; @@ -477,8 +743,8 @@ void vp8cx_init_quantizer(VP8_COMP *cpi) cpi->Y1quant_fast[Q][rc] = (1 << 16) / quant_val; invert_quant(cpi->sf.improved_quant, cpi->Y1quant[Q] + rc, cpi->Y1quant_shift[Q] + rc, quant_val); - cpi->Y1zbin[Q][rc] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; - cpi->Y1round[Q][rc] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->Y1zbin[Q][rc] = ((qzbin_factor * quant_val) + 64) >> 7; + cpi->Y1round[Q][rc] = (qrounding_factor * quant_val) >> 7; cpi->common.Y1dequant[Q][rc] = quant_val; cpi->zrun_zbin_boost_y1[Q][i] = (quant_val * zbin_boost[i]) >> 7; @@ -486,8 +752,8 @@ void vp8cx_init_quantizer(VP8_COMP *cpi) cpi->Y2quant_fast[Q][rc] = (1 << 16) / quant_val; invert_quant(cpi->sf.improved_quant, cpi->Y2quant[Q] + rc, cpi->Y2quant_shift[Q] + rc, quant_val); - cpi->Y2zbin[Q][rc] = ((qzbin_factors_y2[Q] * quant_val) + 64) >> 7; - cpi->Y2round[Q][rc] = (qrounding_factors_y2[Q] * quant_val) >> 7; + cpi->Y2zbin[Q][rc] = ((qzbin_factor * quant_val) + 64) >> 7; + cpi->Y2round[Q][rc] = (qrounding_factor * quant_val) >> 7; cpi->common.Y2dequant[Q][rc] = quant_val; cpi->zrun_zbin_boost_y2[Q][i] = (quant_val * zbin_boost[i]) >> 7; @@ -495,69 +761,8 @@ void vp8cx_init_quantizer(VP8_COMP *cpi) cpi->UVquant_fast[Q][rc] = (1 << 16) / quant_val; invert_quant(cpi->sf.improved_quant, cpi->UVquant[Q] + rc, cpi->UVquant_shift[Q] + rc, quant_val); - cpi->UVzbin[Q][rc] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; - cpi->UVround[Q][rc] = (qrounding_factors[Q] * quant_val) >> 7; - cpi->common.UVdequant[Q][rc] = quant_val; - cpi->zrun_zbin_boost_uv[Q][i] = (quant_val * zbin_boost[i]) >> 7; - } - } -} -#else -void vp8cx_init_quantizer(VP8_COMP *cpi) -{ - int i; - int quant_val; - int Q; - - int zbin_boost[16] = {0, 0, 8, 10, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 44, 44}; - - for (Q = 0; Q < QINDEX_RANGE; Q++) - { - // dc values - quant_val = vp8_dc_quant(Q, cpi->common.y1dc_delta_q); - cpi->Y1quant[Q][0] = (1 << 16) / quant_val; - cpi->Y1zbin[Q][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; - cpi->Y1round[Q][0] = (qrounding_factors[Q] * quant_val) >> 7; - cpi->common.Y1dequant[Q][0] = quant_val; - cpi->zrun_zbin_boost_y1[Q][0] = (quant_val * zbin_boost[0]) >> 7; - - quant_val = vp8_dc2quant(Q, cpi->common.y2dc_delta_q); - cpi->Y2quant[Q][0] = (1 << 16) / quant_val; - cpi->Y2zbin[Q][0] = ((qzbin_factors_y2[Q] * quant_val) + 64) >> 7; - cpi->Y2round[Q][0] = (qrounding_factors_y2[Q] * quant_val) >> 7; - cpi->common.Y2dequant[Q][0] = quant_val; - cpi->zrun_zbin_boost_y2[Q][0] = (quant_val * zbin_boost[0]) >> 7; - - quant_val = vp8_dc_uv_quant(Q, cpi->common.uvdc_delta_q); - cpi->UVquant[Q][0] = (1 << 16) / quant_val; - cpi->UVzbin[Q][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7;; - cpi->UVround[Q][0] = (qrounding_factors[Q] * quant_val) >> 7; - cpi->common.UVdequant[Q][0] = quant_val; - cpi->zrun_zbin_boost_uv[Q][0] = (quant_val * zbin_boost[0]) >> 7; - - // all the ac values = ; - for (i = 1; i < 16; i++) - { - int rc = vp8_default_zig_zag1d[i]; - - quant_val = vp8_ac_yquant(Q); - cpi->Y1quant[Q][rc] = (1 << 16) / quant_val; - cpi->Y1zbin[Q][rc] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; - cpi->Y1round[Q][rc] = (qrounding_factors[Q] * quant_val) >> 7; - cpi->common.Y1dequant[Q][rc] = quant_val; - cpi->zrun_zbin_boost_y1[Q][i] = (quant_val * zbin_boost[i]) >> 7; - - quant_val = vp8_ac2quant(Q, cpi->common.y2ac_delta_q); - cpi->Y2quant[Q][rc] = (1 << 16) / quant_val; - cpi->Y2zbin[Q][rc] = ((qzbin_factors_y2[Q] * quant_val) + 64) >> 7; - cpi->Y2round[Q][rc] = (qrounding_factors_y2[Q] * quant_val) >> 7; - cpi->common.Y2dequant[Q][rc] = quant_val; - cpi->zrun_zbin_boost_y2[Q][i] = (quant_val * zbin_boost[i]) >> 7; - - quant_val = vp8_ac_uv_quant(Q, cpi->common.uvac_delta_q); - cpi->UVquant[Q][rc] = (1 << 16) / quant_val; - cpi->UVzbin[Q][rc] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; - cpi->UVround[Q][rc] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->UVzbin[Q][rc] = ((qzbin_factor * quant_val) + 64) >> 7; + cpi->UVround[Q][rc] = (qrounding_factor * quant_val) >> 7; cpi->common.UVdequant[Q][rc] = quant_val; cpi->zrun_zbin_boost_uv[Q][i] = (quant_val * zbin_boost[i]) >> 7; } @@ -572,19 +777,23 @@ void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x) int QIndex; MACROBLOCKD *xd = &x->e_mbd; int zbin_extra; + int segment_id = xd->mode_info_context->mbmi.segment_id; - // Select the baseline MB Q index. - if (xd->segmentation_enabled) + // Select the baseline MB Q index allowing for any segment level change. + if ( segfeature_active( xd, segment_id, SEG_LVL_ALT_Q ) ) { // Abs Value - if (xd->mb_segement_abs_delta == SEGMENT_ABSDATA) + if (xd->mb_segment_abs_delta == SEGMENT_ABSDATA) + QIndex = get_segdata( xd, segment_id, SEG_LVL_ALT_Q ); - QIndex = xd->segment_feature_data[MB_LVL_ALT_Q][xd->mode_info_context->mbmi.segment_id]; // Delta Value else { - QIndex = cpi->common.base_qindex + xd->segment_feature_data[MB_LVL_ALT_Q][xd->mode_info_context->mbmi.segment_id]; - QIndex = (QIndex >= 0) ? ((QIndex <= MAXQ) ? QIndex : MAXQ) : 0; // Clamp to valid range + QIndex = cpi->common.base_qindex + + get_segdata( xd, segment_id, SEG_LVL_ALT_Q ); + + // Clamp to valid range + QIndex = (QIndex >= 0) ? ((QIndex <= MAXQ) ? QIndex : MAXQ) : 0; } } else @@ -606,6 +815,20 @@ void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x) x->e_mbd.block[i].dequant = cpi->common.Y1dequant[QIndex]; x->block[i].zrun_zbin_boost = cpi->zrun_zbin_boost_y1[QIndex]; x->block[i].zbin_extra = (short)zbin_extra; + + // Segment max eob offset feature. + if ( segfeature_active( xd, segment_id, SEG_LVL_EOB ) ) + { + x->block[i].eob_max_offset = + get_segdata( xd, segment_id, SEG_LVL_EOB ); + x->block[i].eob_max_offset_8x8 = + get_segdata( xd, segment_id, SEG_LVL_EOB ); + } + else + { + x->block[i].eob_max_offset = 16; + x->block[i].eob_max_offset_8x8 = 64; + } } // UV @@ -624,6 +847,20 @@ void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x) x->e_mbd.block[i].dequant = cpi->common.UVdequant[QIndex]; x->block[i].zrun_zbin_boost = cpi->zrun_zbin_boost_uv[QIndex]; x->block[i].zbin_extra = (short)zbin_extra; + + // Segment max eob offset feature. + if ( segfeature_active( xd, segment_id, SEG_LVL_EOB ) ) + { + x->block[i].eob_max_offset = + get_segdata( xd, segment_id, SEG_LVL_EOB ); + x->block[i].eob_max_offset_8x8 = + get_segdata( xd, segment_id, SEG_LVL_EOB ); + } + else + { + x->block[i].eob_max_offset = 16; + x->block[i].eob_max_offset_8x8 = 64; + } } // Y2 @@ -641,6 +878,21 @@ void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x) x->block[24].zrun_zbin_boost = cpi->zrun_zbin_boost_y2[QIndex]; x->block[24].zbin_extra = (short)zbin_extra; + // TBD perhaps not use for Y2 + // Segment max eob offset feature. + if ( segfeature_active( xd, segment_id, SEG_LVL_EOB ) ) + { + x->block[24].eob_max_offset = + get_segdata( xd, segment_id, SEG_LVL_EOB ); + x->block[24].eob_max_offset_8x8 = + get_segdata( xd, segment_id, SEG_LVL_EOB ); + } + else + { + x->block[24].eob_max_offset = 16; + x->block[24].eob_max_offset_8x8 = 4; + } + /* save this macroblock QIndex for vp8_update_zbin_extra() */ x->q_index = QIndex; } @@ -696,39 +948,19 @@ void vp8cx_frame_init_quantizer(VP8_COMP *cpi) void vp8_set_quantizer(struct VP8_COMP *cpi, int Q) { VP8_COMMON *cm = &cpi->common; - MACROBLOCKD *mbd = &cpi->mb.e_mbd; - int update = 0; - int new_delta_q; + cm->base_qindex = Q; - /* if any of the delta_q values are changing update flag has to be set */ - /* currently only y2dc_delta_q may change */ - + // if any of the delta_q values are changing update flag will + // have to be set. cm->y1dc_delta_q = 0; cm->y2ac_delta_q = 0; cm->uvdc_delta_q = 0; cm->uvac_delta_q = 0; + cm->y2dc_delta_q = 0; - if (Q < 4) - { - new_delta_q = 4-Q; - } - else - new_delta_q = 0; - - update |= cm->y2dc_delta_q != new_delta_q; - cm->y2dc_delta_q = new_delta_q; - - - // Set Segment specific quatizers - mbd->segment_feature_data[MB_LVL_ALT_Q][0] = cpi->segment_feature_data[MB_LVL_ALT_Q][0]; - mbd->segment_feature_data[MB_LVL_ALT_Q][1] = cpi->segment_feature_data[MB_LVL_ALT_Q][1]; - mbd->segment_feature_data[MB_LVL_ALT_Q][2] = cpi->segment_feature_data[MB_LVL_ALT_Q][2]; - mbd->segment_feature_data[MB_LVL_ALT_Q][3] = cpi->segment_feature_data[MB_LVL_ALT_Q][3]; - - /* quantizer has to be reinitialized for any delta_q changes */ - if(update) - vp8cx_init_quantizer(cpi); - + // quantizer has to be reinitialized if any delta_q changes. + // As there are not any here for now this is inactive code. + //if(update) + // vp8cx_init_quantizer(cpi); } - diff --git a/vp8/encoder/quantize.h b/vp8/encoder/quantize.h index f1f0156d8..37221839e 100644 --- a/vp8/encoder/quantize.h +++ b/vp8/encoder/quantize.h @@ -46,6 +46,27 @@ extern prototype_quantize_block_pair(vp8_quantize_quantb_pair); #endif extern prototype_quantize_block(vp8_quantize_fastquantb); +#ifndef vp8_quantize_quantb_8x8 +#define vp8_quantize_quantb_8x8 vp8_regular_quantize_b_8x8 +#endif +extern prototype_quantize_block(vp8_quantize_quantb_8x8); + +#ifndef vp8_quantize_fastquantb_8x8 +#define vp8_quantize_fastquantb_8x8 vp8_fast_quantize_b_8x8_c +#endif +extern prototype_quantize_block(vp8_quantize_fastquantb_8x8); + +#ifndef vp8_quantize_quantb_2x2 +#define vp8_quantize_quantb_2x2 vp8_regular_quantize_b_2x2 +#endif +extern prototype_quantize_block(vp8_quantize_quantb_2x2); + +#ifndef vp8_quantize_fastquantb_2x2 +#define vp8_quantize_fastquantb_2x2 vp8_fast_quantize_b_2x2_c +#endif +extern prototype_quantize_block(vp8_quantize_fastquantb_2x2); + + #ifndef vp8_quantize_fastquantb_pair #define vp8_quantize_fastquantb_pair vp8_fast_quantize_b_pair_c #endif @@ -56,6 +77,10 @@ typedef struct prototype_quantize_block(*quantb); prototype_quantize_block_pair(*quantb_pair); prototype_quantize_block(*fastquantb); + prototype_quantize_block(*quantb_8x8); + prototype_quantize_block(*fastquantb_8x8); + prototype_quantize_block(*quantb_2x2); + prototype_quantize_block(*fastquantb_2x2); prototype_quantize_block_pair(*fastquantb_pair); } vp8_quantize_rtcd_vtable_t; @@ -81,6 +106,10 @@ extern prototype_quantize_mb(vp8_quantize_mby); #endif extern void vp8_strict_quantize_b(BLOCK *b,BLOCKD *d); +extern void vp8_strict_quantize_b_8x8(BLOCK *b,BLOCKD *d); +extern void vp8_strict_quantize_b_2x2(BLOCK *b,BLOCKD *d); +extern prototype_quantize_mb(vp8_quantize_mby_8x8); +extern prototype_quantize_mb(vp8_quantize_mbuv_8x8); struct VP8_COMP; extern void vp8_set_quantizer(struct VP8_COMP *cpi, int Q); diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c index a0a3db1c4..bf06f32e1 100644 --- a/vp8/encoder/ratectrl.c +++ b/vp8/encoder/ratectrl.c @@ -24,7 +24,7 @@ #include "encodemv.h" -#define MIN_BPB_FACTOR 0.01 +#define MIN_BPB_FACTOR 0.005 #define MAX_BPB_FACTOR 50 extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; @@ -33,192 +33,18 @@ extern const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES]; #ifdef MODE_STATS -extern int y_modes[5]; -extern int uv_modes[4]; -extern int b_modes[10]; +extern int y_modes[VP8_YMODES]; +extern int uv_modes[VP8_UV_MODES]; +extern int b_modes[B_MODE_COUNT]; -extern int inter_y_modes[10]; -extern int inter_uv_modes[4]; -extern int inter_b_modes[10]; +extern int inter_y_modes[MB_MODE_COUNT]; +extern int inter_uv_modes[VP8_UV_MODES]; +extern int inter_b_modes[B_MODE_COUNT]; #endif // Bits Per MB at different Q (Multiplied by 512) #define BPER_MB_NORMBITS 9 -// Work in progress recalibration of baseline rate tables based on -// the assumption that bits per mb is inversely proportional to the -// quantizer value. -#if !CONFIG_EXTEND_QRANGE -const int vp8_bits_per_mb[2][QINDEX_RANGE] = -{ - // Intra case 450000/Qintra - { - 1125000,900000, 750000, 642857, 562500, 500000, 450000, 450000, - 409090, 375000, 346153, 321428, 300000, 281250, 264705, 264705, - 250000, 236842, 225000, 225000, 214285, 214285, 204545, 204545, - 195652, 195652, 187500, 180000, 180000, 173076, 166666, 160714, - 155172, 150000, 145161, 140625, 136363, 132352, 128571, 125000, - 121621, 121621, 118421, 115384, 112500, 109756, 107142, 104651, - 102272, 100000, 97826, 97826, 95744, 93750, 91836, 90000, - 88235, 86538, 84905, 83333, 81818, 80357, 78947, 77586, - 76271, 75000, 73770, 72580, 71428, 70312, 69230, 68181, - 67164, 66176, 65217, 64285, 63380, 62500, 61643, 60810, - 60000, 59210, 59210, 58441, 57692, 56962, 56250, 55555, - 54878, 54216, 53571, 52941, 52325, 51724, 51136, 50561, - 49450, 48387, 47368, 46875, 45918, 45000, 44554, 44117, - 43269, 42452, 41666, 40909, 40178, 39473, 38793, 38135, - 36885, 36290, 35714, 35156, 34615, 34090, 33582, 33088, - 32608, 32142, 31468, 31034, 30405, 29801, 29220, 28662, - }, - // Inter case 285000/Qinter - { - 712500, 570000, 475000, 407142, 356250, 316666, 285000, 259090, - 237500, 219230, 203571, 190000, 178125, 167647, 158333, 150000, - 142500, 135714, 129545, 123913, 118750, 114000, 109615, 105555, - 101785, 98275, 95000, 91935, 89062, 86363, 83823, 81428, - 79166, 77027, 75000, 73076, 71250, 69512, 67857, 66279, - 64772, 63333, 61956, 60638, 59375, 58163, 57000, 55882, - 54807, 53773, 52777, 51818, 50892, 50000, 49137, 47500, - 45967, 44531, 43181, 41911, 40714, 39583, 38513, 37500, - 36538, 35625, 34756, 33928, 33139, 32386, 31666, 30978, - 30319, 29687, 29081, 28500, 27941, 27403, 26886, 26388, - 25909, 25446, 25000, 24568, 23949, 23360, 22800, 22265, - 21755, 21268, 20802, 20357, 19930, 19520, 19127, 18750, - 18387, 18037, 17701, 17378, 17065, 16764, 16473, 16101, - 15745, 15405, 15079, 14766, 14467, 14179, 13902, 13636, - 13380, 13133, 12895, 12666, 12445, 12179, 11924, 11632, - 11445, 11220, 11003, 10795, 10594, 10401, 10215, 10035, - } -}; -#else -const int vp8_bits_per_mb[2][QINDEX_RANGE] = -{ - // (Updated DEC 2010) Baseline estimate of Bits Per MB at each Q: - // 4500000/Qintra - { - 4500000,3600000,3000000,2571428,2250000,2000000,1800000,1636363, - 1500000,1384615,1285714,1200000,1125000,1058823,1000000, 947368, - 900000, 818181, 750000, 692307, 642857, 600000, 562500, 529411, - 500000, 473684, 450000, 428571, 409090, 391304, 375000, 352941, - 333333, 315789, 300000, 285714, 272727, 260869, 250000, 236842, - 225000, 214285, 204545, 195652, 187500, 180000, 171428, 163636, - 156521, 150000, 144000, 138461, 133333, 128571, 123287, 118421, - 113924, 109756, 105882, 102272, 98901, 95744, 92783, 90000, - 87378, 84905, 82568, 80357, 77586, 75000, 72580, 70312, - 68181, 66176, 64285, 62500, 60810, 59210, 57692, 56250, - 54545, 52941, 51428, 50000, 48648, 47368, 45918, 44554, - 43269, 42056, 40909, 39647, 38461, 37344, 36290, 35294, - 34351, 33333, 32374, 31468, 30612, 29801, 28938, 28125, - 27355, 26627, 25862, 25139, 24456, 23809, 23195, 22613, - 21951, 21327, 20737, 20179, 19650, 19067, 18518, 18000, - 17441, 16917, 16423, 15957, 15410, 14900, 14376, 13846, - }, - //2850000/Qinter - { - 2850000,2280000,1900000,1628571,1425000,1266666,1140000,1036363, - 950000, 876923, 814285, 760000, 712500, 670588, 633333, 600000, - 570000, 518181, 475000, 438461, 407142, 380000, 356250, 335294, - 316666, 300000, 285000, 271428, 259090, 247826, 237500, 223529, - 211111, 200000, 190000, 180952, 172727, 165217, 158333, 150000, - 142500, 135714, 129545, 123913, 118750, 114000, 108571, 103636, - 99130, 95000, 91200, 87692, 84444, 81428, 78082, 75000, - 72151, 69512, 67058, 64772, 62637, 60638, 58762, 57000, - 55339, 53773, 52293, 50892, 49137, 47500, 45967, 44531, - 43181, 41911, 40714, 39583, 38513, 37500, 36538, 35625, - 34545, 33529, 32571, 31666, 30810, 30000, 29081, 28217, - 27403, 26635, 25909, 25110, 24358, 23651, 22983, 22352, - 21755, 21111, 20503, 19930, 19387, 18874, 18327, 17812, - 17325, 16863, 16379, 15921, 15489, 15079, 14690, 14321, - 13902, 13507, 13133, 12780, 12445, 12076, 11728, 11400, - 11046, 10714, 10401, 10106, 9760, 9437, 9105, 8769, - } - }; - #endif - -static const int kf_boost_qadjustment[QINDEX_RANGE] = - { - 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, - 200, 200, 201, 201, 202, 203, 203, 203, - 204, 204, 205, 205, 206, 206, 207, 207, - 208, 208, 209, 209, 210, 210, 211, 211, - 212, 212, 213, 213, 214, 214, 215, 215, - 216, 216, 217, 217, 218, 218, 219, 219, - 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, -}; - -//#define GFQ_ADJUSTMENT (Q+100) -#define GFQ_ADJUSTMENT vp8_gf_boost_qadjustment[Q] -const int vp8_gf_boost_qadjustment[QINDEX_RANGE] = -{ - 80, 82, 84, 86, 88, 90, 92, 94, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, - 184, 184, 185, 185, 186, 186, 187, 187, - 188, 188, 189, 189, 190, 190, 191, 191, - 192, 192, 193, 193, 194, 194, 194, 194, - 195, 195, 196, 196, 197, 197, 198, 198 -}; - -/* -const int vp8_gf_boost_qadjustment[QINDEX_RANGE] = -{ - 100,101,102,103,104,105,105,106, - 106,107,107,108,109,109,110,111, - 112,113,114,115,116,117,118,119, - 120,121,122,123,124,125,126,127, - 128,129,130,131,132,133,134,135, - 136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151, - 152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167, - 168,169,170,170,171,171,172,172, - 173,173,173,174,174,174,175,175, - 175,176,176,176,177,177,177,177, - 178,178,179,179,180,180,181,181, - 182,182,183,183,184,184,185,185, - 186,186,187,187,188,188,189,189, - 190,190,191,191,192,192,193,193, -}; -*/ - -static const int kf_gf_boost_qlimits[QINDEX_RANGE] = -{ - 150, 155, 160, 165, 170, 175, 180, 185, - 190, 195, 200, 205, 210, 215, 220, 225, - 230, 235, 240, 245, 250, 255, 260, 265, - 270, 275, 280, 285, 290, 295, 300, 305, - 310, 320, 330, 340, 350, 360, 370, 380, - 390, 400, 410, 420, 430, 440, 450, 460, - 470, 480, 490, 500, 510, 520, 530, 540, - 550, 560, 570, 580, 590, 600, 600, 600, - 600, 600, 600, 600, 600, 600, 600, 600, - 600, 600, 600, 600, 600, 600, 600, 600, - 600, 600, 600, 600, 600, 600, 600, 600, - 600, 600, 600, 600, 600, 600, 600, 600, - 600, 600, 600, 600, 600, 600, 600, 600, - 600, 600, 600, 600, 600, 600, 600, 600, - 600, 600, 600, 600, 600, 600, 600, 600, - 600, 600, 600, 600, 600, 600, 600, 600, -}; - // % adjustment to target kf size based on seperation from previous frame static const int kf_boost_seperation_adjustment[16] = { @@ -226,7 +52,6 @@ static const int kf_boost_seperation_adjustment[16] = 80, 85, 90, 95, 100, 100, 100, 100, }; - static const int gf_adjust_table[101] = { 100, @@ -265,6 +90,47 @@ static const int gf_interval_table[101] = static const unsigned int prior_key_frame_weight[KEY_FRAME_CONTEXT] = { 1, 2, 3, 4, 5 }; +// These functions use formulaic calculations to make playing with the +// quantizer tables easier. If necessary they can be replaced by lookup +// tables if and when things settle down in the experimental bitstream +double vp8_convert_qindex_to_q( int qindex ) +{ + // Convert the index to a real Q value (scaled down to match old Q values) + return (double)vp8_ac_yquant( qindex, 0 ) / 4.0; +} + +int vp8_gfboost_qadjust( int qindex ) +{ + int retval; + double q; + + q = vp8_convert_qindex_to_q(qindex); + retval = (int)( ( 0.00000828 * q * q * q ) + + ( -0.0055 * q * q ) + + ( 1.32 * q ) + 79.3 ); + return retval; +} + +int kfboost_qadjust( int qindex ) +{ + int retval; + double q; + + q = vp8_convert_qindex_to_q(qindex); + retval = (int)( ( 0.00000973 * q * q * q ) + + ( -0.00613 * q * q ) + + ( 1.316 * q ) + 121.2 ); + return retval; +} + +int vp8_bits_per_mb( FRAME_TYPE frame_type, int qindex ) +{ + if ( frame_type == KEY_FRAME ) + return (int)(4500000 / vp8_convert_qindex_to_q(qindex)); + else + return (int)(2850000 / vp8_convert_qindex_to_q(qindex)); +} + void vp8_save_coding_context(VP8_COMP *cpi) { @@ -282,6 +148,10 @@ void vp8_save_coding_context(VP8_COMP *cpi) vp8_copy(cc->mvc, cpi->common.fc.mvc); vp8_copy(cc->mvcosts, cpi->mb.mvcosts); +#if CONFIG_HIGH_PRECISION_MV + vp8_copy(cc->mvc_hp, cpi->common.fc.mvc_hp); + vp8_copy(cc->mvcosts_hp, cpi->mb.mvcosts_hp); +#endif vp8_copy(cc->kf_ymode_prob, cpi->common.kf_ymode_prob); vp8_copy(cc->ymode_prob, cpi->common.fc.ymode_prob); @@ -321,7 +191,11 @@ void vp8_restore_coding_context(VP8_COMP *cpi) vp8_copy(cpi->common.fc.mvc, cc->mvc); vp8_copy(cpi->mb.mvcosts, cc->mvcosts); +#if CONFIG_HIGH_PRECISION_MV + vp8_copy(cpi->common.fc.mvc_hp, cc->mvc_hp); + vp8_copy(cpi->mb.mvcosts_hp, cc->mvcosts_hp); +#endif vp8_copy(cpi->common.kf_ymode_prob, cc->kf_ymode_prob); vp8_copy(cpi->common.fc.ymode_prob, cc->ymode_prob); vp8_copy(cpi->common.kf_uv_mode_prob, cc->kf_uv_mode_prob); @@ -357,28 +231,73 @@ void vp8_setup_key_frame(VP8_COMP *cpi) int flag[2] = {1, 1}; vp8_build_component_cost_table(cpi->mb.mvcost, (const MV_CONTEXT *) cpi->common.fc.mvc, flag); } - vpx_memset(cpi->common.fc.pre_mvc, 0, sizeof(cpi->common.fc.pre_mvc)); //initialize pre_mvc to all zero. +#if CONFIG_HIGH_PRECISION_MV + vpx_memcpy(cpi->common.fc.mvc_hp, vp8_default_mv_context_hp, sizeof(vp8_default_mv_context_hp)); + { + int flag[2] = {1, 1}; + vp8_build_component_cost_table_hp(cpi->mb.mvcost_hp, (const MV_CONTEXT_HP *) cpi->common.fc.mvc_hp, flag); + } + vpx_memset(cpi->common.fc.pre_mvc_hp, 0, sizeof(cpi->common.fc.pre_mvc_hp)); //initialize pre_mvc to all zero. +#endif + + + cpi->common.txfm_mode = ONLY_4X4; //cpi->common.filter_level = 0; // Reset every key frame. cpi->common.filter_level = cpi->common.base_qindex * 3 / 8 ; - // Provisional interval before next GF - if (cpi->auto_gold) - //cpi->frames_till_gf_update_due = DEFAULT_GF_INTERVAL; - cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; - else - cpi->frames_till_gf_update_due = cpi->goldfreq; + // interval before next GF + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; cpi->common.refresh_golden_frame = TRUE; cpi->common.refresh_alt_ref_frame = TRUE; + + vpx_memcpy(&cpi->common.lfc, &cpi->common.fc, sizeof(cpi->common.fc)); + vpx_memcpy(&cpi->common.lfc_a, &cpi->common.fc, sizeof(cpi->common.fc)); + + vp8_init_mode_contexts(&cpi->common); + vpx_memcpy( cpi->common.vp8_mode_contexts, + cpi->common.mode_context, + sizeof(cpi->common.mode_context)); + vpx_memcpy( cpi->common.vp8_mode_contexts, + default_vp8_mode_contexts, + sizeof(default_vp8_mode_contexts)); +} +void vp8_setup_inter_frame(VP8_COMP *cpi) +{ + + if(cpi->common.Width * cpi->common.Height > 640*360) + //||cpi->this_frame_target < 7 * cpi->common.MBs) + cpi->common.txfm_mode = ALLOW_8X8; + else + cpi->common.txfm_mode = ONLY_4X4; + + if(cpi->common.refresh_alt_ref_frame) + { + vpx_memcpy( &cpi->common.fc, + &cpi->common.lfc_a, + sizeof(cpi->common.fc)); + vpx_memcpy( cpi->common.vp8_mode_contexts, + cpi->common.mode_context_a, + sizeof(cpi->common.vp8_mode_contexts)); + } + else + { + vpx_memcpy( &cpi->common.fc, + &cpi->common.lfc, + sizeof(cpi->common.fc)); + vpx_memcpy( cpi->common.vp8_mode_contexts, + cpi->common.mode_context, + sizeof(cpi->common.vp8_mode_contexts)); + } } static int estimate_bits_at_q(int frame_kind, int Q, int MBs, double correction_factor) { - int Bpm = (int)(.5 + correction_factor * vp8_bits_per_mb[frame_kind][Q]); + int Bpm = (int)(.5 + correction_factor * vp8_bits_per_mb(frame_kind, Q)); /* Attempt to retain reasonable accuracy without overflow. The cutoff is * chosen such that the maximum product of Bpm and MBs fits 31 bits. The @@ -400,53 +319,8 @@ static void calc_iframe_target_size(VP8_COMP *cpi) // Clear down mmx registers to allow floating point in what follows vp8_clear_system_state(); //__asm emms; - if (cpi->oxcf.fixed_q >= 0) - { - int Q = cpi->oxcf.key_q; - - target = estimate_bits_at_q(INTRA_FRAME, Q, cpi->common.MBs, - cpi->key_frame_rate_correction_factor); - } - else if (cpi->pass == 2) - { - // New Two pass RC - target = cpi->per_frame_bandwidth; - } - // First Frame is a special case - else if (cpi->common.current_video_frame == 0) - { - /* 1 Pass there is no information on which to base size so use - * bandwidth per second * fraction of the initial buffer - * level - */ - target = cpi->oxcf.starting_buffer_level / 2; - - if(target > cpi->oxcf.target_bandwidth * 3 / 2) - target = cpi->oxcf.target_bandwidth * 3 / 2; - } - else - { - // if this keyframe was forced, use a more recent Q estimate - int Q = (cpi->common.frame_flags & FRAMEFLAGS_KEY) - ? cpi->avg_frame_qindex : cpi->ni_av_qi; - - // Boost depends somewhat on frame rate - kf_boost = (int)(2 * cpi->output_frame_rate - 16); - - // adjustment up based on q - kf_boost = kf_boost * kf_boost_qadjustment[Q] / 100; - - // frame separation adjustment ( down) - if (cpi->frames_since_key < cpi->output_frame_rate / 2) - kf_boost = (int)(kf_boost - * cpi->frames_since_key / (cpi->output_frame_rate / 2)); - - if (kf_boost < 16) - kf_boost = 16; - - target = ((16 + kf_boost) * cpi->per_frame_bandwidth) >> 4; - } - + // New Two pass RC + target = cpi->per_frame_bandwidth; if (cpi->oxcf.rc_max_intra_bitrate_pct) { @@ -459,192 +333,18 @@ static void calc_iframe_target_size(VP8_COMP *cpi) cpi->this_frame_target = target; - // TODO: if we separate rate targeting from Q targetting, move this. - // Reset the active worst quality to the baseline value for key frames. - if (cpi->pass != 2) - cpi->active_worst_quality = cpi->worst_quality; - -#if 0 - { - FILE *f; - - f = fopen("kf_boost.stt", "a"); - //fprintf(f, " %8d %10d %10d %10d %10d %10d %10d\n", - // cpi->common.current_video_frame, cpi->target_bandwidth, cpi->frames_to_key, kf_boost_qadjustment[cpi->ni_av_qi], cpi->kf_boost, (cpi->this_frame_target *100 / cpi->per_frame_bandwidth), cpi->this_frame_target ); - - fprintf(f, " %8u %10d %10d %10d\n", - cpi->common.current_video_frame, cpi->gfu_boost, cpi->baseline_gf_interval, cpi->source_alt_ref_pending); - - fclose(f); - } -#endif } -// Do the best we can to define the parameteres for the next GF based on what information we have available. +// Do the best we can to define the parameteres for the next GF based +// on what information we have available. +// +// In this experimental code only two pass is supported +// so we just use the interval determined in the two pass code. static void calc_gf_params(VP8_COMP *cpi) { - int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; - int Boost = 0; - - int gf_frame_useage = 0; // Golden frame useage since last GF - int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] + - cpi->recent_ref_frame_usage[LAST_FRAME] + - cpi->recent_ref_frame_usage[GOLDEN_FRAME] + - cpi->recent_ref_frame_usage[ALTREF_FRAME]; - - int pct_gf_active = (100 * cpi->gf_active_count) / (cpi->common.mb_rows * cpi->common.mb_cols); - - // Reset the last boost indicator - //cpi->last_boost = 100; - - if (tot_mbs) - gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] + cpi->recent_ref_frame_usage[ALTREF_FRAME]) * 100 / tot_mbs; - - if (pct_gf_active > gf_frame_useage) - gf_frame_useage = pct_gf_active; - - // Not two pass - if (cpi->pass != 2) - { - // Single Pass lagged mode: TBD - if (FALSE) - { - } - - // Single Pass compression: Has to use current and historical data - else - { -#if 0 - // Experimental code - int index = cpi->one_pass_frame_index; - int frames_to_scan = (cpi->max_gf_interval <= MAX_LAG_BUFFERS) ? cpi->max_gf_interval : MAX_LAG_BUFFERS; - - /* - // *************** Experimental code - incomplete - double decay_val = 1.0; - double IIAccumulator = 0.0; - double last_iiaccumulator = 0.0; - double IIRatio; - - cpi->one_pass_frame_index = cpi->common.current_video_frame%MAX_LAG_BUFFERS; - - for ( i = 0; i < (frames_to_scan - 1); i++ ) - { - if ( index < 0 ) - index = MAX_LAG_BUFFERS; - index --; - - if ( cpi->one_pass_frame_stats[index].frame_coded_error > 0.0 ) - { - IIRatio = cpi->one_pass_frame_stats[index].frame_intra_error / cpi->one_pass_frame_stats[index].frame_coded_error; - - if ( IIRatio > 30.0 ) - IIRatio = 30.0; - } - else - IIRatio = 30.0; - - IIAccumulator += IIRatio * decay_val; - - decay_val = decay_val * cpi->one_pass_frame_stats[index].frame_pcnt_inter; - - if ( (i > MIN_GF_INTERVAL) && - ((IIAccumulator - last_iiaccumulator) < 2.0) ) - { - break; - } - last_iiaccumulator = IIAccumulator; - } - - Boost = IIAccumulator*100.0/16.0; - cpi->baseline_gf_interval = i; - - */ -#else - - /*************************************************************/ - // OLD code - - // Adjust boost based upon ambient Q - Boost = GFQ_ADJUSTMENT; - - // Adjust based upon most recently measure intra useage - Boost = Boost * gf_intra_usage_adjustment[(cpi->this_frame_percent_intra < 15) ? cpi->this_frame_percent_intra : 14] / 100; - - // Adjust gf boost based upon GF usage since last GF - Boost = Boost * gf_adjust_table[gf_frame_useage] / 100; -#endif - } - - // golden frame boost without recode loop often goes awry. be safe by keeping numbers down. - if (!cpi->sf.recode_loop) - { - if (cpi->compressor_speed == 2) - Boost = Boost / 2; - } - - // Apply an upper limit based on Q for 1 pass encodes - if (Boost > kf_gf_boost_qlimits[Q] && (cpi->pass == 0)) - Boost = kf_gf_boost_qlimits[Q]; - - // Apply lower limits to boost. - else if (Boost < 110) - Boost = 110; - - // Note the boost used - cpi->last_boost = Boost; - - } - - // Estimate next interval - // This is updated once the real frame size/boost is known. - if (cpi->oxcf.fixed_q == -1) - { - if (cpi->pass == 2) // 2 Pass - { - cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; - } - else // 1 Pass - { - cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; - - if (cpi->last_boost > 750) - cpi->frames_till_gf_update_due++; - - if (cpi->last_boost > 1000) - cpi->frames_till_gf_update_due++; - - if (cpi->last_boost > 1250) - cpi->frames_till_gf_update_due++; - - if (cpi->last_boost >= 1500) - cpi->frames_till_gf_update_due ++; - - if (gf_interval_table[gf_frame_useage] > cpi->frames_till_gf_update_due) - cpi->frames_till_gf_update_due = gf_interval_table[gf_frame_useage]; - - if (cpi->frames_till_gf_update_due > cpi->max_gf_interval) - cpi->frames_till_gf_update_due = cpi->max_gf_interval; - } - } - else - cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; - - // ARF on or off - if (cpi->pass != 2) - { - // For now Alt ref is not allowed except in 2 pass modes. - cpi->source_alt_ref_pending = FALSE; - - /*if ( cpi->oxcf.fixed_q == -1) - { - if ( cpi->oxcf.play_alternate && (cpi->last_boost > (100 + (AF_THRESH*cpi->frames_till_gf_update_due)) ) ) - cpi->source_alt_ref_pending = TRUE; - else - cpi->source_alt_ref_pending = FALSE; - }*/ - } + // Set the gf interval + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; } @@ -655,155 +355,24 @@ static void calc_pframe_target_size(VP8_COMP *cpi) min_frame_target = 0; - if (cpi->pass == 2) - { - min_frame_target = cpi->min_frame_bandwidth; + min_frame_target = cpi->min_frame_bandwidth; - if (min_frame_target < (cpi->av_per_frame_bandwidth >> 5)) - min_frame_target = cpi->av_per_frame_bandwidth >> 5; - } - else if (min_frame_target < cpi->per_frame_bandwidth / 4) - min_frame_target = cpi->per_frame_bandwidth / 4; + if (min_frame_target < (cpi->av_per_frame_bandwidth >> 5)) + min_frame_target = cpi->av_per_frame_bandwidth >> 5; // Special alt reference frame case if (cpi->common.refresh_alt_ref_frame) { - if (cpi->pass == 2) - { - cpi->per_frame_bandwidth = cpi->twopass.gf_bits; // Per frame bit target for the alt ref frame - cpi->this_frame_target = cpi->per_frame_bandwidth; - } - - /* One Pass ??? TBD */ - /*else - { - int frames_in_section; - int allocation_chunks; - int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; - int alt_boost; - int max_arf_rate; - - alt_boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); - alt_boost += (cpi->frames_till_gf_update_due * 50); - - // If alt ref is not currently active then we have a pottential double hit with GF and ARF so reduce the boost a bit. - // A similar thing is done on GFs that preceed a arf update. - if ( !cpi->source_alt_ref_active ) - alt_boost = alt_boost * 3 / 4; - - frames_in_section = cpi->frames_till_gf_update_due+1; // Standard frames + GF - allocation_chunks = (frames_in_section * 100) + alt_boost; - - // Normalize Altboost and allocations chunck down to prevent overflow - while ( alt_boost > 1000 ) - { - alt_boost /= 2; - allocation_chunks /= 2; - } - - else - { - int bits_in_section; - - if ( cpi->kf_overspend_bits > 0 ) - { - Adjustment = (cpi->kf_bitrate_adjustment <= cpi->kf_overspend_bits) ? cpi->kf_bitrate_adjustment : cpi->kf_overspend_bits; - - if ( Adjustment > (cpi->per_frame_bandwidth - min_frame_target) ) - Adjustment = (cpi->per_frame_bandwidth - min_frame_target); - - cpi->kf_overspend_bits -= Adjustment; - - // Calculate an inter frame bandwidth target for the next few frames designed to recover - // any extra bits spent on the key frame. - cpi->inter_frame_target = cpi->per_frame_bandwidth - Adjustment; - if ( cpi->inter_frame_target < min_frame_target ) - cpi->inter_frame_target = min_frame_target; - } - else - cpi->inter_frame_target = cpi->per_frame_bandwidth; - - bits_in_section = cpi->inter_frame_target * frames_in_section; - - // Avoid loss of precision but avoid overflow - if ( (bits_in_section>>7) > allocation_chunks ) - cpi->this_frame_target = alt_boost * (bits_in_section / allocation_chunks); - else - cpi->this_frame_target = (alt_boost * bits_in_section) / allocation_chunks; - } - } - */ + // Per frame bit target for the alt ref frame + cpi->per_frame_bandwidth = cpi->twopass.gf_bits; + cpi->this_frame_target = cpi->per_frame_bandwidth; } // Normal frames (gf,and inter) else { - // 2 pass - if (cpi->pass == 2) - { - cpi->this_frame_target = cpi->per_frame_bandwidth; - } - // 1 pass - else - { - // Make rate adjustment to recover bits spent in key frame - // Test to see if the key frame inter data rate correction should still be in force - if (cpi->kf_overspend_bits > 0) - { - Adjustment = (cpi->kf_bitrate_adjustment <= cpi->kf_overspend_bits) ? cpi->kf_bitrate_adjustment : cpi->kf_overspend_bits; - - if (Adjustment > (cpi->per_frame_bandwidth - min_frame_target)) - Adjustment = (cpi->per_frame_bandwidth - min_frame_target); - - cpi->kf_overspend_bits -= Adjustment; - - // Calculate an inter frame bandwidth target for the next few frames designed to recover - // any extra bits spent on the key frame. - cpi->this_frame_target = cpi->per_frame_bandwidth - Adjustment; - - if (cpi->this_frame_target < min_frame_target) - cpi->this_frame_target = min_frame_target; - } - else - cpi->this_frame_target = cpi->per_frame_bandwidth; - - // If appropriate make an adjustment to recover bits spent on a recent GF - if ((cpi->gf_overspend_bits > 0) && (cpi->this_frame_target > min_frame_target)) - { - int Adjustment = (cpi->non_gf_bitrate_adjustment <= cpi->gf_overspend_bits) ? cpi->non_gf_bitrate_adjustment : cpi->gf_overspend_bits; - - if (Adjustment > (cpi->this_frame_target - min_frame_target)) - Adjustment = (cpi->this_frame_target - min_frame_target); - - cpi->gf_overspend_bits -= Adjustment; - cpi->this_frame_target -= Adjustment; - } - - // Apply small + and - boosts for non gf frames - if ((cpi->last_boost > 150) && (cpi->frames_till_gf_update_due > 0) && - (cpi->current_gf_interval >= (MIN_GF_INTERVAL << 1))) - { - // % Adjustment limited to the range 1% to 10% - Adjustment = (cpi->last_boost - 100) >> 5; - - if (Adjustment < 1) - Adjustment = 1; - else if (Adjustment > 10) - Adjustment = 10; - - // Convert to bits - Adjustment = (cpi->this_frame_target * Adjustment) / 100; - - if (Adjustment > (cpi->this_frame_target - min_frame_target)) - Adjustment = (cpi->this_frame_target - min_frame_target); - - if (cpi->common.frames_since_golden == (cpi->current_gf_interval >> 1)) - cpi->this_frame_target += ((cpi->current_gf_interval - 1) * Adjustment); - else - cpi->this_frame_target -= Adjustment; - } - } + cpi->this_frame_target = cpi->per_frame_bandwidth; } // Sanity check that the total sum of adjustments is not above the maximum allowed @@ -818,346 +387,43 @@ static void calc_pframe_target_size(VP8_COMP *cpi) // Note the baseline target data rate for this inter frame. cpi->inter_frame_target = cpi->this_frame_target; - // One Pass specific code - if (cpi->pass == 0) - { - // Adapt target frame size with respect to any buffering constraints: - if (cpi->buffered_mode) - { - int one_percent_bits = 1 + cpi->oxcf.optimal_buffer_level / 100; - - if ((cpi->buffer_level < cpi->oxcf.optimal_buffer_level) || - (cpi->bits_off_target < cpi->oxcf.optimal_buffer_level)) - { - int percent_low = 0; - - // Decide whether or not we need to adjust the frame data rate target. - // - // If we are are below the optimal buffer fullness level and adherence - // to buffering contraints is important to the end useage then adjust - // the per frame target. - if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && - (cpi->buffer_level < cpi->oxcf.optimal_buffer_level)) - { - percent_low = - (cpi->oxcf.optimal_buffer_level - cpi->buffer_level) / - one_percent_bits; - } - // Are we overshooting the long term clip data rate... - else if (cpi->bits_off_target < 0) - { - // Adjust per frame data target downwards to compensate. - percent_low = (int)(100 * -cpi->bits_off_target / - (cpi->total_byte_count * 8)); - } - - if (percent_low > cpi->oxcf.under_shoot_pct) - percent_low = cpi->oxcf.under_shoot_pct; - else if (percent_low < 0) - percent_low = 0; - - // lower the target bandwidth for this frame. - cpi->this_frame_target -= (cpi->this_frame_target * percent_low) - / 200; - - // Are we using allowing control of active_worst_allowed_q - // according to buffer level. - if (cpi->auto_worst_q) - { - int critical_buffer_level; - - // For streaming applications the most important factor is - // cpi->buffer_level as this takes into account the - // specified short term buffering constraints. However, - // hitting the long term clip data rate target is also - // important. - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - { - // Take the smaller of cpi->buffer_level and - // cpi->bits_off_target - critical_buffer_level = - (cpi->buffer_level < cpi->bits_off_target) - ? cpi->buffer_level : cpi->bits_off_target; - } - // For local file playback short term buffering contraints - // are less of an issue - else - { - // Consider only how we are doing for the clip as a - // whole - critical_buffer_level = cpi->bits_off_target; - } - - // Set the active worst quality based upon the selected - // buffer fullness number. - if (critical_buffer_level < cpi->oxcf.optimal_buffer_level) - { - if ( critical_buffer_level > - (cpi->oxcf.optimal_buffer_level >> 2) ) - { - int64_t qadjustment_range = - cpi->worst_quality - cpi->ni_av_qi; - int64_t above_base = - (critical_buffer_level - - (cpi->oxcf.optimal_buffer_level >> 2)); - - // Step active worst quality down from - // cpi->ni_av_qi when (critical_buffer_level == - // cpi->optimal_buffer_level) to - // cpi->worst_quality when - // (critical_buffer_level == - // cpi->optimal_buffer_level >> 2) - cpi->active_worst_quality = - cpi->worst_quality - - ((qadjustment_range * above_base) / - (cpi->oxcf.optimal_buffer_level*3>>2)); - } - else - { - cpi->active_worst_quality = cpi->worst_quality; - } - } - else - { - cpi->active_worst_quality = cpi->ni_av_qi; - } - } - else - { - cpi->active_worst_quality = cpi->worst_quality; - } - } - else - { - int percent_high = 0; - - if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) - && (cpi->buffer_level > cpi->oxcf.optimal_buffer_level)) - { - percent_high = (cpi->buffer_level - - cpi->oxcf.optimal_buffer_level) - / one_percent_bits; - } - else if (cpi->bits_off_target > cpi->oxcf.optimal_buffer_level) - { - percent_high = (int)((100 * cpi->bits_off_target) - / (cpi->total_byte_count * 8)); - } - - if (percent_high > cpi->oxcf.over_shoot_pct) - percent_high = cpi->oxcf.over_shoot_pct; - else if (percent_high < 0) - percent_high = 0; - - cpi->this_frame_target += (cpi->this_frame_target * - percent_high) / 200; - - - // Are we allowing control of active_worst_allowed_q according to bufferl level. - if (cpi->auto_worst_q) - { - // When using the relaxed buffer model stick to the user specified value - cpi->active_worst_quality = cpi->ni_av_qi; - } - else - { - cpi->active_worst_quality = cpi->worst_quality; - } - } - - // Set active_best_quality to prevent quality rising too high - cpi->active_best_quality = cpi->best_quality; - - // Worst quality obviously must not be better than best quality - if (cpi->active_worst_quality <= cpi->active_best_quality) - cpi->active_worst_quality = cpi->active_best_quality + 1; - - } - // Unbuffered mode (eg. video conferencing) - else - { - // Set the active worst quality - cpi->active_worst_quality = cpi->worst_quality; - } - - // Special trap for constrained quality mode - // "active_worst_quality" may never drop below cq level - // for any frame type. - if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY && - cpi->active_worst_quality < cpi->cq_target_quality) - { - cpi->active_worst_quality = cpi->cq_target_quality; - } - } - - // Test to see if we have to drop a frame - // The auto-drop frame code is only used in buffered mode. - // In unbufferd mode (eg vide conferencing) the descision to - // code or drop a frame is made outside the codec in response to real - // world comms or buffer considerations. - if (cpi->drop_frames_allowed && cpi->buffered_mode && - (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && - ((cpi->common.frame_type != KEY_FRAME))) //|| !cpi->oxcf.allow_spatial_resampling) ) - { - // Check for a buffer underun-crisis in which case we have to drop a frame - if ((cpi->buffer_level < 0)) - { -#if 0 - FILE *f = fopen("dec.stt", "a"); - fprintf(f, "%10d %10d %10d %10d ***** BUFFER EMPTY\n", - (int) cpi->common.current_video_frame, - cpi->decimation_factor, cpi->common.horiz_scale, - (cpi->buffer_level * 100) / cpi->oxcf.optimal_buffer_level); - fclose(f); -#endif - //vpx_log("Decoder: Drop frame due to bandwidth: %d \n",cpi->buffer_level, cpi->av_per_frame_bandwidth); - - cpi->drop_frame = TRUE; - } - -#if 0 - // Check for other drop frame crtieria (Note 2 pass cbr uses decimation on whole KF sections) - else if ((cpi->buffer_level < cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100) && - (cpi->drop_count < cpi->max_drop_count) && (cpi->pass == 0)) - { - cpi->drop_frame = TRUE; - } - -#endif - - if (cpi->drop_frame) - { - // Update the buffer level variable. - cpi->bits_off_target += cpi->av_per_frame_bandwidth; - if (cpi->bits_off_target > cpi->oxcf.maximum_buffer_size) - cpi->bits_off_target = cpi->oxcf.maximum_buffer_size; - cpi->buffer_level = cpi->bits_off_target; - } - else - cpi->drop_count = 0; - } - // Adjust target frame size for Golden Frames: - if (cpi->oxcf.error_resilient_mode == 0 && - (cpi->frames_till_gf_update_due == 0) && !cpi->drop_frame) + if ( cpi->frames_till_gf_update_due == 0 ) { //int Boost = 0; int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; - int gf_frame_useage = 0; // Golden frame useage since last GF - int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] + - cpi->recent_ref_frame_usage[LAST_FRAME] + - cpi->recent_ref_frame_usage[GOLDEN_FRAME] + - cpi->recent_ref_frame_usage[ALTREF_FRAME]; + cpi->common.refresh_golden_frame = TRUE; - int pct_gf_active = (100 * cpi->gf_active_count) / (cpi->common.mb_rows * cpi->common.mb_cols); + calc_gf_params(cpi); - // Reset the last boost indicator - //cpi->last_boost = 100; - - if (tot_mbs) - gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] + cpi->recent_ref_frame_usage[ALTREF_FRAME]) * 100 / tot_mbs; - - if (pct_gf_active > gf_frame_useage) - gf_frame_useage = pct_gf_active; - - // Is a fixed manual GF frequency being used - if (cpi->auto_gold) + // If we are using alternate ref instead of gf then do not apply the boost + // It will instead be applied to the altref update + // Jims modified boost + if (!cpi->source_alt_ref_active) { - // For one pass throw a GF if recent frame intra useage is low or the GF useage is high - if ((cpi->pass == 0) && (cpi->this_frame_percent_intra < 15 || gf_frame_useage >= 5)) - cpi->common.refresh_golden_frame = TRUE; - - // Two pass GF descision - else if (cpi->pass == 2) - cpi->common.refresh_golden_frame = TRUE; - } - -#if 0 - - // Debug stats - if (0) - { - FILE *f; - - f = fopen("gf_useaget.stt", "a"); - fprintf(f, " %8ld %10ld %10ld %10ld %10ld\n", - cpi->common.current_video_frame, cpi->gfu_boost, GFQ_ADJUSTMENT, cpi->gfu_boost, gf_frame_useage); - fclose(f); - } - -#endif - - if (cpi->common.refresh_golden_frame == TRUE) - { -#if 0 - - if (0) // p_gw + if (cpi->oxcf.fixed_q < 0) { - FILE *f; - - f = fopen("GFexit.stt", "a"); - fprintf(f, "%8ld GF coded\n", cpi->common.current_video_frame); - fclose(f); + // The spend on the GF is defined in the two pass code + // for two pass encodes + cpi->this_frame_target = cpi->per_frame_bandwidth; } - -#endif - - if (cpi->auto_adjust_gold_quantizer) - { - calc_gf_params(cpi); - } - - // If we are using alternate ref instead of gf then do not apply the boost - // It will instead be applied to the altref update - // Jims modified boost - if (!cpi->source_alt_ref_active) - { - if (cpi->oxcf.fixed_q < 0) - { - if (cpi->pass == 2) - { - cpi->this_frame_target = cpi->per_frame_bandwidth; // The spend on the GF is defined in the two pass code for two pass encodes - } - else - { - int Boost = cpi->last_boost; - int frames_in_section = cpi->frames_till_gf_update_due + 1; - int allocation_chunks = (frames_in_section * 100) + (Boost - 100); - int bits_in_section = cpi->inter_frame_target * frames_in_section; - - // Normalize Altboost and allocations chunck down to prevent overflow - while (Boost > 1000) - { - Boost /= 2; - allocation_chunks /= 2; - } - - // Avoid loss of precision but avoid overflow - if ((bits_in_section >> 7) > allocation_chunks) - cpi->this_frame_target = Boost * (bits_in_section / allocation_chunks); - else - cpi->this_frame_target = (Boost * bits_in_section) / allocation_chunks; - } - } - else - cpi->this_frame_target = - (estimate_bits_at_q(1, Q, cpi->common.MBs, 1.0) - * cpi->last_boost) / 100; - - } - // If there is an active ARF at this location use the minimum - // bits on this frame even if it is a contructed arf. - // The active maximum quantizer insures that an appropriate - // number of bits will be spent if needed for contstructed ARFs. else - { - cpi->this_frame_target = 0; - } - - cpi->current_gf_interval = cpi->frames_till_gf_update_due; + cpi->this_frame_target = + (estimate_bits_at_q(1, Q, cpi->common.MBs, 1.0) + * cpi->last_boost) / 100; } + // If there is an active ARF at this location use the minimum + // bits on this frame even if it is a contructed arf. + // The active maximum quantizer insures that an appropriate + // number of bits will be spent if needed for contstructed ARFs. + else + { + cpi->this_frame_target = 0; + } + + cpi->current_gf_interval = cpi->frames_till_gf_update_due; } } @@ -1188,8 +454,10 @@ void vp8_update_rate_correction_factors(VP8_COMP *cpi, int damp_var) // Work out how big we would have expected the frame to be at this Q given the current correction factor. // Stay in double to avoid int overflow when values are large - //projected_size_based_on_q = ((int)(.5 + rate_correction_factor * vp8_bits_per_mb[cpi->common.frame_type][Q]) * cpi->common.MBs) >> BPER_MB_NORMBITS; - projected_size_based_on_q = (int)(((.5 + rate_correction_factor * vp8_bits_per_mb[cpi->common.frame_type][Q]) * cpi->common.MBs) / (1 << BPER_MB_NORMBITS)); + projected_size_based_on_q = + (int)(((.5 + rate_correction_factor * + vp8_bits_per_mb(cpi->common.frame_type, Q)) * + cpi->common.MBs) / (1 << BPER_MB_NORMBITS)); // Make some allowance for cpi->zbin_over_quant if (cpi->zbin_over_quant > 0) @@ -1270,126 +538,93 @@ int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame) { int Q = cpi->active_worst_quality; + int i; + int last_error = INT_MAX; + int target_bits_per_mb; + int bits_per_mb_at_this_q; + double correction_factor; + // Reset Zbin OQ value cpi->zbin_over_quant = 0; - if (cpi->oxcf.fixed_q >= 0) - { - Q = cpi->oxcf.fixed_q; - - if (cpi->common.frame_type == KEY_FRAME) - { - Q = cpi->oxcf.key_q; - } - else if (cpi->common.refresh_alt_ref_frame) - { - Q = cpi->oxcf.alt_q; - } - else if (cpi->common.refresh_golden_frame) - { - Q = cpi->oxcf.gold_q; - } - - } + // Select the appropriate correction factor based upon type of frame. + if (cpi->common.frame_type == KEY_FRAME) + correction_factor = cpi->key_frame_rate_correction_factor; else { - int i; - int last_error = INT_MAX; - int target_bits_per_mb; - int bits_per_mb_at_this_q; - double correction_factor; + if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) + correction_factor = cpi->gf_rate_correction_factor; + else + correction_factor = cpi->rate_correction_factor; + } + + // Calculate required scaling factor based on target frame size and size of frame produced using previous Q + if (target_bits_per_frame >= (INT_MAX >> BPER_MB_NORMBITS)) + target_bits_per_mb = (target_bits_per_frame / cpi->common.MBs) << BPER_MB_NORMBITS; // Case where we would overflow int + else + target_bits_per_mb = (target_bits_per_frame << BPER_MB_NORMBITS) / cpi->common.MBs; + + i = cpi->active_best_quality; + + do + { + bits_per_mb_at_this_q = + (int)(.5 + correction_factor * + vp8_bits_per_mb(cpi->common.frame_type, i )); + + if (bits_per_mb_at_this_q <= target_bits_per_mb) + { + if ((target_bits_per_mb - bits_per_mb_at_this_q) <= last_error) + Q = i; + else + Q = i - 1; + + break; + } + else + last_error = bits_per_mb_at_this_q - target_bits_per_mb; + } + while (++i <= cpi->active_worst_quality); + + + // If we are at MAXQ then enable Q over-run which seeks to claw back additional bits through things like + // the RD multiplier and zero bin size. + if (Q >= MAXQ) + { + int zbin_oqmax; + + double Factor = 0.99; + double factor_adjustment = 0.01 / 256.0; //(double)ZBIN_OQ_MAX; - // Select the appropriate correction factor based upon type of frame. if (cpi->common.frame_type == KEY_FRAME) - correction_factor = cpi->key_frame_rate_correction_factor; + zbin_oqmax = 0; //ZBIN_OQ_MAX/16 + else if (cpi->common.refresh_alt_ref_frame || (cpi->common.refresh_golden_frame && !cpi->source_alt_ref_active)) + zbin_oqmax = 16; else + zbin_oqmax = ZBIN_OQ_MAX; + + // Each incrment in the zbin is assumed to have a fixed effect on bitrate. This is not of course true. + // The effect will be highly clip dependent and may well have sudden steps. + // The idea here is to acheive higher effective quantizers than the normal maximum by expanding the zero + // bin and hence decreasing the number of low magnitude non zero coefficients. + while (cpi->zbin_over_quant < zbin_oqmax) { - if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) - correction_factor = cpi->gf_rate_correction_factor; - else - correction_factor = cpi->rate_correction_factor; - } + cpi->zbin_over_quant ++; - // Calculate required scaling factor based on target frame size and size of frame produced using previous Q - if (target_bits_per_frame >= (INT_MAX >> BPER_MB_NORMBITS)) - target_bits_per_mb = (target_bits_per_frame / cpi->common.MBs) << BPER_MB_NORMBITS; // Case where we would overflow int - else - target_bits_per_mb = (target_bits_per_frame << BPER_MB_NORMBITS) / cpi->common.MBs; + if (cpi->zbin_over_quant > zbin_oqmax) + cpi->zbin_over_quant = zbin_oqmax; - i = cpi->active_best_quality; + // Adjust bits_per_mb_at_this_q estimate + bits_per_mb_at_this_q = (int)(Factor * bits_per_mb_at_this_q); + Factor += factor_adjustment; - do - { - bits_per_mb_at_this_q = (int)(.5 + correction_factor * vp8_bits_per_mb[cpi->common.frame_type][i]); - - if (bits_per_mb_at_this_q <= target_bits_per_mb) - { - if ((target_bits_per_mb - bits_per_mb_at_this_q) <= last_error) - Q = i; - else - Q = i - 1; + if (Factor >= 0.999) + Factor = 0.999; + if (bits_per_mb_at_this_q <= target_bits_per_mb) // Break out if we get down to the target rate break; - } - else - last_error = bits_per_mb_at_this_q - target_bits_per_mb; } - while (++i <= cpi->active_worst_quality); - - // If we are at MAXQ then enable Q over-run which seeks to claw back additional bits through things like - // the RD multiplier and zero bin size. - if (Q >= MAXQ) - { - int zbin_oqmax; - - double Factor = 0.99; - double factor_adjustment = 0.01 / 256.0; //(double)ZBIN_OQ_MAX; - - if (cpi->common.frame_type == KEY_FRAME) - zbin_oqmax = 0; //ZBIN_OQ_MAX/16 - else if (cpi->common.refresh_alt_ref_frame || (cpi->common.refresh_golden_frame && !cpi->source_alt_ref_active)) - zbin_oqmax = 16; - else - zbin_oqmax = ZBIN_OQ_MAX; - - /*{ - double Factor = (double)target_bits_per_mb/(double)bits_per_mb_at_this_q; - double Oq; - - Factor = Factor/1.2683; - - Oq = pow( Factor, (1.0/-0.165) ); - - if ( Oq > zbin_oqmax ) - Oq = zbin_oqmax; - - cpi->zbin_over_quant = (int)Oq; - }*/ - - // Each incrment in the zbin is assumed to have a fixed effect on bitrate. This is not of course true. - // The effect will be highly clip dependent and may well have sudden steps. - // The idea here is to acheive higher effective quantizers than the normal maximum by expanding the zero - // bin and hence decreasing the number of low magnitude non zero coefficients. - while (cpi->zbin_over_quant < zbin_oqmax) - { - cpi->zbin_over_quant ++; - - if (cpi->zbin_over_quant > zbin_oqmax) - cpi->zbin_over_quant = zbin_oqmax; - - // Adjust bits_per_mb_at_this_q estimate - bits_per_mb_at_this_q = (int)(Factor * bits_per_mb_at_this_q); - Factor += factor_adjustment; - - if (Factor >= 0.999) - Factor = 0.999; - - if (bits_per_mb_at_this_q <= target_bits_per_mb) // Break out if we get down to the target rate - break; - } - - } } return Q; @@ -1454,28 +689,6 @@ void vp8_adjust_key_frame_context(VP8_COMP *cpi) // Clear down mmx registers to allow floating point in what follows vp8_clear_system_state(); - // Do we have any key frame overspend to recover? - // Two-pass overspend handled elsewhere. - if ((cpi->pass != 2) - && (cpi->projected_frame_size > cpi->per_frame_bandwidth)) - { - int overspend; - - /* Update the count of key frame overspend to be recovered in - * subsequent frames. A portion of the KF overspend is treated as gf - * overspend (and hence recovered more quickly) as the kf is also a - * gf. Otherwise the few frames following each kf tend to get more - * bits allocated than those following other gfs. - */ - overspend = (cpi->projected_frame_size - cpi->per_frame_bandwidth); - cpi->kf_overspend_bits += overspend * 7 / 8; - cpi->gf_overspend_bits += overspend * 1 / 8; - - /* Work out how much to try and recover per frame. */ - cpi->kf_bitrate_adjustment = cpi->kf_overspend_bits - / estimate_keyframe_frequency(cpi); - } - cpi->frames_since_key = 0; cpi->key_frame_count++; } @@ -1506,45 +719,27 @@ void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit, } else { - // For CBR take buffer fullness into account - if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + // Stron overshoot limit for constrained quality + if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) { - if (cpi->buffer_level >= ((cpi->oxcf.optimal_buffer_level + cpi->oxcf.maximum_buffer_size) >> 1)) - { - // Buffer is too full so relax overshoot and tighten undershoot - *frame_over_shoot_limit = cpi->this_frame_target * 12 / 8; - *frame_under_shoot_limit = cpi->this_frame_target * 6 / 8; - } - else if (cpi->buffer_level <= (cpi->oxcf.optimal_buffer_level >> 1)) - { - // Buffer is too low so relax undershoot and tighten overshoot - *frame_over_shoot_limit = cpi->this_frame_target * 10 / 8; - *frame_under_shoot_limit = cpi->this_frame_target * 4 / 8; - } - else - { - *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; - *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; - } + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 2 / 8; } - // VBR and CQ mode - // Note that tighter restrictions here can help quality but hurt encode speed else { - // Stron overshoot limit for constrained quality - if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) - { - *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; - *frame_under_shoot_limit = cpi->this_frame_target * 2 / 8; - } - else - { - *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; - *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; - } + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; } } } + + // For very small rate targets where the fractional adjustment + // (eg * 7/8) may be tiny make sure there is at least a minimum + // range. + *frame_over_shoot_limit += 200; + *frame_under_shoot_limit -= 200; + if ( *frame_under_shoot_limit < 0 ) + *frame_under_shoot_limit = 0; } } @@ -1557,16 +752,7 @@ int vp8_pick_frame_size(VP8_COMP *cpi) if (cm->frame_type == KEY_FRAME) calc_iframe_target_size(cpi); else - { calc_pframe_target_size(cpi); - // Check if we're dropping the frame: - if (cpi->drop_frame) - { - cpi->drop_frame = FALSE; - cpi->drop_count++; - return 0; - } - } return 1; } diff --git a/vp8/encoder/ratectrl.h b/vp8/encoder/ratectrl.h index d4f779677..85d36fd6b 100644 --- a/vp8/encoder/ratectrl.h +++ b/vp8/encoder/ratectrl.h @@ -13,6 +13,8 @@ #include "onyx_int.h" +#define FRAME_OVERHEAD_BITS 200 + extern void vp8_save_coding_context(VP8_COMP *cpi); extern void vp8_restore_coding_context(VP8_COMP *cpi); @@ -25,4 +27,8 @@ extern void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_ // return of 0 means drop frame extern int vp8_pick_frame_size(VP8_COMP *cpi); +extern double vp8_convert_qindex_to_q( int qindex ); +extern int vp8_gfboost_qadjust( int qindex ); +extern int vp8_bits_per_mb( FRAME_TYPE frame_type, int qindex ); + #endif diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c index 73beffb39..1f02f55d9 100644 --- a/vp8/encoder/rdopt.c +++ b/vp8/encoder/rdopt.c @@ -25,6 +25,7 @@ #include "vp8/common/reconintra.h" #include "vp8/common/reconintra4x4.h" #include "vp8/common/findnearmv.h" +#include "vp8/common/quant_common.h" #include "encodemb.h" #include "quantize.h" #include "vp8/common/idct.h" @@ -32,20 +33,29 @@ #include "variance.h" #include "mcomp.h" #include "rdopt.h" +#include "ratectrl.h" #include "vpx_mem/vpx_mem.h" #include "dct.h" #include "vp8/common/systemdependent.h" +#include "vp8/common/seg_common.h" +#include "vp8/common/pred_common.h" + #if CONFIG_RUNTIME_CPU_DETECT #define IF_RTCD(x) (x) #else #define IF_RTCD(x) NULL #endif - extern void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x); extern void vp8_update_zbin_extra(VP8_COMP *cpi, MACROBLOCK *x); +#if CONFIG_HIGH_PRECISION_MV +#define XMVCOST (x->e_mbd.allow_high_precision_mv?x->mvcost_hp:x->mvcost) +#else +#define XMVCOST (x->mvcost) +#endif + #define MAXF(a,b) (((a) > (b)) ? (a) : (b)) static const int auto_speed_thresh[17] = @@ -99,6 +109,24 @@ const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES] = SPLITMV, B_PRED, + I8X8_PRED, + + /* compound prediction modes */ + ZEROMV, + NEARESTMV, + NEARMV, + + ZEROMV, + NEARESTMV, + NEARMV, + + ZEROMV, + NEARESTMV, + NEARMV, + + NEWMV, + NEWMV, + NEWMV, }; const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES] = @@ -131,6 +159,48 @@ const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES] = ALTREF_FRAME, INTRA_FRAME, + INTRA_FRAME, + + /* compound prediction modes */ + LAST_FRAME, + LAST_FRAME, + LAST_FRAME, + + ALTREF_FRAME, + ALTREF_FRAME, + ALTREF_FRAME, + + GOLDEN_FRAME, + GOLDEN_FRAME, + GOLDEN_FRAME, + + LAST_FRAME, + ALTREF_FRAME, + GOLDEN_FRAME, +}; + +const MV_REFERENCE_FRAME vp8_second_ref_frame_order[MAX_MODES] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + + /* compound prediction modes */ + GOLDEN_FRAME, + GOLDEN_FRAME, + GOLDEN_FRAME, + + LAST_FRAME, + LAST_FRAME, + LAST_FRAME, + + ALTREF_FRAME, + ALTREF_FRAME, + ALTREF_FRAME, + + GOLDEN_FRAME, + LAST_FRAME, + ALTREF_FRAME, }; static void fill_token_costs( @@ -144,8 +214,14 @@ static void fill_token_costs( for (i = 0; i < BLOCK_TYPES; i++) for (j = 0; j < COEF_BANDS; j++) for (k = 0; k < PREV_COEF_CONTEXTS; k++) + { - vp8_cost_tokens((int *)(c [i][j][k]), p [i][j][k], vp8_coef_tree); + if(k == 0 && ((j > 0 && i > 0) || (j > 1 && i == 0))) + vp8_cost_tokens_skip((int *)(c [i][j][k]), p [i][j][k], vp8_coef_tree); + else + + vp8_cost_tokens((int *)(c [i][j][k]), p [i][j][k], vp8_coef_tree); + } } @@ -156,87 +232,33 @@ static int rd_iifactor [ 32 ] = { 4, 4, 3, 2, 1, 0, 0, 0, }; // 3* dc_qlookup[Q]*dc_qlookup[Q]; -#if !CONFIG_EXTEND_QRANGE -static int rdmult_lut[QINDEX_RANGE]= -{ - 48,75,108,147,192,243,300,300, - 363,432,507,588,675,768,867,867, - 972,1083,1200,1200,1323,1323,1452,1452, - 1587,1587,1728,1875,1875,2028,2187,2352, - 2523,2700,2883,3072,3267,3468,3675,3888, - 4107,4107,4332,4563,4800,5043,5292,5547, - 5808,6075,6348,6348,6627,6912,7203,7500, - 7803,8112,8427,8748,9075,9408,9747,10092, - 10443,10800,11163,11532,11907,12288,12675,13068, - 13467,13872,14283,14700,15123,15552,15987,16428, - 16875,17328,17328,17787,18252,18723,19200,19683, - 20172,20667,21168,21675,22188,22707,23232,23763, - 24843,25947,27075,27648,28812,30000,30603,31212, - 32448,33708,34992,36300,37632,38988,40368,41772, - 44652,46128,47628,49152,50700,52272,53868,55488, - 57132,58800,61347,63075,65712,68403,71148,73947, -}; -#else -static int rdmult_lut[QINDEX_RANGE]= -{ - 3,5,7,9,12,15,19,23, - 27,32,37,42,48,54,61,68, - 75,83,91,99,108,117,127,137, - 147,169,192,217,243,271,300,331, - 363,397,450,507,567,631,698,768, - 842,919,999,1083,1170,1261,1355,1452, - 1587,1728,1875,2028,2187,2352,2523,2700, - 2883,3072,3267,3468,3675,3888,4107,4332, - 4563,4800,5043,5292,5547,5808,6075,6348, - 6627,6912,7203,7500,7880,8269,8667,9075, - 9492,9919,10355,10800,11255,11719,12192,12675, - 13167,13669,14180,14700,15230,15769,16317,16875, - 18019,19200,20419,21675,22969,24300,25669,27075, - 28519,30000,31519,33075,34669,36300,37969,39675, - 41772,43923,46128,48387,50700,53067,55488,57963, - 61347,64827,69312,73947,78732,83667,89787,97200, -}; -#endif /* values are now correlated to quantizer */ -static int sad_per_bit16lut[QINDEX_RANGE] = +static int sad_per_bit16lut[QINDEX_RANGE]; +static int sad_per_bit4lut[QINDEX_RANGE]; + +void vp8_init_me_luts() { - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 10, 10, - 10, 10, 10, 10, 10, 10, 11, 11, - 11, 11, 11, 11, 12, 12, 12, 12, - 12, 12, 13, 13, 13, 13, 14, 14 -}; -static int sad_per_bit4lut[QINDEX_RANGE] = + int i; + + // Initialize the sad lut tables using a formulaic calculation for now + // This is to make it easier to resolve the impact of experimental changes + // to the quantizer tables. + for ( i = 0; i < QINDEX_RANGE; i++ ) + { + sad_per_bit16lut[i] = + (int)((0.0418*vp8_convert_qindex_to_q(i)) + 2.4107); + sad_per_bit4lut[i] = (int)((0.063*vp8_convert_qindex_to_q(i)) + 2.742); + } +} + +int compute_rd_mult( int qindex ) { - 2, 2, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 8, 8, 8, - 8, 8, 9, 9, 9, 9, 9, 9, - 10, 10, 10, 10, 10, 10, 10, 10, - 11, 11, 11, 11, 11, 11, 11, 11, - 12, 12, 12, 12, 12, 12, 12, 12, - 13, 13, 13, 13, 13, 13, 13, 14, - 14, 14, 14, 14, 15, 15, 15, 15, - 16, 16, 16, 16, 17, 17, 17, 18, - 18, 18, 19, 19, 19, 20, 20, 20, -}; + int q; + + q = vp8_dc_quant(qindex,0); + return (11 * q * q) >> 6; +} void vp8cx_initialize_me_consts(VP8_COMP *cpi, int QIndex) { @@ -245,15 +267,10 @@ void vp8cx_initialize_me_consts(VP8_COMP *cpi, int QIndex) } - - - void vp8_initialize_rd_consts(VP8_COMP *cpi, int QIndex) { int q; int i; - int *thresh; - int threshmult; vp8_clear_system_state(); //__asm emms; @@ -261,14 +278,14 @@ void vp8_initialize_rd_consts(VP8_COMP *cpi, int QIndex) // for key frames, golden frames and arf frames. // if (cpi->common.refresh_golden_frame || // cpi->common.refresh_alt_ref_frame) - QIndex=(QIndex<0)? 0 : ((QIndex>127)?127 : QIndex); - cpi->RDMULT = rdmult_lut[QIndex]; + QIndex=(QIndex<0)? 0 : ((QIndex>MAXQ)?MAXQ : QIndex); + + cpi->RDMULT = compute_rd_mult(QIndex); // Extend rate multiplier along side quantizer zbin increases if (cpi->zbin_over_quant > 0) { double oq_factor; - double modq; // Experimental code using the same basic equation as used for Q above // The units of cpi->zbin_over_quant are 1/128 of Q bin size @@ -285,31 +302,21 @@ void vp8_initialize_rd_consts(VP8_COMP *cpi, int QIndex) (cpi->RDMULT * rd_iifactor[cpi->twopass.next_iiratio]) >> 4; } -#if !CONFIG_EXTEND_QRANGE -#else if (cpi->RDMULT < 7) cpi->RDMULT = 7; -#endif + cpi->mb.errorperbit = (cpi->RDMULT / 110); cpi->mb.errorperbit += (cpi->mb.errorperbit==0); -#if CONFIG_EXTEND_QRANGE - if(cpi->mb.errorperbit<1) - cpi->mb.errorperbit=1; -#endif vp8_set_speed_features(cpi); - q = (int)pow(vp8_dc_quant(QIndex,0), 1.25); + q = (int)pow(vp8_dc_quant(QIndex,0)>>2, 1.25); + q = q << 2; + cpi->RDMULT = cpi->RDMULT << 4; if (q < 8) q = 8; - - -#if CONFIG_EXTEND_QRANGE - cpi->RDMULT *= 16; -#endif - if (cpi->RDMULT > 1000) { cpi->RDDIV = 1; @@ -353,6 +360,14 @@ void vp8_initialize_rd_consts(VP8_COMP *cpi, int QIndex) (const vp8_prob( *)[8][3][11]) cpi->common.fc.coef_probs ); + fill_token_costs( + cpi->mb.token_costs_8x8, + (const vp8_prob( *)[8][3][11]) cpi->common.fc.coef_probs_8x8 + ); +#if CONFIG_QIMODE + //rough estimate for costing + cpi->common.kf_ymode_probs_index = cpi->common.base_qindex>>4; +#endif vp8_init_mode_costs(cpi); } @@ -526,10 +541,17 @@ int VP8_UVSSE(MACROBLOCK *x, const vp8_variance_rtcd_vtable_t *rtcd) if ((mv_row | mv_col) & 7) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + VARIANCE_INVOKE(rtcd, subpixvar8x8)(uptr, pre_stride, + (mv_col & 7)<<1, (mv_row & 7)<<1, upred_ptr, uv_stride, &sse2); + VARIANCE_INVOKE(rtcd, subpixvar8x8)(vptr, pre_stride, + (mv_col & 7)<<1, (mv_row & 7)<<1, vpred_ptr, uv_stride, &sse1); +#else VARIANCE_INVOKE(rtcd, subpixvar8x8)(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, uv_stride, &sse2); VARIANCE_INVOKE(rtcd, subpixvar8x8)(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, uv_stride, &sse1); +#endif sse2 += sse1; } else @@ -640,18 +662,141 @@ static void macro_block_yrd( MACROBLOCK *mb, // Distortion d = ENCODEMB_INVOKE(rtcd, mberr)(mb, 1) << 2; -#if CONFIG_EXTEND_QRANGE d += ENCODEMB_INVOKE(rtcd, berr)(mb_y2->coeff, x_y2->dqcoeff)<<2; -#else - d += ENCODEMB_INVOKE(rtcd, berr)(mb_y2->coeff, x_y2->dqcoeff); -#endif *Distortion = (d >> 4); - // rate *Rate = vp8_rdcost_mby(mb); } + +static int cost_coeffs_2x2(MACROBLOCK *mb, + BLOCKD *b, int type, + ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + int c = !type; /* start at coef 0, unless Y with Y2 */ + int eob = b->eob; + int pt ; /* surrounding block/prev coef predictor */ + int cost = 0; + short *qcoeff_ptr = b->qcoeff; + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + assert(eob<=4); + +# define QC2X2( I) ( qcoeff_ptr [vp8_default_zig_zag1d[I]] ) + + for (; c < eob; c++) + { + int v = QC2X2(c); + int t = vp8_dct_value_tokens_ptr[v].Token; + cost += mb->token_costs_8x8[type] [vp8_coef_bands[c]] [pt] [t]; + cost += vp8_dct_value_cost_ptr[v]; + pt = vp8_prev_token_class[t]; + } + +# undef QC2X2 + if (c < 4) + cost += mb->token_costs_8x8 [type][vp8_coef_bands[c]] + [pt] [DCT_EOB_TOKEN]; + + pt = (c != !type); // is eob first coefficient; + *a = *l = pt; + return cost; +} + + +static int cost_coeffs_8x8(MACROBLOCK *mb, + BLOCKD *b, int type, + ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + int c = !type; /* start at coef 0, unless Y with Y2 */ + int eob = b->eob; + int pt ; /* surrounding block/prev coef predictor */ + int cost = 0; + short *qcoeff_ptr = b->qcoeff; + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + +# define QC8X8( I) ( qcoeff_ptr [vp8_default_zig_zag1d_8x8[I]] ) + + for (; c < eob; c++) + { + int v = QC8X8(c); + int t = vp8_dct_value_tokens_ptr[v].Token; + cost += mb->token_costs_8x8[type] [vp8_coef_bands_8x8[c]] [pt] [t]; + cost += vp8_dct_value_cost_ptr[v]; + pt = vp8_prev_token_class[t]; + } + +# undef QC8X8 + if (c < 64) + cost += mb->token_costs_8x8 [type][vp8_coef_bands_8x8[c]] + [pt] [DCT_EOB_TOKEN]; + + pt = (c != !type); // is eob first coefficient; + *a = *l = pt; + return cost; +} +static int vp8_rdcost_mby_8x8(MACROBLOCK *mb) +{ + int cost = 0; + int b; + MACROBLOCKD *x = &mb->e_mbd; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + vpx_memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + for (b = 0; b < 16; b+=4) + cost += cost_coeffs_8x8(mb, x->block + b, PLANE_TYPE_Y_NO_DC, + ta + vp8_block2above_8x8[b], tl + vp8_block2left_8x8[b]); + + cost += cost_coeffs_2x2(mb, x->block + 24, PLANE_TYPE_Y2, + ta + vp8_block2above[24], tl + vp8_block2left[24]); + return cost; +} + +static void macro_block_yrd_8x8( MACROBLOCK *mb, + int *Rate, + int *Distortion, + const VP8_ENCODER_RTCD *rtcd) +{ + MACROBLOCKD *const x = &mb->e_mbd; + BLOCK *const mb_y2 = mb->block + 24; + BLOCKD *const x_y2 = x->block + 24; + short *Y2DCPtr = mb_y2->src_diff; + int d; + + ENCODEMB_INVOKE(&rtcd->encodemb, submby) + ( mb->src_diff, *(mb->block[0].base_src), + mb->e_mbd.predictor, mb->block[0].src_stride ); + + vp8_transform_mby_8x8(mb); + vp8_quantize_mby_8x8(mb); + + /* remove 1st order dc to properly combine 1st/2nd order distortion */ + mb->coeff[0] = 0; + mb->coeff[64] = 0; + mb->coeff[128] = 0; + mb->coeff[192] = 0; + mb->e_mbd.dqcoeff[0] = 0; + mb->e_mbd.dqcoeff[64] = 0; + mb->e_mbd.dqcoeff[128] = 0; + mb->e_mbd.dqcoeff[192] = 0; + d = ENCODEMB_INVOKE(&rtcd->encodemb, mberr)(mb, 0) << 2; + + d += ENCODEMB_INVOKE(&rtcd->encodemb, berr)(mb_y2->coeff, x_y2->dqcoeff)<<2; + + *Distortion = (d >> 4); + // rate + *Rate = vp8_rdcost_mby_8x8(mb); +} + static void copy_predictor(unsigned char *dst, const unsigned char *predictor) { const unsigned int *p = (const unsigned int *)predictor; @@ -661,21 +806,51 @@ static void copy_predictor(unsigned char *dst, const unsigned char *predictor) d[8] = p[8]; d[12] = p[12]; } + +static void copy_predictor_8x8(unsigned char *dst, const unsigned char *predictor) +{ + const unsigned int *p = (const unsigned int *)predictor; + unsigned int *d = (unsigned int *)dst; + d[0] = p[0]; + d[1] = p[1]; + d[4] = p[4]; + d[5] = p[5]; + d[8] = p[8]; + d[9] = p[9]; + d[12] = p[12]; + d[13] = p[13]; + d[16] = p[16]; + d[17] = p[17]; + d[20] = p[20]; + d[21] = p[21]; + d[24] = p[24]; + d[25] = p[25]; + d[28] = p[28]; + d[29] = p[29]; +} + static int rd_pick_intra4x4block( VP8_COMP *cpi, MACROBLOCK *x, BLOCK *be, BLOCKD *b, B_PREDICTION_MODE *best_mode, +#if CONFIG_COMP_INTRA_PRED + B_PREDICTION_MODE *best_second_mode, +#endif unsigned int *bmode_costs, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, int *bestrate, int *bestratey, - int *bestdistortion) + int *bestdistortion, + int allow_comp) { B_PREDICTION_MODE mode; +#if CONFIG_COMP_INTRA_PRED + B_PREDICTION_MODE mode2; +#endif int best_rd = INT_MAX; int rate = 0; int distortion; @@ -692,13 +867,30 @@ static int rd_pick_intra4x4block( for (mode = B_DC_PRED; mode <= B_HU_PRED; mode++) { +#if CONFIG_COMP_INTRA_PRED + for (mode2 = (allow_comp ? 0 : (B_DC_PRED - 1)); mode2 != (allow_comp ? (mode + 1) : 0); mode2++) + { +#endif int this_rd; int ratey; rate = bmode_costs[mode]; +#if CONFIG_COMP_INTRA_PRED + if (mode2 == (B_PREDICTION_MODE) (B_DC_PRED - 1)) + { +#endif RECON_INVOKE(&cpi->rtcd.common->recon, intra4x4_predict) (b, mode, b->predictor); +#if CONFIG_COMP_INTRA_PRED + } + else + { + RECON_INVOKE(&cpi->rtcd.common->recon, comp_intra4x4_predict) + (b, mode, mode2, b->predictor); + rate += bmode_costs[mode2]; + } +#endif ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), subb)(be, b, 16); x->vp8_short_fdct4x4(be->src_diff, be->coeff, 32); x->quantize_b(be, b); @@ -719,13 +911,22 @@ static int rd_pick_intra4x4block( *bestdistortion = distortion; best_rd = this_rd; *best_mode = mode; +#if CONFIG_COMP_INTRA_PRED + *best_second_mode = mode2; +#endif *a = tempa; *l = templ; copy_predictor(best_predictor, b->predictor); vpx_memcpy(best_dqcoeff, b->dqcoeff, 32); +#if CONFIG_COMP_INTRA_PRED + } +#endif } } - b->bmi.as_mode = (B_PREDICTION_MODE)(*best_mode); + b->bmi.as_mode.first = (B_PREDICTION_MODE)(*best_mode); +#if CONFIG_COMP_INTRA_PRED + b->bmi.as_mode.second = (B_PREDICTION_MODE)(*best_second_mode); +#endif IDCT_INVOKE(IF_RTCD(&cpi->rtcd.common->idct), idct16)(best_dqcoeff, b->diff, 32); RECON_INVOKE(IF_RTCD(&cpi->rtcd.common->recon), recon)(best_predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); @@ -734,7 +935,8 @@ static int rd_pick_intra4x4block( } static int rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *Rate, - int *rate_y, int *Distortion, int best_rd) + int *rate_y, int *Distortion, int best_rd, + int allow_comp) { MACROBLOCKD *const xd = &mb->e_mbd; int i; @@ -762,6 +964,9 @@ static int rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *Rate, MODE_INFO *const mic = xd->mode_info_context; const int mis = xd->mode_info_stride; B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); +#if CONFIG_COMP_INTRA_PRED + B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_second_mode); +#endif int UNINITIALIZED_IS_SAFE(r), UNINITIALIZED_IS_SAFE(ry), UNINITIALIZED_IS_SAFE(d); if (mb->e_mbd.frame_type == KEY_FRAME) @@ -773,15 +978,21 @@ static int rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *Rate, } total_rd += rd_pick_intra4x4block( - cpi, mb, mb->block + i, xd->block + i, &best_mode, bmode_costs, - ta + vp8_block2above[i], - tl + vp8_block2left[i], &r, &ry, &d); + cpi, mb, mb->block + i, xd->block + i, &best_mode, +#if CONFIG_COMP_INTRA_PRED + &best_second_mode, +#endif + bmode_costs, ta + vp8_block2above[i], + tl + vp8_block2left[i], &r, &ry, &d, allow_comp); cost += r; distortion += d; tot_rate_y += ry; - mic->bmi[i].as_mode = best_mode; + mic->bmi[i].as_mode.first = best_mode; +#if CONFIG_COMP_INTRA_PRED + mic->bmi[i].as_mode.second = best_second_mode; +#endif if(total_rd >= (int64_t)best_rd) break; @@ -790,7 +1001,7 @@ static int rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *Rate, if(total_rd >= (int64_t)best_rd) return INT_MAX; - *Rate = cost; + *Rate = cost + vp8_cost_bit(128, allow_comp); *rate_y += tot_rate_y; *Distortion = distortion; @@ -806,6 +1017,10 @@ static int rd_pick_intra16x16mby_mode(VP8_COMP *cpi, { MB_PREDICTION_MODE mode; MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode_selected); +#if CONFIG_COMP_INTRA_PRED + MB_PREDICTION_MODE mode2; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode2_selected); +#endif int rate, ratey; int distortion; int best_rd = INT_MAX; @@ -815,11 +1030,27 @@ static int rd_pick_intra16x16mby_mode(VP8_COMP *cpi, for (mode = DC_PRED; mode <= TM_PRED; mode++) { x->e_mbd.mode_info_context->mbmi.mode = mode; - +#if CONFIG_COMP_INTRA_PRED + for (mode2 = DC_PRED - 1; mode2 != TM_PRED + 1; mode2++) + { + x->e_mbd.mode_info_context->mbmi.second_mode = mode2; + if (mode2 == (MB_PREDICTION_MODE) (DC_PRED - 1)) + { +#endif RECON_INVOKE(&cpi->common.rtcd.recon, build_intra_predictors_mby) (&x->e_mbd); +#if CONFIG_COMP_INTRA_PRED + } + else + { + continue; // i.e. disable for now + RECON_INVOKE(&cpi->common.rtcd.recon, build_comp_intra_predictors_mby)(&x->e_mbd); + } +#endif macro_block_yrd(x, &ratey, &distortion, IF_RTCD(&cpi->rtcd.encodemb)); + // FIXME add compoundmode cost + // FIXME add rate for mode2 rate = ratey + x->mbmode_cost[x->e_mbd.frame_type] [x->e_mbd.mode_info_context->mbmi.mode]; @@ -828,16 +1059,214 @@ static int rd_pick_intra16x16mby_mode(VP8_COMP *cpi, if (this_rd < best_rd) { mode_selected = mode; +#if CONFIG_COMP_INTRA_PRED + mode2_selected = mode2; +#endif best_rd = this_rd; *Rate = rate; *rate_y = ratey; *Distortion = distortion; } +#if CONFIG_COMP_INTRA_PRED + } +#endif } x->e_mbd.mode_info_context->mbmi.mode = mode_selected; +#if CONFIG_COMP_INTRA_PRED + x->e_mbd.mode_info_context->mbmi.second_mode = mode2_selected; +#endif return best_rd; } +static int rd_pick_intra8x8block( + VP8_COMP *cpi, + MACROBLOCK *x, + int ib, + B_PREDICTION_MODE *best_mode, +#if CONFIG_COMP_INTRA_PRED + B_PREDICTION_MODE *best_second_mode, +#endif + unsigned int *mode_costs, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + int *bestrate, + int *bestratey, + int *bestdistortion) +{ + MB_PREDICTION_MODE mode; +#if CONFIG_COMP_INTRA_PRED + MB_PREDICTION_MODE mode2; +#endif + MACROBLOCKD *xd = &x->e_mbd; + int best_rd = INT_MAX; + int rate = 0; + int distortion; + BLOCK *be=x->block + ib; + BLOCKD *b=x->e_mbd.block + ib; + ENTROPY_CONTEXT ta0, ta1, besta0, besta1; + ENTROPY_CONTEXT tl0, tl1, bestl0, bestl1; + + + /* + * The predictor buffer is a 2d buffer with a stride of 16. Create + * a temp buffer that meets the stride requirements, but we are only + * interested in the left 8x8 block + * */ + + DECLARE_ALIGNED_ARRAY(16, unsigned char, best_predictor, 16*8); + DECLARE_ALIGNED_ARRAY(16, short, best_dqcoeff, 16*4); + + for (mode = DC_PRED; mode <= TM_PRED; mode++) + { +#if CONFIG_COMP_INTRA_PRED + for (mode2 = DC_PRED - 1; mode2 != TM_PRED + 1; mode2++) + { +#endif + int this_rd; + int rate_t; + + // FIXME rate for compound mode and second intrapred mode + rate = mode_costs[mode]; + +#if CONFIG_COMP_INTRA_PRED + if (mode2 == (MB_PREDICTION_MODE) (DC_PRED - 1)) + { +#endif + RECON_INVOKE(&cpi->rtcd.common->recon, intra8x8_predict) + (b, mode, b->predictor); +#if CONFIG_COMP_INTRA_PRED + } + else + { + continue; // i.e. disable for now + RECON_INVOKE(&cpi->rtcd.common->recon, comp_intra8x8_predict) + (b, mode, mode2, b->predictor); + } +#endif + + vp8_subtract_4b_c(be, b, 16); + + x->vp8_short_fdct8x4(be->src_diff, be->coeff, 32); + x->vp8_short_fdct8x4(be->src_diff + 64, be->coeff + 64, 32); + + x->quantize_b_pair(x->block+ib, x->block+ib+1, + xd->block+ib, xd->block+ib+1); + x->quantize_b_pair(x->block+ib+4, x->block+ib+5, + xd->block+ib+4, xd->block+ib+5); + + distortion = ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), berr) + ((x->block+ib)->coeff,(xd->block+ib)->dqcoeff)>>2; + distortion += ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), berr) + ((x->block+ib+1)->coeff,(xd->block+ib+1)->dqcoeff)>>2; + distortion += ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), berr) + ((x->block+ib+4)->coeff,(xd->block+ib+4)->dqcoeff)>>2; + distortion += ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), berr) + ((x->block+ib+5)->coeff,(xd->block+ib+5)->dqcoeff)>>2; + + ta0 = *(a + vp8_block2above[ib]); + ta1 = *(a + vp8_block2above[ib+1]); + tl0 = *(l + vp8_block2above[ib]); + tl1 = *(l + vp8_block2above[ib+4]); + rate_t = cost_coeffs(x, xd->block+ib, PLANE_TYPE_Y_WITH_DC, + &ta0, &tl0); + rate_t += cost_coeffs(x, xd->block+ib+1, PLANE_TYPE_Y_WITH_DC, + &ta1, &tl0); + rate_t += cost_coeffs(x, xd->block+ib+4, PLANE_TYPE_Y_WITH_DC, + &ta0, &tl1); + rate_t += cost_coeffs(x, xd->block+ib+5, PLANE_TYPE_Y_WITH_DC, + &ta1, &tl1); + rate += rate_t; + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + if (this_rd < best_rd) + { + *bestrate = rate; + *bestratey = rate_t; + *bestdistortion = distortion; + besta0 = ta0; + besta1 = ta1; + bestl0 = tl0; + bestl1 = tl1; + best_rd = this_rd; + *best_mode = mode; +#if CONFIG_COMP_INTRA_PRED + *best_second_mode = mode2; +#endif + copy_predictor_8x8(best_predictor, b->predictor); + vpx_memcpy(best_dqcoeff, b->dqcoeff, 64); + vpx_memcpy(best_dqcoeff+32, b->dqcoeff+64, 64); +#if CONFIG_COMP_INTRA_PRED + } +#endif + } + } + b->bmi.as_mode.first = (*best_mode); +#if CONFIG_COMP_INTRA_PRED + b->bmi.as_mode.second = (*best_second_mode); +#endif + vp8_encode_intra8x8 (IF_RTCD(&cpi->rtcd), x, ib); + *(a + vp8_block2above[ib]) = besta0; + *(a + vp8_block2above[ib+1]) = besta1; + *(l + vp8_block2above[ib]) = bestl0; + *(l + vp8_block2above[ib+4]) = bestl1; + return best_rd; +} + +const int vp8_i8x8_block[4]={0, 2, 8, 10}; +int rd_pick_intra8x8mby_modes(VP8_COMP *cpi, + MACROBLOCK *mb, + int *Rate, + int *rate_y, + int *Distortion, + int best_rd) +{ + MACROBLOCKD *const xd = &mb->e_mbd; + int i,ib; + int cost = mb->mbmode_cost [xd->frame_type] [I8X8_PRED]; + int distortion = 0; + int tot_rate_y = 0; + long long total_rd = 0; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + unsigned int *i8x8mode_costs; + + vpx_memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + i8x8mode_costs = mb->i8x8_mode_costs; + + for (i = 0; i < 4; i++) + { + MODE_INFO *const mic = xd->mode_info_context; + B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); +#if CONFIG_COMP_INTRA_PRED + B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_second_mode); +#endif + int UNINITIALIZED_IS_SAFE(r), UNINITIALIZED_IS_SAFE(ry), UNINITIALIZED_IS_SAFE(d); + + ib = vp8_i8x8_block[i]; + total_rd += rd_pick_intra8x8block( + cpi, mb, ib, &best_mode, +#if CONFIG_COMP_INTRA_PRED + &best_second_mode, +#endif + i8x8mode_costs, ta, tl, &r, &ry, &d); + cost += r; + distortion += d; + tot_rate_y += ry; + mic->bmi[ib].as_mode.first = best_mode; +#if CONFIG_COMP_INTRA_PRED + mic->bmi[ib].as_mode.second = best_second_mode; +#endif + } + *Rate = cost; + *rate_y += tot_rate_y; + *Distortion = distortion; + return RDCOST(mb->rdmult, mb->rddiv, cost, distortion); +} static int rd_cost_mbuv(MACROBLOCK *mb) { @@ -865,7 +1294,6 @@ static int rd_cost_mbuv(MACROBLOCK *mb) static int rd_inter16x16_uv(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *distortion, int fullpixel) { - vp8_build_inter16x16_predictors_mbuv(&x->e_mbd); ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); @@ -878,6 +1306,47 @@ static int rd_inter16x16_uv(VP8_COMP *cpi, MACROBLOCK *x, int *rate, return RDCOST(x->rdmult, x->rddiv, *rate, *distortion); } +static int rd_cost_mbuv_8x8(MACROBLOCK *mb) +{ + int b; + int cost = 0; + MACROBLOCKD *x = &mb->e_mbd; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + vpx_memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + for (b = 16; b < 24; b+=4) + cost += cost_coeffs_8x8(mb, x->block + b, PLANE_TYPE_UV, + ta + vp8_block2above_8x8[b], + tl + vp8_block2left_8x8[b]); + + return cost; +} + + +static int rd_inter16x16_uv_8x8(VP8_COMP *cpi, MACROBLOCK *x, int *rate, + int *distortion, int fullpixel) +{ + ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), submbuv)(x->src_diff, + x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); + + vp8_transform_mbuv_8x8(x); + + vp8_quantize_mbuv_8x8(x); + + *rate = rd_cost_mbuv_8x8(x); + *distortion = ENCODEMB_INVOKE(&cpi->rtcd.encodemb, mbuverr)(x) / 4; + + return RDCOST(x->rdmult, x->rddiv, *rate, *distortion); +} + + static int rd_inter4x4_uv(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *distortion, int fullpixel) { @@ -894,23 +1363,50 @@ static int rd_inter4x4_uv(VP8_COMP *cpi, MACROBLOCK *x, int *rate, return RDCOST(x->rdmult, x->rddiv, *rate, *distortion); } -static void rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *rate_tokenonly, int *distortion) +static void rd_pick_intra_mbuv_mode(VP8_COMP *cpi, + MACROBLOCK *x, + int *rate, + int *rate_tokenonly, + int *distortion) { MB_PREDICTION_MODE mode; MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode_selected); +#if CONFIG_COMP_INTRA_PRED + MB_PREDICTION_MODE mode2; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode2_selected); +#endif int best_rd = INT_MAX; int UNINITIALIZED_IS_SAFE(d), UNINITIALIZED_IS_SAFE(r); int rate_to; for (mode = DC_PRED; mode <= TM_PRED; mode++) { +#if CONFIG_COMP_INTRA_PRED + for (mode2 = DC_PRED - 1; mode2 != TM_PRED + 1; mode2++) + { +#endif int rate; int distortion; int this_rd; x->e_mbd.mode_info_context->mbmi.uv_mode = mode; +#if CONFIG_COMP_INTRA_PRED + x->e_mbd.mode_info_context->mbmi.second_uv_mode = mode2; + if (mode2 == (MB_PREDICTION_MODE) (DC_PRED - 1)) + { +#endif RECON_INVOKE(&cpi->rtcd.common->recon, build_intra_predictors_mbuv) (&x->e_mbd); +#if CONFIG_COMP_INTRA_PRED + } + else + { + continue; + RECON_INVOKE(&cpi->rtcd.common->recon, build_comp_intra_predictors_mbuv) + (&x->e_mbd); + } +#endif + ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); @@ -931,6 +1427,10 @@ static void rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int r = rate; *rate_tokenonly = rate_to; mode_selected = mode; +#if CONFIG_COMP_INTRA_PRED + mode2_selected = mode2; + } +#endif } } @@ -938,13 +1438,67 @@ static void rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *distortion = d; x->e_mbd.mode_info_context->mbmi.uv_mode = mode_selected; +#if CONFIG_COMP_INTRA_PRED + x->e_mbd.mode_info_context->mbmi.second_uv_mode = mode2_selected; +#endif } -int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]) +static void rd_pick_intra_mbuv_mode_8x8(VP8_COMP *cpi, + MACROBLOCK *x, + int *rate, + int *rate_tokenonly, + int *distortion) +{ + MB_PREDICTION_MODE mode; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode_selected); + int best_rd = INT_MAX; + int UNINITIALIZED_IS_SAFE(d), UNINITIALIZED_IS_SAFE(r); + int rate_to; + + for (mode = DC_PRED; mode <= TM_PRED; mode++) + { + int rate; + int distortion; + int this_rd; + + x->e_mbd.mode_info_context->mbmi.uv_mode = mode; + RECON_INVOKE(&cpi->rtcd.common->recon, build_intra_predictors_mbuv) + (&x->e_mbd); + ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), submbuv)(x->src_diff, + x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, + x->src.uv_stride); + vp8_transform_mbuv_8x8(x); + + vp8_quantize_mbuv_8x8(x); + + rate_to = rd_cost_mbuv_8x8(x); + rate = rate_to + x->intra_uv_mode_cost[x->e_mbd.frame_type] + [x->e_mbd.mode_info_context->mbmi.uv_mode]; + + distortion = ENCODEMB_INVOKE(&cpi->rtcd.encodemb, mbuverr)(x) / 4; + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_rd) + { + best_rd = this_rd; + d = distortion; + r = rate; + *rate_tokenonly = rate_to; + mode_selected = mode; + } + } + *rate = r; + *distortion = d; + x->e_mbd.mode_info_context->mbmi.uv_mode = mode_selected; +} + +int vp8_cost_mv_ref(VP8_COMMON *pc, + MB_PREDICTION_MODE m, + const int near_mv_ref_ct[4]) { vp8_prob p [VP8_MVREFS-1]; assert(NEARESTMV <= m && m <= SPLITMV); - vp8_mv_ref_probs(p, near_mv_ref_ct); + vp8_mv_ref_probs(pc, p, near_mv_ref_ct); return vp8_cost_token(vp8_mv_ref_tree, p, vp8_mv_ref_encoding_array - NEARESTMV + m); } @@ -997,7 +1551,12 @@ static int labels2mode( switch (m = this_mode) { case NEW4X4 : +#if CONFIG_HIGH_PRECISION_MV + thismvcost = vp8_mv_bit_cost(this_mv, best_ref_mv, mvcost, + 102, xd->allow_high_precision_mv); +#else thismvcost = vp8_mv_bit_cost(this_mv, best_ref_mv, mvcost, 102); +#endif break; case LEFT4X4: this_mv->as_int = col ? d[-1].bmi.mv.as_int : left_block_mv(mic, i); @@ -1084,7 +1643,6 @@ static unsigned int vp8_encode_inter_mb_segment(MACROBLOCK *x, int const *labels } - static const unsigned int segmentation_to_sseshift[4] = {3, 3, 2, 0}; @@ -1161,7 +1719,7 @@ static void rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, // Segmentation method overheads rate = vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + segmentation); - rate += vp8_cost_mv_ref(SPLITMV, bsi->mdcounts); + rate += vp8_cost_mv_ref(&cpi->common, SPLITMV, bsi->mdcounts); this_segment_rd += RDCOST(x->rdmult, x->rddiv, rate, 0); br += rate; @@ -1245,7 +1803,8 @@ static void rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, bestsme = cpi->diamond_search_sad(x, c, e, &mvp_full, &mode_mv[NEW4X4], step_param, sadpb, &num00, v_fn_ptr, - x->mvcost, bsi->ref_mv); + XMVCOST, + bsi->ref_mv); n = num00; num00 = 0; @@ -1262,7 +1821,8 @@ static void rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, &mvp_full, &temp_mv, step_param + n, sadpb, &num00, v_fn_ptr, - x->mvcost, bsi->ref_mv); + XMVCOST, + bsi->ref_mv); if (thissme < bestsme) { @@ -1283,7 +1843,7 @@ static void rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, thissme = cpi->full_search_sad(x, c, e, &mvp_full, sadpb, 16, v_fn_ptr, - x->mvcost, bsi->ref_mv); + XMVCOST, bsi->ref_mv); if (thissme < bestsme) { @@ -1303,14 +1863,13 @@ static void rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, int distortion; unsigned int sse; cpi->find_fractional_mv_step(x, c, e, &mode_mv[NEW4X4], - bsi->ref_mv, x->errorperbit, v_fn_ptr, x->mvcost, + bsi->ref_mv, x->errorperbit, v_fn_ptr, XMVCOST, &distortion, &sse); - } } /* NEW4X4 */ rate = labels2mode(x, labels, i, this_mode, &mode_mv[this_mode], - bsi->ref_mv, x->mvcost); + bsi->ref_mv, XMVCOST); // Trap vectors that reach beyond the UMV borders if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) || @@ -1344,15 +1903,17 @@ static void rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, vpx_memcpy(tl, tl_b, sizeof(ENTROPY_CONTEXT_PLANES)); labels2mode(x, labels, i, mode_selected, &mode_mv[mode_selected], - bsi->ref_mv, x->mvcost); + bsi->ref_mv, XMVCOST); br += sbr; bd += sbd; segmentyrate += bestlabelyrate; this_segment_rd += best_label_rd; - if (this_segment_rd >= bsi->segment_rd) + if (this_segment_rd >= bsi->segment_rd) { break; + } + } /* for each label */ @@ -1427,6 +1988,7 @@ static int vp8_rd_pick_best_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x, rd_check_segment(cpi, x, &bsi, BLOCK_8X8); + if (bsi.segment_rd < best_rd) { int col_min = (best_ref_mv->as_mv.col>>3) - MAX_FULL_PEL_VAL + ((best_ref_mv->as_mv.col & 7)?1:0); @@ -1528,6 +2090,7 @@ static int vp8_rd_pick_best_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x, return bsi.segment_rd; } +/* Order arr in increasing order, original position stored in idx */ static void insertsortmv(int arr[], int len) { int i, j, k; @@ -1795,24 +2358,138 @@ static void rd_update_mvcount(VP8_COMP *cpi, MACROBLOCK *x, int_mv *best_ref_mv) { if (x->partition_info->bmi[i].mode == NEW4X4) { - cpi->MVcount[0][mv_max+((x->partition_info->bmi[i].mv.as_mv.row - - best_ref_mv->as_mv.row) >> 1)]++; - cpi->MVcount[1][mv_max+((x->partition_info->bmi[i].mv.as_mv.col - - best_ref_mv->as_mv.col) >> 1)]++; +#if CONFIG_HIGH_PRECISION_MV + if (x->e_mbd.allow_high_precision_mv) + { + cpi->MVcount_hp[0][mv_max_hp+(x->partition_info->bmi[i].mv.as_mv.row + - best_ref_mv->as_mv.row)]++; + cpi->MVcount_hp[1][mv_max_hp+(x->partition_info->bmi[i].mv.as_mv.col + - best_ref_mv->as_mv.col)]++; + } + else +#endif + { + cpi->MVcount[0][mv_max+((x->partition_info->bmi[i].mv.as_mv.row + - best_ref_mv->as_mv.row) >> 1)]++; + cpi->MVcount[1][mv_max+((x->partition_info->bmi[i].mv.as_mv.col + - best_ref_mv->as_mv.col) >> 1)]++; + } } } } else if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV) { - cpi->MVcount[0][mv_max+((x->e_mbd.mode_info_context->mbmi.mv.as_mv.row - - best_ref_mv->as_mv.row) >> 1)]++; - cpi->MVcount[1][mv_max+((x->e_mbd.mode_info_context->mbmi.mv.as_mv.col - - best_ref_mv->as_mv.col) >> 1)]++; +#if CONFIG_HIGH_PRECISION_MV + if (x->e_mbd.allow_high_precision_mv) + { + cpi->MVcount_hp[0][mv_max_hp+(x->e_mbd.mode_info_context->mbmi.mv.as_mv.row + - best_ref_mv->as_mv.row)]++; + cpi->MVcount_hp[1][mv_max_hp+(x->e_mbd.mode_info_context->mbmi.mv.as_mv.col + - best_ref_mv->as_mv.col)]++; + } + else +#endif + { + cpi->MVcount[0][mv_max+((x->e_mbd.mode_info_context->mbmi.mv.as_mv.row + - best_ref_mv->as_mv.row) >> 1)]++; + cpi->MVcount[1][mv_max+((x->e_mbd.mode_info_context->mbmi.mv.as_mv.col + - best_ref_mv->as_mv.col) >> 1)]++; + } } } -void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra) +static void set_i8x8_block_modes(MACROBLOCK *x, int modes[2][4]) { + int i; + MACROBLOCKD *xd = &x->e_mbd; + for(i=0;i<4;i++) + { + int ib = vp8_i8x8_block[i]; + x->e_mbd.mode_info_context->bmi[ib+0].as_mode.first= modes[0][i]; + x->e_mbd.mode_info_context->bmi[ib+1].as_mode.first= modes[0][i]; + x->e_mbd.mode_info_context->bmi[ib+4].as_mode.first= modes[0][i]; + x->e_mbd.mode_info_context->bmi[ib+5].as_mode.first= modes[0][i]; +#if CONFIG_COMP_INTRA_PRED + x->e_mbd.mode_info_context->bmi[ib+0].as_mode.second= modes[1][i]; + x->e_mbd.mode_info_context->bmi[ib+1].as_mode.second= modes[1][i]; + x->e_mbd.mode_info_context->bmi[ib+4].as_mode.second= modes[1][i]; + x->e_mbd.mode_info_context->bmi[ib+5].as_mode.second= modes[1][i]; +#endif + //printf("%d,%d,%d,%d %d,%d,%d,%d\n", + // modes[0][0], modes[0][1], modes[0][2], modes[0][3], + // modes[1][0], modes[1][1], modes[1][2], modes[1][3]); + } + + for (i = 0; i < 16; i++) + { + xd->block[i].bmi = xd->mode_info_context->bmi[i]; + } +} + +void vp8_estimate_ref_frame_costs(VP8_COMP *cpi, unsigned int * ref_costs ) +{ + VP8_COMMON *cm = &cpi->common; + MACROBLOCKD *xd = &cpi->mb.e_mbd; + vp8_prob * mod_refprobs; + + unsigned int cost; + int pred_ref ; + int pred_flag; + int i; + + vp8_prob pred_prob; + + // Get the predicted reference for this mb + pred_ref = get_pred_ref( cm, xd ); + + // Get the context probability for the prediction flag + pred_prob = get_pred_prob( cm, xd, PRED_REF ); + + // Get the set of probailities to use if prediction fails + mod_refprobs = cm->mod_refprobs[pred_ref]; + + // For each possible selected reference frame work out a cost. + // TODO: correct handling of costs if segment indicates only a subset of + // reference frames are allowed... though mostly this should come out + // in the wash. + for ( i = 0; i < MAX_REF_FRAMES; i++ ) + { + pred_flag = (i == pred_ref); + + // Get the prediction for the current mb + cost = vp8_cost_bit( pred_prob, pred_flag ); + + // for incorectly predicted cases + if ( ! pred_flag ) + { + if ( mod_refprobs[0] ) + cost += vp8_cost_bit( (i != INTRA_FRAME), mod_refprobs[0] ); + + // Inter coded + if (i != INTRA_FRAME) + { + if ( mod_refprobs[1] ) + cost += vp8_cost_bit( (i != LAST_FRAME), mod_refprobs[1] ); + + if (i != LAST_FRAME) + { + if ( mod_refprobs[2] ) + cost += vp8_cost_bit( (i != GOLDEN_FRAME), + mod_refprobs[2] ); + } + } + } + + ref_costs[i] = cost; + } +} + +void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, + int *returnrate, int *returndistortion, int *returnintra, + int *best_single_rd_diff, int *best_comp_rd_diff, + int *best_hybrid_rd_diff) +{ + VP8_COMMON *cm = &cpi->common; BLOCK *b = &x->block[0]; BLOCKD *d = &x->e_mbd.block[0]; MACROBLOCKD *xd = &x->e_mbd; @@ -1824,6 +2501,8 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int MB_PREDICTION_MODE this_mode; int num00; int best_mode_index = 0; + int mode8x8[2][4]; + unsigned char segment_id = xd->mode_info_context->mbmi.segment_id; int i; int mode_index; @@ -1832,8 +2511,14 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int int distortion; int best_rd = INT_MAX; int best_intra_rd = INT_MAX; + int best_comp_rd = INT_MAX; + int best_single_rd = INT_MAX; + int best_hybrid_rd = INT_MAX; int rate2, distortion2; int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly; + int uv_intra_skippable = 0; + int uv_intra_rate_8x8, uv_intra_distortion_8x8, uv_intra_rate_tokenonly_8x8; + int uv_intra_skippable_8x8=0; int rate_y, UNINITIALIZED_IS_SAFE(rate_uv); int distortion_uv; int best_yrd = INT_MAX; @@ -1844,6 +2529,8 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int //int intermodecost[MAX_MODES]; MB_PREDICTION_MODE uv_intra_mode; + MB_PREDICTION_MODE uv_intra_mode_8x8; + int_mv mvp; int near_sadidx[8] = {0, 1, 2, 3, 4, 5, 6, 7}; int saddone=0; @@ -1852,55 +2539,63 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int int_mv frame_nearest_mv[4]; int_mv frame_near_mv[4]; int_mv frame_best_ref_mv[4]; + int_mv mc_search_result[4]; int frame_mdcounts[4][4]; - int frame_lf_or_gf[4]; unsigned char *y_buffer[4]; unsigned char *u_buffer[4]; unsigned char *v_buffer[4]; + unsigned int ref_costs[MAX_REF_FRAMES]; + vpx_memset(&best_mbmode, 0, sizeof(best_mbmode)); vpx_memset(&best_bmodes, 0, sizeof(best_bmodes)); + for (i = 0; i < 4; i++) + { +#define INVALID_MV 0x80008000 + mc_search_result[i].as_int = INVALID_MV; + } + if (cpi->ref_frame_flags & VP8_LAST_FLAG) { YV12_BUFFER_CONFIG *lst_yv12 = &cpi->common.yv12_fb[cpi->common.lst_fb_idx]; - vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &frame_nearest_mv[LAST_FRAME], &frame_near_mv[LAST_FRAME], - &frame_best_ref_mv[LAST_FRAME], frame_mdcounts[LAST_FRAME], LAST_FRAME, cpi->common.ref_frame_sign_bias); + vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, + x->e_mbd.prev_mode_info_context, + &frame_nearest_mv[LAST_FRAME], &frame_near_mv[LAST_FRAME], + &frame_best_ref_mv[LAST_FRAME], frame_mdcounts[LAST_FRAME], LAST_FRAME, cpi->common.ref_frame_sign_bias); y_buffer[LAST_FRAME] = lst_yv12->y_buffer + recon_yoffset; u_buffer[LAST_FRAME] = lst_yv12->u_buffer + recon_uvoffset; v_buffer[LAST_FRAME] = lst_yv12->v_buffer + recon_uvoffset; - - frame_lf_or_gf[LAST_FRAME] = 0; } if (cpi->ref_frame_flags & VP8_GOLD_FLAG) { YV12_BUFFER_CONFIG *gld_yv12 = &cpi->common.yv12_fb[cpi->common.gld_fb_idx]; - vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &frame_nearest_mv[GOLDEN_FRAME], &frame_near_mv[GOLDEN_FRAME], - &frame_best_ref_mv[GOLDEN_FRAME], frame_mdcounts[GOLDEN_FRAME], GOLDEN_FRAME, cpi->common.ref_frame_sign_bias); + vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, + x->e_mbd.prev_mode_info_context, + &frame_nearest_mv[GOLDEN_FRAME], &frame_near_mv[GOLDEN_FRAME], + &frame_best_ref_mv[GOLDEN_FRAME], frame_mdcounts[GOLDEN_FRAME], GOLDEN_FRAME, cpi->common.ref_frame_sign_bias); y_buffer[GOLDEN_FRAME] = gld_yv12->y_buffer + recon_yoffset; u_buffer[GOLDEN_FRAME] = gld_yv12->u_buffer + recon_uvoffset; v_buffer[GOLDEN_FRAME] = gld_yv12->v_buffer + recon_uvoffset; - - frame_lf_or_gf[GOLDEN_FRAME] = 1; } if (cpi->ref_frame_flags & VP8_ALT_FLAG) { YV12_BUFFER_CONFIG *alt_yv12 = &cpi->common.yv12_fb[cpi->common.alt_fb_idx]; - vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &frame_nearest_mv[ALTREF_FRAME], &frame_near_mv[ALTREF_FRAME], + vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, + x->e_mbd.prev_mode_info_context, + &frame_nearest_mv[ALTREF_FRAME], &frame_near_mv[ALTREF_FRAME], &frame_best_ref_mv[ALTREF_FRAME], frame_mdcounts[ALTREF_FRAME], ALTREF_FRAME, cpi->common.ref_frame_sign_bias); y_buffer[ALTREF_FRAME] = alt_yv12->y_buffer + recon_yoffset; u_buffer[ALTREF_FRAME] = alt_yv12->u_buffer + recon_uvoffset; v_buffer[ALTREF_FRAME] = alt_yv12->v_buffer + recon_uvoffset; - - frame_lf_or_gf[ALTREF_FRAME] = 1; } *returnintra = INT_MAX; @@ -1911,22 +2606,37 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int vpx_memset(mode_mv, 0, sizeof(mode_mv)); x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; - rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate, &uv_intra_rate_tokenonly, &uv_intra_distortion); + + /* Initialize zbin mode boost for uv costing */ + cpi->zbin_mode_boost = 0; + vp8_update_zbin_extra(cpi, x); + + rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate, + &uv_intra_rate_tokenonly, &uv_intra_distortion); uv_intra_mode = x->e_mbd.mode_info_context->mbmi.uv_mode; + uv_intra_skippable = mbuv_is_skippable(&x->e_mbd); + + /* rough estimate for now */ + if(cpi->common.txfm_mode==ALLOW_8X8) + { + rd_pick_intra_mbuv_mode_8x8(cpi, x, &uv_intra_rate_8x8, + &uv_intra_rate_tokenonly_8x8, + &uv_intra_distortion_8x8); + uv_intra_mode_8x8 = x->e_mbd.mode_info_context->mbmi.uv_mode; + uv_intra_skippable_8x8 = mbuv_is_skippable_8x8(&x->e_mbd); + } + + // Get estimates of reference frame costs for each reference frame + // that depend on the current prediction etc. + vp8_estimate_ref_frame_costs( cpi, ref_costs ); for (mode_index = 0; mode_index < MAX_MODES; mode_index++) { int this_rd = INT_MAX; - int lf_or_gf = 0; // Lat Frame (01) or gf/arf (1) int disable_skip = 0; int other_cost = 0; - - // Experimental debug code. - // Record of rd values recorded for this MB. -1 indicates not measured - //all_rds[mode_index] = -1; - //all_rates[mode_index] = -1; - //all_dist[mode_index] = -1; - //intermodecost[mode_index] = -1; + int compmode_cost = 0; + int mode_excluded = 0; // Test best rd so far against threshold for trying this mode. if (best_rd <= cpi->rd_threshes[mode_index]) @@ -1939,16 +2649,46 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int this_mode = vp8_mode_order[mode_index]; x->e_mbd.mode_info_context->mbmi.mode = this_mode; +#if CONFIG_COMP_INTRA_PRED + x->e_mbd.mode_info_context->mbmi.second_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); + x->e_mbd.mode_info_context->mbmi.second_uv_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); +#endif x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; x->e_mbd.mode_info_context->mbmi.ref_frame = vp8_ref_frame_order[mode_index]; + x->e_mbd.mode_info_context->mbmi.second_ref_frame = vp8_second_ref_frame_order[mode_index]; - // Only consider ZEROMV/ALTREF_FRAME for alt ref frame, - // unless ARNR filtering is enabled in which case we want - // an unfiltered alternative - if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) + // If the segment reference frame feature is enabled.... + // then do nothing if the current ref frame is not allowed.. + if ( segfeature_active( xd, segment_id, SEG_LVL_REF_FRAME ) && + !check_segref( xd, segment_id, + xd->mode_info_context->mbmi.ref_frame ) ) { - if (this_mode != ZEROMV || x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME) - continue; + continue; + } + // If the segment mode feature is enabled.... + // then do nothing if the current mode is not allowed.. + else if ( segfeature_active( xd, segment_id, SEG_LVL_MODE ) && + ( this_mode != + get_segdata( xd, segment_id, SEG_LVL_MODE ) ) ) + { + continue; + } + + // Disable this drop out case if either the mode or ref frame + // segment level feature is enabled for this segment. This is to + // prevent the possibility that the we end up unable to pick any mode. + else if ( !segfeature_active( xd, segment_id, SEG_LVL_REF_FRAME ) && + !segfeature_active( xd, segment_id, SEG_LVL_MODE ) ) + { + // Only consider ZEROMV/ALTREF_FRAME for alt ref frame, + // unless ARNR filtering is enabled in which case we want + // an unfiltered alternative + if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) + { + if (this_mode != ZEROMV || + x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME) + continue; + } } /* everything but intra */ @@ -1961,31 +2701,10 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int mode_mv[NEARMV] = frame_near_mv[x->e_mbd.mode_info_context->mbmi.ref_frame]; best_ref_mv = frame_best_ref_mv[x->e_mbd.mode_info_context->mbmi.ref_frame]; vpx_memcpy(mdcounts, frame_mdcounts[x->e_mbd.mode_info_context->mbmi.ref_frame], sizeof(mdcounts)); - lf_or_gf = frame_lf_or_gf[x->e_mbd.mode_info_context->mbmi.ref_frame]; } - // Check to see if the testing frequency for this mode is at its max - // If so then prevent it from being tested and increase the threshold for its testing - if (cpi->mode_test_hit_counts[mode_index] && (cpi->mode_check_freq[mode_index] > 1)) - { - if (cpi->mbs_tested_so_far <= cpi->mode_check_freq[mode_index] * cpi->mode_test_hit_counts[mode_index]) - { - // Increase the threshold for coding this mode to make it less likely to be chosen - cpi->rd_thresh_mult[mode_index] += 4; - - if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) - cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; - - cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; - - continue; - } - } - - // We have now reached the point where we are going to test the current mode so increment the counter for the number of times it has been tested - cpi->mode_test_hit_counts[mode_index] ++; - - // Experimental code. Special case for gf and arf zeromv modes. Increase zbin size to supress noise + // Experimental code. Special case for gf and arf zeromv modes. + // Increase zbin size to suppress noise if (cpi->zbin_mode_boost_enabled) { if ( vp8_ref_frame_order[mode_index] == INTRA_FRAME ) @@ -2008,6 +2727,8 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int vp8_update_zbin_extra(cpi, x); } + + if (!x->e_mbd.mode_info_context->mbmi.second_ref_frame) switch (this_mode) { case B_PRED: @@ -2015,7 +2736,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int int tmp_rd; // Note the rate value returned here includes the cost of coding the BPRED mode : x->mbmode_cost[x->e_mbd.frame_type][BPRED]; - tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rate_y, &distortion, best_yrd); + tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rate_y, &distortion, best_yrd, 0); rate2 += rate; distortion2 += distortion; @@ -2033,6 +2754,41 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int } } break; + case I8X8_PRED: + { + int tmp_rd; + tmp_rd = rd_pick_intra8x8mby_modes(cpi, + x, &rate, &rate_y, &distortion, best_yrd); + rate2 += rate; + distortion2 += distortion; + + mode8x8[0][0]= x->e_mbd.mode_info_context->bmi[0].as_mode.first; + mode8x8[0][1]= x->e_mbd.mode_info_context->bmi[2].as_mode.first; + mode8x8[0][2]= x->e_mbd.mode_info_context->bmi[8].as_mode.first; + mode8x8[0][3]= x->e_mbd.mode_info_context->bmi[10].as_mode.first; +#if CONFIG_COMP_INTRA_PRED + mode8x8[1][0]= x->e_mbd.mode_info_context->bmi[0].as_mode.second; + mode8x8[1][1]= x->e_mbd.mode_info_context->bmi[2].as_mode.second; + mode8x8[1][2]= x->e_mbd.mode_info_context->bmi[8].as_mode.second; + mode8x8[1][3]= x->e_mbd.mode_info_context->bmi[10].as_mode.second; +#endif + + /* TODO: uv rate maybe over-estimated here since there is UV intra + mode coded in I8X8_PRED prediction */ + if(tmp_rd < best_yrd) + { + rate2 += uv_intra_rate; + rate_uv = uv_intra_rate_tokenonly; + distortion2 += uv_intra_distortion; + distortion_uv = uv_intra_distortion; + } + else + { + this_rd = INT_MAX; + disable_skip = 1; + } + } + break; case SPLITMV: { @@ -2069,16 +2825,32 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int case H_PRED: case TM_PRED: x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; + // FIXME compound intra prediction RECON_INVOKE(&cpi->common.rtcd.recon, build_intra_predictors_mby) (&x->e_mbd); - macro_block_yrd(x, &rate_y, &distortion, IF_RTCD(&cpi->rtcd.encodemb)) ; + if(cpi->common.txfm_mode == ALLOW_8X8) + macro_block_yrd_8x8(x, &rate_y, &distortion, + IF_RTCD(&cpi->rtcd)) ; + else + macro_block_yrd(x, &rate_y, &distortion, + IF_RTCD(&cpi->rtcd.encodemb)) ; rate2 += rate_y; distortion2 += distortion; rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode]; - rate2 += uv_intra_rate; - rate_uv = uv_intra_rate_tokenonly; - distortion2 += uv_intra_distortion; - distortion_uv = uv_intra_distortion; + if(cpi->common.txfm_mode == ALLOW_8X8) + { + rate2 += uv_intra_rate_8x8; + rate_uv = uv_intra_rate_tokenonly_8x8; + distortion2 += uv_intra_distortion_8x8; + distortion_uv = uv_intra_distortion_8x8; + } + else + { + rate2 += uv_intra_rate; + rate_uv = uv_intra_rate_tokenonly; + distortion2 += uv_intra_distortion; + distortion_uv = uv_intra_distortion; + } break; case NEWMV: @@ -2135,7 +2907,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int bestsme = cpi->diamond_search_sad(x, b, d, &mvp_full, &d->bmi.mv, step_param, sadpb, &num00, &cpi->fn_ptr[BLOCK_16X16], - x->mvcost, &best_ref_mv); + XMVCOST, &best_ref_mv); mode_mv[NEWMV].as_int = d->bmi.mv.as_int; // Further step/diamond searches as necessary @@ -2159,8 +2931,8 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int { thissme = cpi->diamond_search_sad(x, b, d, &mvp_full, &d->bmi.mv, step_param + n, sadpb, &num00, - &cpi->fn_ptr[BLOCK_16X16], x->mvcost, - &best_ref_mv); + &cpi->fn_ptr[BLOCK_16X16], + XMVCOST, &best_ref_mv); /* check to see if refining search is needed. */ if (num00 > (further_steps-n)) @@ -2191,7 +2963,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int //thissme = cpi->full_search_sad(x, b, d, &d->bmi.mv.as_mv, sadpb, search_range, &cpi->fn_ptr[BLOCK_16X16], x->mvcost, &best_ref_mv); thissme = cpi->refining_search_sad(x, b, d, &d->bmi.mv, sadpb, search_range, &cpi->fn_ptr[BLOCK_16X16], - x->mvcost, &best_ref_mv); + XMVCOST, &best_ref_mv); if (thissme < bestsme) { @@ -2216,13 +2988,21 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv, &best_ref_mv, x->errorperbit, &cpi->fn_ptr[BLOCK_16X16], - x->mvcost, &dis, &sse); + XMVCOST, &dis, &sse); } + mc_search_result[x->e_mbd.mode_info_context->mbmi.ref_frame].as_int = d->bmi.mv.as_int; mode_mv[NEWMV].as_int = d->bmi.mv.as_int; // Add the new motion vector cost to our rolling cost variable - rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, x->mvcost, 96); +#if CONFIG_HIGH_PRECISION_MV + rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, + XMVCOST, 96, + x->e_mbd.allow_high_precision_mv); +#else + rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, + XMVCOST, 96); +#endif } case NEARESTMV: @@ -2246,6 +3026,9 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int vp8_set_mbmode_and_mvs(x, this_mode, &mode_mv[this_mode]); vp8_build_inter16x16_predictors_mby(&x->e_mbd); + compmode_cost = + vp8_cost_bit( get_pred_prob( cm, xd, PRED_COMP ), 0 ); + if (cpi->active_map_enabled && x->active_ptr[0] == 0) { x->skip = 1; } @@ -2291,58 +3074,199 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int } } } - - //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code // Add in the Mv/mode cost - rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + rate2 += vp8_cost_mv_ref(&cpi->common, this_mode, mdcounts); // Y cost and distortion - macro_block_yrd(x, &rate_y, &distortion, IF_RTCD(&cpi->rtcd.encodemb)); + if(cpi->common.txfm_mode == ALLOW_8X8) + macro_block_yrd_8x8(x, &rate_y, &distortion, + IF_RTCD(&cpi->rtcd)); + else + macro_block_yrd(x, &rate_y, &distortion, + IF_RTCD(&cpi->rtcd.encodemb)); + rate2 += rate_y; distortion2 += distortion; // UV cost and distortion - rd_inter16x16_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel); + vp8_build_inter16x16_predictors_mbuv(&x->e_mbd); + + if(cpi->common.txfm_mode == ALLOW_8X8) + rd_inter16x16_uv_8x8(cpi, x, &rate_uv, + &distortion_uv, + cpi->common.full_pixel); + else + rd_inter16x16_uv(cpi, x, &rate_uv, + &distortion_uv, + cpi->common.full_pixel); rate2 += rate_uv; distortion2 += distortion_uv; + mode_excluded = cpi->common.comp_pred_mode == COMP_PREDICTION_ONLY; break; default: break; } + else /* x->e_mbd.mode_info_context->mbmi.second_ref_frame != 0 */ + { + int ref1 = x->e_mbd.mode_info_context->mbmi.ref_frame; + int ref2 = x->e_mbd.mode_info_context->mbmi.second_ref_frame; + + mode_excluded = cpi->common.comp_pred_mode == SINGLE_PREDICTION_ONLY; + switch (this_mode) + { + case NEWMV: + if (mc_search_result[ref1].as_int == INVALID_MV || + mc_search_result[ref2].as_int == INVALID_MV) + continue; + x->e_mbd.mode_info_context->mbmi.mv.as_int = mc_search_result[ref1].as_int; + x->e_mbd.mode_info_context->mbmi.second_mv.as_int = mc_search_result[ref2].as_int; +#if CONFIG_HIGH_PRECISION_MV + rate2 += vp8_mv_bit_cost(&mc_search_result[ref1], + &frame_best_ref_mv[ref1], + XMVCOST, 96, + x->e_mbd.allow_high_precision_mv); + rate2 += vp8_mv_bit_cost(&mc_search_result[ref2], + &frame_best_ref_mv[ref2], + XMVCOST, 96, + x->e_mbd.allow_high_precision_mv); +#else + rate2 += vp8_mv_bit_cost(&mc_search_result[ref1], + &frame_best_ref_mv[ref1], + XMVCOST, 96); + rate2 += vp8_mv_bit_cost(&mc_search_result[ref2], + &frame_best_ref_mv[ref2], + XMVCOST, 96); +#endif + break; + case ZEROMV: + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + x->e_mbd.mode_info_context->mbmi.second_mv.as_int = 0; + break; + case NEARMV: + if (frame_near_mv[ref1].as_int == 0 || frame_near_mv[ref2].as_int == 0) + continue; + x->e_mbd.mode_info_context->mbmi.mv.as_int = frame_near_mv[ref1].as_int; + x->e_mbd.mode_info_context->mbmi.second_mv.as_int = frame_near_mv[ref2].as_int; + break; + case NEARESTMV: + if (frame_nearest_mv[ref1].as_int == 0 || frame_nearest_mv[ref2].as_int == 0) + continue; + x->e_mbd.mode_info_context->mbmi.mv.as_int = frame_nearest_mv[ref1].as_int; + x->e_mbd.mode_info_context->mbmi.second_mv.as_int = frame_nearest_mv[ref2].as_int; + break; + default: + break; + } + + /* Add in the Mv/mode cost */ + rate2 += vp8_cost_mv_ref(&cpi->common,this_mode, mdcounts); + + vp8_clamp_mv2(&x->e_mbd.mode_info_context->mbmi.mv, xd); + vp8_clamp_mv2(&x->e_mbd.mode_info_context->mbmi.second_mv, xd); + if (((x->e_mbd.mode_info_context->mbmi.mv.as_mv.row >> 3) < x->mv_row_min) || + ((x->e_mbd.mode_info_context->mbmi.mv.as_mv.row >> 3) > x->mv_row_max) || + ((x->e_mbd.mode_info_context->mbmi.mv.as_mv.col >> 3) < x->mv_col_min) || + ((x->e_mbd.mode_info_context->mbmi.mv.as_mv.col >> 3) > x->mv_col_max) || + ((x->e_mbd.mode_info_context->mbmi.second_mv.as_mv.row >> 3) < x->mv_row_min) || + ((x->e_mbd.mode_info_context->mbmi.second_mv.as_mv.row >> 3) > x->mv_row_max) || + ((x->e_mbd.mode_info_context->mbmi.second_mv.as_mv.col >> 3) < x->mv_col_min) || + ((x->e_mbd.mode_info_context->mbmi.second_mv.as_mv.col >> 3) > x->mv_col_max)) + continue; + + /* build first and second prediction */ + vp8_build_inter16x16_predictors_mby(&x->e_mbd); + vp8_build_inter16x16_predictors_mbuv(&x->e_mbd); + /* do second round and average the results */ + x->e_mbd.second_pre.y_buffer = y_buffer[ref2]; + x->e_mbd.second_pre.u_buffer = u_buffer[ref2]; + x->e_mbd.second_pre.v_buffer = v_buffer[ref2]; + vp8_build_2nd_inter16x16_predictors_mb(&x->e_mbd, x->e_mbd.predictor, + &x->e_mbd.predictor[256], + &x->e_mbd.predictor[320], 16, 8); + + /* Y cost and distortion */ + if(cpi->common.txfm_mode == ALLOW_8X8) + macro_block_yrd_8x8(x, &rate_y, &distortion, + IF_RTCD(&cpi->rtcd)); + else + macro_block_yrd(x, &rate_y, &distortion, + IF_RTCD(&cpi->rtcd.encodemb)); + + rate2 += rate_y; + distortion2 += distortion; + + /* UV cost and distortion */ + if(cpi->common.txfm_mode == ALLOW_8X8) + rd_inter16x16_uv_8x8(cpi, x, &rate_uv, + &distortion_uv, + cpi->common.full_pixel); + else + rd_inter16x16_uv(cpi, x, &rate_uv, + &distortion_uv, + cpi->common.full_pixel); + rate2 += rate_uv; + distortion2 += distortion_uv; + + /* don't bother w/ skip, we would never have come here if skip were enabled */ + x->e_mbd.mode_info_context->mbmi.mode = this_mode; + + /* We don't include the cost of the second reference here, because there are only + * three options: Last/Golden, ARF/Last or Golden/ARF, or in other words if you + * present them in that order, the second one is always known if the first is known */ + compmode_cost = + vp8_cost_bit( get_pred_prob( cm, xd, PRED_COMP ), 1 ); + } // Where skip is allowable add in the default per mb cost for the no skip case. // where we then decide to skip we have to delete this and replace it with the // cost of signallying a skip if (cpi->common.mb_no_coeff_skip) { - other_cost += vp8_cost_bit(cpi->prob_skip_false, 0); - rate2 += other_cost; + int prob_skip_cost = vp8_cost_bit(cpi->prob_skip_false, 0); + other_cost += prob_skip_cost; + rate2 += prob_skip_cost; } - /* Estimate the reference frame signaling cost and add it - * to the rolling cost variable. - */ - rate2 += - x->e_mbd.ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + if (cpi->common.comp_pred_mode == HYBRID_PREDICTION) + { + rate2 += compmode_cost; + } + + + // Estimate the reference frame signaling cost and add it + // to the rolling cost variable. + rate2 += ref_costs[x->e_mbd.mode_info_context->mbmi.ref_frame]; if (!disable_skip) { // Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate if (cpi->common.mb_no_coeff_skip) { - int tteob; - - tteob = 0; - - for (i = 0; i <= 24; i++) + int mb_skippable; + int has_y2 = ( this_mode!=SPLITMV + &&this_mode!=B_PRED + &&this_mode!=I8X8_PRED); + if((cpi->common.txfm_mode == ALLOW_8X8) && has_y2) { - tteob += x->e_mbd.block[i].eob; + if(x->e_mbd.mode_info_context->mbmi.ref_frame!=INTRA_FRAME) + mb_skippable = mb_is_skippable_8x8(&x->e_mbd); + else + mb_skippable = uv_intra_skippable_8x8 + & mby_is_skippable_8x8(&x->e_mbd); + } + else + { + if(x->e_mbd.mode_info_context->mbmi.ref_frame!=INTRA_FRAME) + mb_skippable = mb_is_skippable(&x->e_mbd, has_y2); + else + mb_skippable = uv_intra_skippable + & mby_is_skippable(&x->e_mbd, has_y2); } - if (tteob == 0) + if (mb_skippable) { rate2 -= (rate_y + rate_uv); //for best_yrd calculation @@ -2377,38 +3301,57 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int *returnintra = distortion2 ; } + if (!disable_skip && + (this_mode == SPLITMV || x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME)) + { + if (this_rd < best_comp_rd) + best_comp_rd = this_rd; + if (this_rd < best_single_rd) + best_single_rd = this_rd; + if (this_rd < best_hybrid_rd) + best_hybrid_rd = this_rd; + } + // Did this mode help.. i.i is it the new best mode if (this_rd < best_rd || x->skip) { - // Note index of best mode so far - best_mode_index = mode_index; - - if (this_mode <= B_PRED) + if (!mode_excluded) { - x->e_mbd.mode_info_context->mbmi.uv_mode = uv_intra_mode; - /* required for left and above block mv */ - x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; - } + // Note index of best mode so far + best_mode_index = mode_index; - other_cost += - x->e_mbd.ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; - - /* Calculate the final y RD estimate for this mode */ - best_yrd = RDCOST(x->rdmult, x->rddiv, (rate2-rate_uv-other_cost), - (distortion2-distortion_uv)); - - *returnrate = rate2; - *returndistortion = distortion2; - best_rd = this_rd; - vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); - vpx_memcpy(&best_partition, x->partition_info, sizeof(PARTITION_INFO)); - - if ((this_mode == B_PRED) || (this_mode == SPLITMV)) - for (i = 0; i < 16; i++) + if (this_mode <= B_PRED) { - best_bmodes[i] = x->e_mbd.block[i].bmi; + if( cpi->common.txfm_mode == ALLOW_8X8 + && this_mode != B_PRED + && this_mode != I8X8_PRED) + x->e_mbd.mode_info_context->mbmi.uv_mode = uv_intra_mode_8x8; + else + x->e_mbd.mode_info_context->mbmi.uv_mode = uv_intra_mode; + /* required for left and above block mv */ + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; } + other_cost += ref_costs[x->e_mbd.mode_info_context->mbmi.ref_frame]; + + /* Calculate the final y RD estimate for this mode */ + best_yrd = RDCOST(x->rdmult, x->rddiv, (rate2-rate_uv-other_cost), + (distortion2-distortion_uv)); + + *returnrate = rate2; + *returndistortion = distortion2; + best_rd = this_rd; + vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); + vpx_memcpy(&best_partition, x->partition_info, sizeof(PARTITION_INFO)); + + if ((this_mode == B_PRED) + ||(this_mode == I8X8_PRED) + || (this_mode == SPLITMV)) + for (i = 0; i < 16; i++) + { + best_bmodes[i] = x->e_mbd.block[i].bmi; + } + } // Testing this mode gave rise to an improvement in best error score. Lower threshold a bit for next time cpi->rd_thresh_mult[mode_index] = (cpi->rd_thresh_mult[mode_index] >= (MIN_THRESHMULT + 2)) ? cpi->rd_thresh_mult[mode_index] - 2 : MIN_THRESHMULT; @@ -2426,6 +3369,43 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; } + /* keep record of best compound/single-only prediction */ + if (!disable_skip && + x->e_mbd.mode_info_context->mbmi.ref_frame != INTRA_FRAME && + this_mode != SPLITMV) + { + int single_rd, hybrid_rd, single_rate, hybrid_rate; + + if (cpi->common.comp_pred_mode == HYBRID_PREDICTION) + { + single_rate = rate2 - compmode_cost; + hybrid_rate = rate2; + } + else + { + single_rate = rate2; + hybrid_rate = rate2 + compmode_cost; + } + + single_rd = RDCOST(x->rdmult, x->rddiv, single_rate, distortion2); + hybrid_rd = RDCOST(x->rdmult, x->rddiv, hybrid_rate, distortion2); + + if (x->e_mbd.mode_info_context->mbmi.second_ref_frame == INTRA_FRAME && + single_rd < best_single_rd) + { + best_single_rd = single_rd; + } + else if (x->e_mbd.mode_info_context->mbmi.second_ref_frame != INTRA_FRAME && + single_rd < best_comp_rd) + { + best_comp_rd = single_rd; + } + if (hybrid_rd < best_hybrid_rd) + { + best_hybrid_rd = hybrid_rd; + } + } + if (x->skip) break; @@ -2460,8 +3440,14 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int // Note how often each mode chosen as best cpi->mode_chosen_counts[best_mode_index] ++; - - if (cpi->is_src_frame_alt_ref && + // This code force Altref,0,0 and skip for the frame that overlays a + // an alrtef unless Altref is filtered. However, this is unsafe if + // segment level coding of ref frame or mode is enabled for this + // segment. + if (!segfeature_active( xd, segment_id, SEG_LVL_REF_FRAME ) && + !segfeature_active( xd, segment_id, SEG_LVL_MODE ) && + cpi->is_src_frame_alt_ref && + (cpi->oxcf.arnr_max_frames == 0) && (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) { x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; @@ -2472,6 +3458,8 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int (cpi->common.mb_no_coeff_skip) ? 1 : 0; x->e_mbd.mode_info_context->mbmi.partitioning = 0; + *best_single_rd_diff = *best_comp_rd_diff = *best_hybrid_rd_diff = 0; + return; } @@ -2482,7 +3470,15 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int if (best_mbmode.mode == B_PRED) { for (i = 0; i < 16; i++) + { xd->mode_info_context->bmi[i].as_mode = best_bmodes[i].as_mode; + xd->block[i].bmi.as_mode = xd->mode_info_context->bmi[i].as_mode; + } + } + + if (best_mbmode.mode == I8X8_PRED) + { + set_i8x8_block_modes(x, mode8x8); } if (best_mbmode.mode == SPLITMV) @@ -2498,19 +3494,34 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int rd_update_mvcount(cpi, x, &frame_best_ref_mv[xd->mode_info_context->mbmi.ref_frame]); - - + if (best_single_rd == INT_MAX) + *best_single_rd_diff = INT_MIN; + else + *best_single_rd_diff = best_rd - best_single_rd; + if (best_comp_rd == INT_MAX) + *best_comp_rd_diff = INT_MIN; + else + *best_comp_rd_diff = best_rd - best_comp_rd; + if (best_hybrid_rd == INT_MAX) + *best_hybrid_rd_diff = INT_MIN; + else + *best_hybrid_rd_diff = best_rd - best_hybrid_rd; } void vp8_rd_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate_) { - int error4x4, error16x16; - int rate4x4, rate16x16 = 0, rateuv; - int dist4x4, dist16x16, distuv; + MACROBLOCKD *xd = &x->e_mbd; + int error4x4, error16x16, error4x4d; + int rate4x4, rate16x16 = 0, rateuv, rate4x4d; + int dist4x4, dist16x16, distuv, dist4x4d; int rate; int rate4x4_tokenonly = 0; int rate16x16_tokenonly = 0; int rateuv_tokenonly = 0; + int error8x8, rate8x8_tokenonly=0; + int rate8x8, dist8x8; + int mode16x16; + int mode8x8[2][4]; x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; @@ -2520,20 +3531,65 @@ void vp8_rd_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate_) error16x16 = rd_pick_intra16x16mby_mode(cpi, x, &rate16x16, &rate16x16_tokenonly, &dist16x16); + mode16x16 = x->e_mbd.mode_info_context->mbmi.mode; + + error8x8 = rd_pick_intra8x8mby_modes(cpi, x, + &rate8x8, &rate8x8_tokenonly, + &dist8x8, error16x16); + mode8x8[0][0]= x->e_mbd.mode_info_context->bmi[0].as_mode.first; + mode8x8[0][1]= x->e_mbd.mode_info_context->bmi[2].as_mode.first; + mode8x8[0][2]= x->e_mbd.mode_info_context->bmi[8].as_mode.first; + mode8x8[0][3]= x->e_mbd.mode_info_context->bmi[10].as_mode.first; +#if CONFIG_COMP_INTRA_PRED + mode8x8[1][0]= x->e_mbd.mode_info_context->bmi[0].as_mode.second; + mode8x8[1][1]= x->e_mbd.mode_info_context->bmi[2].as_mode.second; + mode8x8[1][2]= x->e_mbd.mode_info_context->bmi[8].as_mode.second; + mode8x8[1][3]= x->e_mbd.mode_info_context->bmi[10].as_mode.second; +#endif error4x4 = rd_pick_intra4x4mby_modes(cpi, x, &rate4x4, &rate4x4_tokenonly, - &dist4x4, error16x16); + &dist4x4, error16x16, 0); + error4x4d = rd_pick_intra4x4mby_modes(cpi, x, + &rate4x4d, &rate4x4_tokenonly, + &dist4x4d, error16x16, 1); - if (error4x4 < error16x16) + if(error8x8> error16x16) { - x->e_mbd.mode_info_context->mbmi.mode = B_PRED; - rate += rate4x4; + if (error4x4 < error16x16) + { + rate += (error4x4d < error4x4) ? rate4x4d : rate4x4; + if (error4x4d >= error4x4) // FIXME save original modes etc. + error4x4 = rd_pick_intra4x4mby_modes(cpi, x, &rate4x4, + &rate4x4_tokenonly, + &dist4x4, error16x16, 0); + x->e_mbd.mode_info_context->mbmi.mode = B_PRED; + } + else + { + x->e_mbd.mode_info_context->mbmi.mode = mode16x16; + rate += rate16x16; + + } } else { - rate += rate16x16; - } + if (error4x4 < error8x8) + { + rate += (error4x4d < error4x4) ? rate4x4d : rate4x4; + if (error4x4d >= error4x4) // FIXME save original modes etc. + error4x4 = rd_pick_intra4x4mby_modes(cpi, x, &rate4x4, + &rate4x4_tokenonly, + &dist4x4, error16x16, 0); + x->e_mbd.mode_info_context->mbmi.mode = B_PRED; + } + else + { + x->e_mbd.mode_info_context->mbmi.mode = I8X8_PRED; + set_i8x8_block_modes(x, mode8x8); + rate += rate8x8; + } + } *rate_ = rate; } diff --git a/vp8/encoder/rdopt.h b/vp8/encoder/rdopt.h index 95134cb81..9bb7e404b 100644 --- a/vp8/encoder/rdopt.h +++ b/vp8/encoder/rdopt.h @@ -13,9 +13,12 @@ #define __INC_RDOPT_H #define RDCOST(RM,DM,R,D) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) +#define RDCOST_8x8(RM,DM,R,D) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) extern void vp8_initialize_rd_consts(VP8_COMP *cpi, int Qvalue); -extern void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra); +extern void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, + int *returnrate, int *returndistortion, int *returnintra, + int *best_single_rd_diff, int *best_comp_rd_diff, int *best_hybrid_rd_diff); extern void vp8_rd_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate); extern void vp8_mv_pred @@ -29,6 +32,8 @@ extern void vp8_mv_pred int *sr, int near_sadidx[] ); -void vp8_cal_sad(VP8_COMP *cpi, MACROBLOCKD *xd, MACROBLOCK *x, int recon_yoffset, int near_sadidx[]); +extern void vp8_cal_sad(VP8_COMP *cpi, MACROBLOCKD *xd, MACROBLOCK *x, int recon_yoffset, int near_sadidx[]); +extern void vp8_init_me_luts(); +extern void vp8_set_mbmode_and_mvs(MACROBLOCK *x, MB_PREDICTION_MODE mb, int_mv *mv); #endif diff --git a/vp8/encoder/sad_c.c b/vp8/encoder/sad_c.c index 3b6e26c4e..c734458a9 100644 --- a/vp8/encoder/sad_c.c +++ b/vp8/encoder/sad_c.c @@ -10,7 +10,7 @@ #include -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx/vpx_integer.h" unsigned int vp8_sad16x16_c( diff --git a/vp8/encoder/satd_c.c b/vp8/encoder/satd_c.c new file mode 100644 index 000000000..88c304b1f --- /dev/null +++ b/vp8/encoder/satd_c.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include "dct.h" +#include "vpx_ports/mem.h" + +unsigned int vp8_satd16x16_c(const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned int *psatd) +{ + int r, c, i; + unsigned int satd = 0; + DECLARE_ALIGNED(16, short, diff_in[256]); + DECLARE_ALIGNED(16, short, diff_out[16]); + short *in; + + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + diff_in[r * 16 + c] = src_ptr[c] - ref_ptr[c]; + } + src_ptr += src_stride; + ref_ptr += ref_stride; + } + + in = diff_in; + for (r = 0; r < 16; r += 4) + { + for (c = 0; c < 16; c+=4) + { + vp8_short_walsh4x4_c(in + c, diff_out, 32); + for(i = 0; i < 16; i++) + satd += abs(diff_out[i]); + } + in += 64; + } + + if (psatd) + *psatd = satd; + + return satd; +} diff --git a/vp8/encoder/segmentation.c b/vp8/encoder/segmentation.c index fc0967db3..c36246a02 100644 --- a/vp8/encoder/segmentation.c +++ b/vp8/encoder/segmentation.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -9,8 +9,10 @@ */ -#include "segmentation.h" +#include "limits.h" #include "vpx_mem/vpx_mem.h" +#include "segmentation.h" +#include "vp8/common/pred_common.h" void vp8_update_gf_useage_maps(VP8_COMP *cpi, VP8_COMMON *cm, MACROBLOCK *x) { @@ -37,8 +39,10 @@ void vp8_update_gf_useage_maps(VP8_COMP *cpi, VP8_COMMON *cm, MACROBLOCK *x) // If using golden then set GF active flag if not already set. // If using last frame 0,0 mode then leave flag as it is - // else if using non 0,0 motion or intra modes then clear flag if it is currently set - if ((this_mb_mode_info->mbmi.ref_frame == GOLDEN_FRAME) || (this_mb_mode_info->mbmi.ref_frame == ALTREF_FRAME)) + // else if using non 0,0 motion or intra modes then clear + // flag if it is currently set + if ((this_mb_mode_info->mbmi.ref_frame == GOLDEN_FRAME) || + (this_mb_mode_info->mbmi.ref_frame == ALTREF_FRAME)) { if (*(x->gf_active_ptr) == 0) { @@ -46,14 +50,15 @@ void vp8_update_gf_useage_maps(VP8_COMP *cpi, VP8_COMMON *cm, MACROBLOCK *x) cpi->gf_active_count ++; } } - else if ((this_mb_mode_info->mbmi.mode != ZEROMV) && *(x->gf_active_ptr)) + else if ((this_mb_mode_info->mbmi.mode != ZEROMV) && + *(x->gf_active_ptr)) { *(x->gf_active_ptr) = 0; cpi->gf_active_count--; } x->gf_active_ptr++; // Step onto next entry - this_mb_mode_info++; // skip to next mb + this_mb_mode_info++; // skip to next mb } @@ -62,3 +67,251 @@ void vp8_update_gf_useage_maps(VP8_COMP *cpi, VP8_COMMON *cm, MACROBLOCK *x) } } } + +void vp8_enable_segmentation(VP8_PTR ptr) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + // Set the appropriate feature bit + cpi->mb.e_mbd.segmentation_enabled = 1; + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; +} + +void vp8_disable_segmentation(VP8_PTR ptr) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + // Clear the appropriate feature bit + cpi->mb.e_mbd.segmentation_enabled = 0; +} + +void vp8_set_segmentation_map(VP8_PTR ptr, + unsigned char *segmentation_map) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + // Copy in the new segmentation map + vpx_memcpy( cpi->segmentation_map, segmentation_map, + (cpi->common.mb_rows * cpi->common.mb_cols) ); + + // Signal that the map should be updated. + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; +} + +void vp8_set_segment_data(VP8_PTR ptr, + signed char *feature_data, + unsigned char abs_delta) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + cpi->mb.e_mbd.mb_segment_abs_delta = abs_delta; + + vpx_memcpy(cpi->mb.e_mbd.segment_feature_data, feature_data, + sizeof(cpi->mb.e_mbd.segment_feature_data)); + + // TBD ?? Set the feature mask + // vpx_memcpy(cpi->mb.e_mbd.segment_feature_mask, 0, + // sizeof(cpi->mb.e_mbd.segment_feature_mask)); +} + +// Based on set of segment counts calculate a probability tree +static void calc_segtree_probs( MACROBLOCKD * xd, + int * segcounts, + vp8_prob * segment_tree_probs ) +{ + int count1,count2; + int tot_count; + int i; + + // Blank the strtucture to start with + vpx_memset(segment_tree_probs, 0, sizeof(segment_tree_probs)); + + // Total count for all segments + count1 = segcounts[0] + segcounts[1]; + count2 = segcounts[2] + segcounts[3]; + tot_count = count1 + count2; + + // Work out probabilities of each segment + if (tot_count) + segment_tree_probs[0] = (count1 * 255) / tot_count; + if (count1 > 0) + segment_tree_probs[1] = (segcounts[0] * 255) / count1; + if (count2 > 0) + segment_tree_probs[2] = (segcounts[2] * 255) / count2; + + // Clamp probabilities to minimum allowed value + for (i = 0; i < MB_FEATURE_TREE_PROBS; i++) + { + if (segment_tree_probs[i] == 0) + segment_tree_probs[i] = 1; + } +} + +// Based on set of segment counts and probabilities calculate a cost estimate +static int cost_segmap( MACROBLOCKD * xd, + int * segcounts, + vp8_prob * probs ) +{ + int cost; + int count1,count2; + + // Cost the top node of the tree + count1 = segcounts[0] + segcounts[1]; + count2 = segcounts[2] + segcounts[3]; + cost = count1 * vp8_cost_zero(probs[0]) + + count2 * vp8_cost_one(probs[0]); + + // Now add the cost of each individual segment branch + if (count1 > 0) + cost += segcounts[0] * vp8_cost_zero(probs[1]) + + segcounts[1] * vp8_cost_one(probs[1]); + + if (count2 > 0) + cost += segcounts[2] * vp8_cost_zero(probs[2]) + + segcounts[3] * vp8_cost_one(probs[2]) ; + + return cost; + +} + +void choose_segmap_coding_method( VP8_COMP *cpi ) +{ + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & cpi->mb.e_mbd; + + int i; + int tot_count; + int no_pred_cost; + int t_pred_cost = INT_MAX; + int pred_context; + + int mb_row, mb_col; + int segmap_index = 0; + unsigned char segment_id; + + int temporal_predictor_count[PREDICTION_PROBS][2]; + int no_pred_segcounts[MAX_MB_SEGMENTS]; + int t_unpred_seg_counts[MAX_MB_SEGMENTS]; + + vp8_prob no_pred_tree[MB_FEATURE_TREE_PROBS]; + vp8_prob t_pred_tree[MB_FEATURE_TREE_PROBS]; + vp8_prob t_nopred_prob[PREDICTION_PROBS]; + + // Set default state for the segment tree probabilities and the + // temporal coding probabilities + vpx_memset(xd->mb_segment_tree_probs, 255, + sizeof(xd->mb_segment_tree_probs)); + vpx_memset(cm->segment_pred_probs, 255, + sizeof(cm->segment_pred_probs)); + + vpx_memset(no_pred_segcounts, 0, sizeof(no_pred_segcounts)); + vpx_memset(t_unpred_seg_counts, 0, sizeof(t_unpred_seg_counts)); + vpx_memset(temporal_predictor_count, 0, sizeof(temporal_predictor_count)); + + // First of all generate stats regarding how well the last segment map + // predicts this one + + // Initialize macroblock decoder mode info context for the first mb + // in the frame + xd->mode_info_context = cm->mi; + + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + segment_id = xd->mode_info_context->mbmi.segment_id; + + // Count the number of hits on each segment with no prediction + no_pred_segcounts[segment_id]++; + + // Temporal prediction not allowed on key frames + if (cm->frame_type != KEY_FRAME) + { + // Test to see if the segment id matches the predicted value. + int seg_predicted = + (segment_id == get_pred_mb_segid( cm, segmap_index )); + + // Get the segment id prediction context + pred_context = + get_pred_context( cm, xd, PRED_SEG_ID ); + + // Store the prediction status for this mb and update counts + // as appropriate + set_pred_flag( xd, PRED_SEG_ID, seg_predicted ); + temporal_predictor_count[pred_context][seg_predicted]++; + + if ( !seg_predicted ) + // Update the "unpredicted" segment count + t_unpred_seg_counts[segment_id]++; + } + + // Step on to the next mb + xd->mode_info_context++; + + // Step on to the next entry in the segment maps + segmap_index++; + } + + // this is to account for the border in mode_info_context + xd->mode_info_context++; + } + + // Work out probability tree for coding segments without prediction + // and the cost. + calc_segtree_probs( xd, no_pred_segcounts, no_pred_tree ); + no_pred_cost = cost_segmap( xd, no_pred_segcounts, no_pred_tree ); + + // Key frames cannot use temporal prediction + if (cm->frame_type != KEY_FRAME) + { + // Work out probability tree for coding those segments not + // predicted using the temporal method and the cost. + calc_segtree_probs( xd, t_unpred_seg_counts, t_pred_tree ); + t_pred_cost = cost_segmap( xd, t_unpred_seg_counts, t_pred_tree ); + + // Add in the cost of the signalling for each prediction context + for ( i = 0; i < PREDICTION_PROBS; i++ ) + { + tot_count = temporal_predictor_count[i][0] + + temporal_predictor_count[i][1]; + + // Work out the context probabilities for the segment + // prediction flag + if ( tot_count ) + { + t_nopred_prob[i] = ( temporal_predictor_count[i][0] * 255 ) / + tot_count; + + // Clamp to minimum allowed value + if ( t_nopred_prob[i] < 1 ) + t_nopred_prob[i] = 1; + } + else + t_nopred_prob[i] = 1; + + // Add in the predictor signaling cost + t_pred_cost += ( temporal_predictor_count[i][0] * + vp8_cost_zero(t_nopred_prob[i]) ) + + ( temporal_predictor_count[i][1] * + vp8_cost_one(t_nopred_prob[i]) ); + } + } + + // Now choose which coding method to use. + if ( t_pred_cost < no_pred_cost ) + { + cm->temporal_update = 1; + vpx_memcpy( xd->mb_segment_tree_probs, + t_pred_tree, sizeof(t_pred_tree) ); + vpx_memcpy( &cm->segment_pred_probs, + t_nopred_prob, sizeof(t_nopred_prob) ); + } + else + { + cm->temporal_update = 0; + vpx_memcpy( xd->mb_segment_tree_probs, + no_pred_tree, sizeof(no_pred_tree) ); + } +} diff --git a/vp8/encoder/segmentation.h b/vp8/encoder/segmentation.h index 12815b087..a7e1f7cfe 100644 --- a/vp8/encoder/segmentation.h +++ b/vp8/encoder/segmentation.h @@ -13,4 +13,31 @@ #include "vp8/common/blockd.h" #include "onyx_int.h" +#ifndef __INC_SEGMENTATION_H__ +#define __INC_SEGMENTATION_H__ 1 + extern void vp8_update_gf_useage_maps(VP8_COMP *cpi, VP8_COMMON *cm, MACROBLOCK *x); + +extern void vp8_enable_segmentation(VP8_PTR ptr); +extern void vp8_disable_segmentation(VP8_PTR ptr); + +// Valid values for a segment are 0 to 3 +// Segmentation map is arrange as [Rows][Columns] +extern void vp8_set_segmentation_map(VP8_PTR ptr, unsigned char *segmentation_map); + +// The values given for each segment can be either deltas (from the default +// value chosen for the frame) or absolute values. +// +// Valid range for abs values is (0-127 for MB_LVL_ALT_Q) , (0-63 for +// SEGMENT_ALT_LF) +// Valid range for delta values are (+/-127 for MB_LVL_ALT_Q) , (+/-63 for +// SEGMENT_ALT_LF) +// +// abs_delta = SEGMENT_DELTADATA (deltas) abs_delta = SEGMENT_ABSDATA (use +// the absolute values given). +// +extern void vp8_set_segment_data(VP8_PTR ptr, signed char *feature_data, unsigned char abs_delta); + +extern void choose_segmap_coding_method( VP8_COMP *cpi ); + +#endif /* __INC_SEGMENTATION_H__ */ diff --git a/vp8/encoder/temporal_filter.c b/vp8/encoder/temporal_filter.c index b9ade1c6c..7440883e0 100644 --- a/vp8/encoder/temporal_filter.c +++ b/vp8/encoder/temporal_filter.c @@ -26,7 +26,6 @@ #include "vpx_scale/yv12extend.h" #include "vpx_mem/vpx_mem.h" #include "vp8/common/swapyv12buffer.h" -#include "vp8/common/threading.h" #include "vpx_ports/vpx_timer.h" #include @@ -37,6 +36,7 @@ #if VP8_TEMPORAL_ALT_REF + static void vp8_temporal_filter_predictors_mb_c ( MACROBLOCKD *x, @@ -51,14 +51,20 @@ static void vp8_temporal_filter_predictors_mb_c { int offset; unsigned char *yptr, *uptr, *vptr; + int omv_row, omv_col; // Y yptr = y_mb_ptr + (mv_row >> 3) * stride + (mv_col >> 3); if ((mv_row | mv_col) & 7) { +#if CONFIG_SIXTEENTH_SUBPEL_UV x->subpixel_predict16x16(yptr, stride, - mv_col & 7, mv_row & 7, &pred[0], 16); + (mv_col & 7)<<1, (mv_row & 7)<<1, &pred[0], 16); +#else + x->subpixel_predict16x16(yptr, stride, + mv_col & 7, mv_row & 7, &pred[0], 16); +#endif } else { @@ -66,6 +72,8 @@ static void vp8_temporal_filter_predictors_mb_c } // U & V + omv_row = mv_row; + omv_col = mv_col; mv_row >>= 1; mv_col >>= 1; stride = (stride + 1) >> 1; @@ -73,6 +81,15 @@ static void vp8_temporal_filter_predictors_mb_c uptr = u_mb_ptr + offset; vptr = v_mb_ptr + offset; +#if CONFIG_SIXTEENTH_SUBPEL_UV + if ((omv_row | omv_col) & 15) + { + x->subpixel_predict8x8(uptr, stride, + (omv_col & 15), (omv_row & 15), &pred[256], 8); + x->subpixel_predict8x8(vptr, stride, + (omv_col & 15), (omv_row & 15), &pred[320], 8); + } +#else if ((mv_row | mv_col) & 7) { x->subpixel_predict8x8(uptr, stride, @@ -80,6 +97,7 @@ static void vp8_temporal_filter_predictors_mb_c x->subpixel_predict8x8(vptr, stride, mv_col & 7, mv_row & 7, &pred[320], 8); } +#endif else { RECON_INVOKE(&x->rtcd->recon, copy8x8)(uptr, stride, &pred[256], 8); @@ -98,7 +116,7 @@ void vp8_temporal_filter_apply_c unsigned short *count ) { - int i, j, k; + unsigned int i, j, k; int modifier; int byte = 0; @@ -137,6 +155,9 @@ void vp8_temporal_filter_apply_c #if ALT_REF_MC_ENABLED static int dummy_cost[2*mv_max+1]; +#if CONFIG_HIGH_PRECISION_MV +static int dummy_cost_hp[2*mv_max_hp+1]; +#endif static int vp8_temporal_filter_find_matching_mb_c ( @@ -160,6 +181,10 @@ static int vp8_temporal_filter_find_matching_mb_c int *mvcost[2] = { &dummy_cost[mv_max+1], &dummy_cost[mv_max+1] }; int *mvsadcost[2] = { &dummy_cost[mv_max+1], &dummy_cost[mv_max+1] }; +#if CONFIG_HIGH_PRECISION_MV + int *mvcost_hp[2] = { &dummy_cost_hp[mv_max_hp+1], &dummy_cost_hp[mv_max_hp+1] }; + int *mvsadcost_hp[2] = { &dummy_cost_hp[mv_max_hp+1], &dummy_cost_hp[mv_max_hp+1] }; +#endif // Save input state unsigned char **base_src = b->base_src; @@ -203,7 +228,13 @@ static int vp8_temporal_filter_find_matching_mb_c step_param, sadpb, &cpi->fn_ptr[BLOCK_16X16], - mvsadcost, mvcost, &best_ref_mv1); +#if CONFIG_HIGH_PRECISION_MV + x->e_mbd.allow_high_precision_mv?mvsadcost_hp:mvsadcost, + x->e_mbd.allow_high_precision_mv?mvcost_hp:mvcost, +#else + mvsadcost, mvcost, +#endif + &best_ref_mv1); #if ALT_REF_SUBPEL_ENABLED // Try sub-pixel MC? @@ -214,7 +245,12 @@ static int vp8_temporal_filter_find_matching_mb_c bestsme = cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv, &best_ref_mv1, x->errorperbit, &cpi->fn_ptr[BLOCK_16X16], - mvcost, &distortion, &sse); +#if CONFIG_HIGH_PRECISION_MV + x->e_mbd.allow_high_precision_mv?mvcost_hp:mvcost, +#else + mvcost, +#endif + &distortion, &sse); } #endif @@ -263,17 +299,17 @@ static void vp8_temporal_filter_iterate_c #if ALT_REF_MC_ENABLED // Source frames are extended to 16 pixels. This is different than // L/A/G reference frames that have a border of 32 (VP8BORDERINPIXELS) - // A 6 tap filter is used for motion search. This requires 2 pixels + // A 6/8 tap filter is used for motion search. This requires 2 pixels // before and 3 pixels after. So the largest Y mv on a border would - // then be 16 - 3. The UV blocks are half the size of the Y and + // then be 16 - INTERP_EXTEND. The UV blocks are half the size of the Y and // therefore only extended by 8. The largest mv that a UV block - // can support is 8 - 3. A UV mv is half of a Y mv. - // (16 - 3) >> 1 == 6 which is greater than 8 - 3. + // can support is 8 - INTERP_EXTEND. A UV mv is half of a Y mv. + // (16 - INTERP_EXTEND) >> 1 which is greater than 8 - INTERP_EXTEND. // To keep the mv in play for both Y and UV planes the max that it - // can be on a border is therefore 16 - 5. - cpi->mb.mv_row_min = -((mb_row * 16) + (16 - 5)); + // can be on a border is therefore 16 - (2*INTERP_EXTEND+1). + cpi->mb.mv_row_min = -((mb_row * 16) + (17 - 2*INTERP_EXTEND)); cpi->mb.mv_row_max = ((cpi->common.mb_rows - 1 - mb_row) * 16) - + (16 - 5); + + (17 - 2*INTERP_EXTEND); #endif for (mb_col = 0; mb_col < mb_cols; mb_col++) @@ -285,9 +321,9 @@ static void vp8_temporal_filter_iterate_c vpx_memset(count, 0, 384*sizeof(unsigned short)); #if ALT_REF_MC_ENABLED - cpi->mb.mv_col_min = -((mb_col * 16) + (16 - 5)); + cpi->mb.mv_col_min = -((mb_col * 16) + (17 - 2*INTERP_EXTEND)); cpi->mb.mv_col_max = ((cpi->common.mb_cols - 1 - mb_col) * 16) - + (16 - 5); + + (17 - 2*INTERP_EXTEND); #endif for (frame = 0; frame < frame_count; frame++) diff --git a/vp8/encoder/tokenize.c b/vp8/encoder/tokenize.c index 15e7336b1..c86e022ba 100644 --- a/vp8/encoder/tokenize.c +++ b/vp8/encoder/tokenize.c @@ -17,23 +17,30 @@ #include "tokenize.h" #include "vpx_mem/vpx_mem.h" +#include "vp8/common/seg_common.h" + /* Global event counters used for accumulating statistics across several compressions, then generating context.c = initial stats. */ #ifdef ENTROPY_STATS _int64 context_counters[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; +_int64 context_counters_8x8[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; #endif void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) ; +void vp8_stuff_mb_8x8(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) ; void vp8_fix_contexts(MACROBLOCKD *x); static TOKENVALUE dct_value_tokens[DCT_MAX_VALUE*2]; const TOKENVALUE *vp8_dct_value_tokens_ptr; static int dct_value_cost[DCT_MAX_VALUE*2]; const int *vp8_dct_value_cost_ptr; -#if 0 -int skip_true_count = 0; -int skip_false_count = 0; + +#ifdef ENC_DEBUG +extern int mb_row_debug; +extern int mb_col_debug; +extern int enc_debug; #endif + static void fill_value_tokens() { @@ -93,9 +100,81 @@ static void fill_value_tokens() vp8_dct_value_cost_ptr = dct_value_cost + DCT_MAX_VALUE; } +static void tokenize2nd_order_b_8x8 +( + MACROBLOCKD *xd, + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + int c = 0; /* start at DC */ + const int eob = b->eob; /* one beyond last nonzero coeff */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + int x; + const short *qcoeff_ptr = b->qcoeff; + + int seg_eob = 4; + int segment_id = xd->mode_info_context->mbmi.segment_id; + + if ( segfeature_active( xd, segment_id, SEG_LVL_EOB ) ) + { + seg_eob = get_segdata( xd, segment_id, SEG_LVL_EOB ); + } + + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + assert(eob<=4); + + do + { + const int band = vp8_coef_bands[c]; + + if (c < eob) + { + int rc = vp8_default_zig_zag1d[c]; + const int v = qcoeff_ptr[rc]; + + assert(-DCT_MAX_VALUE <= v && v < (DCT_MAX_VALUE)); + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + x = vp8_dct_value_tokens_ptr[v].Token; + } + else + x = DCT_EOB_TOKEN; + + t->Token = x; + //printf("Token : %d\n", x); + t->context_tree = cpi->common.fc.coef_probs_8x8 [type] [band] [pt]; + + t->skip_eob_node = pt == 0 && ((band > 0 && type > 0) || (band > 1 && type == 0)); + +#ifdef ENC_DEBUG + if (t->skip_eob_node && vp8_coef_encodings[x].Len==1) + printf("Trouble 2 x=%d Len=%d skip=%d eob=%d c=%d band=%d type=%d: [%d %d %d]\n", + x, vp8_coef_encodings[x].Len, t->skip_eob_node, eob, c, band, type, + cpi->count, mb_row_debug, mb_col_debug); +#endif + + ++cpi->coef_counts_8x8 [type] [band] [pt] [x]; + } + while (pt = vp8_prev_token_class[x], ++t, c < eob && ++c all coeff data is zero */ + *a = *l = pt; + +} + static void tokenize2nd_order_b ( - MACROBLOCKD *x, + MACROBLOCKD *xd, TOKENEXTRA **tp, VP8_COMP *cpi ) @@ -109,10 +188,18 @@ static void tokenize2nd_order_b ENTROPY_CONTEXT * l; int band, rc, v, token; - b = x->block + 24; + int seg_eob = 16; + int segment_id = xd->mode_info_context->mbmi.segment_id; + + if ( segfeature_active( xd, segment_id, SEG_LVL_EOB ) ) + { + seg_eob = get_segdata( xd, segment_id, SEG_LVL_EOB ); + } + + b = xd->block + 24; qcoeff_ptr = b->qcoeff; - a = (ENTROPY_CONTEXT *)x->above_context + 8; - l = (ENTROPY_CONTEXT *)x->left_context + 8; + a = (ENTROPY_CONTEXT *)xd->above_context + 8; + l = (ENTROPY_CONTEXT *)xd->left_context + 8; VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); @@ -135,7 +222,8 @@ static void tokenize2nd_order_b pt = vp8_prev_token_class[token]; t++; } - if (c < 16) + + if (c < seg_eob) { band = vp8_coef_bands[c]; t->Token = DCT_EOB_TOKEN; @@ -154,9 +242,77 @@ static void tokenize2nd_order_b } +static void tokenize1st_order_b_8x8 +( + MACROBLOCKD *xd, + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + int c = type ? 0 : 1; /* start at DC unless type 0 */ + const int eob = b->eob; /* one beyond last nonzero coeff */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + int x; + const short *qcoeff_ptr = b->qcoeff; + + int seg_eob = 64; + int segment_id = xd->mode_info_context->mbmi.segment_id; + + if ( segfeature_active( xd, segment_id, SEG_LVL_EOB ) ) + { + seg_eob = get_segdata( xd, segment_id, SEG_LVL_EOB ); + } + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + do + { + const int band = vp8_coef_bands_8x8[c]; + + x = DCT_EOB_TOKEN; + + if (c < eob) + { + int rc = vp8_default_zig_zag1d_8x8[c]; + const int v = qcoeff_ptr[rc]; + + assert(-DCT_MAX_VALUE <= v && v < (DCT_MAX_VALUE)); + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + x = vp8_dct_value_tokens_ptr[v].Token; + } + + t->Token = x; + t->context_tree = cpi->common.fc.coef_probs_8x8 [type] [band] [pt]; + + t->skip_eob_node = pt == 0 && ((band > 0 && type > 0) || (band > 1 && type == 0)); + +#ifdef ENC_DEBUG + if (t->skip_eob_node && vp8_coef_encodings[x].Len==1) + printf("Trouble 1 x=%d Len=%d skip=%d eob=%d c=%d band=%d type=%d: [%d %d %d]\n", x, vp8_coef_encodings[x].Len, t->skip_eob_node, eob, c, band, type, cpi->count, mb_row_debug, mb_col_debug); +#endif + + ++cpi->coef_counts_8x8 [type] [band] [pt] [x]; + } + while (pt = vp8_prev_token_class[x], ++t, c < eob && ++c < seg_eob); + + *tp = t; + pt = (c != !type); /* 0 <-> all coeff data is zero */ + *a = *l = pt; +} + + + + static void tokenize1st_order_b ( - MACROBLOCKD *x, + MACROBLOCKD *xd, TOKENEXTRA **tp, int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ VP8_COMP *cpi @@ -174,15 +330,23 @@ static void tokenize1st_order_b int band, rc, v; int tmp1, tmp2; - b = x->block; + int seg_eob = 16; + int segment_id = xd->mode_info_context->mbmi.segment_id; + + if ( segfeature_active( xd, segment_id, SEG_LVL_EOB ) ) + { + seg_eob = get_segdata( xd, segment_id, SEG_LVL_EOB ); + } + + b = xd->block; /* Luma */ for (block = 0; block < 16; block++, b++) { tmp1 = vp8_block2above[block]; tmp2 = vp8_block2left[block]; qcoeff_ptr = b->qcoeff; - a = (ENTROPY_CONTEXT *)x->above_context + tmp1; - l = (ENTROPY_CONTEXT *)x->left_context + tmp2; + a = (ENTROPY_CONTEXT *)xd->above_context + tmp1; + l = (ENTROPY_CONTEXT *)xd->left_context + tmp2; VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); @@ -208,7 +372,8 @@ static void tokenize1st_order_b pt = vp8_prev_token_class[token]; t++; } - if (c < 16) + + if (c < seg_eob) { band = vp8_coef_bands[c]; t->Token = DCT_EOB_TOKEN; @@ -232,8 +397,8 @@ static void tokenize1st_order_b tmp1 = vp8_block2above[block]; tmp2 = vp8_block2left[block]; qcoeff_ptr = b->qcoeff; - a = (ENTROPY_CONTEXT *)x->above_context + tmp1; - l = (ENTROPY_CONTEXT *)x->left_context + tmp2; + a = (ENTROPY_CONTEXT *)xd->above_context + tmp1; + l = (ENTROPY_CONTEXT *)xd->left_context + tmp2; VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); @@ -256,7 +421,8 @@ static void tokenize1st_order_b pt = vp8_prev_token_class[token]; t++; } - if (c < 16) + + if (c < seg_eob) { band = vp8_coef_bands[c]; t->Token = DCT_EOB_TOKEN; @@ -276,7 +442,7 @@ static void tokenize1st_order_b } -static int mb_is_skippable(MACROBLOCKD *x, int has_y2_block) +int mby_is_skippable(MACROBLOCKD *x, int has_y2_block) { int skip = 1; int i = 0; @@ -285,30 +451,95 @@ static int mb_is_skippable(MACROBLOCKD *x, int has_y2_block) { for (i = 0; i < 16; i++) skip &= (x->block[i].eob < 2); + skip &= (!x->block[24].eob); + } + else + { + for (i = 0; i < 16; i++) + skip &= (!x->block[i].eob); } - - for (; i < 24 + has_y2_block; i++) - skip &= (!x->block[i].eob); - return skip; } +int mbuv_is_skippable(MACROBLOCKD *x) +{ + int skip = 1; + int i; + + for (i = 16; i < 24; i++) + skip &= (!x->block[i].eob); + return skip; +} + +int mb_is_skippable(MACROBLOCKD *x, int has_y2_block) +{ + return (mby_is_skippable(x, has_y2_block) & + mbuv_is_skippable(x)); +} + +int mby_is_skippable_8x8(MACROBLOCKD *x) +{ + int skip = 1; + int i = 0; + + for (i = 0; i < 16; i+=4) + skip &= (x->block[i].eob < 2); + skip &= (!x->block[24].eob); + return skip; +} + +int mbuv_is_skippable_8x8(MACROBLOCKD *x) +{ + return (!x->block[16].eob) & (!x->block[20].eob); +} + +int mb_is_skippable_8x8(MACROBLOCKD *x) +{ + return (mby_is_skippable_8x8(x) & mbuv_is_skippable_8x8(x)); +} + void vp8_tokenize_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) { int plane_type; int has_y2_block; + int b; + int tx_type = x->mode_info_context->mbmi.txfm_size; + + // If the MB is going to be skipped because of a segment level flag + // exclude this from the skip count stats used to calculate the + // transmitted skip probability; + int skip_inc; + int segment_id = x->mode_info_context->mbmi.segment_id; + + if ( !segfeature_active( x, segment_id, SEG_LVL_EOB ) || + ( get_segdata( x, segment_id, SEG_LVL_EOB ) != 0) ) + { + skip_inc = 1; + } + else + skip_inc = 0; has_y2_block = (x->mode_info_context->mbmi.mode != B_PRED + && x->mode_info_context->mbmi.mode != I8X8_PRED && x->mode_info_context->mbmi.mode != SPLITMV); - x->mode_info_context->mbmi.mb_skip_coeff = mb_is_skippable(x, has_y2_block); + x->mode_info_context->mbmi.mb_skip_coeff = + (( tx_type == TX_8X8 ) ? + mb_is_skippable_8x8(x) : + mb_is_skippable(x, has_y2_block)); + if (x->mode_info_context->mbmi.mb_skip_coeff) { - cpi->skip_true_count++; + cpi->skip_true_count += skip_inc; if (!cpi->common.mb_no_coeff_skip) - vp8_stuff_mb(cpi, x, t) ; + { + if ( tx_type == TX_8X8 ) + vp8_stuff_mb_8x8(cpi, x, t) ; + else + vp8_stuff_mb(cpi, x, t) ; + } else { vp8_fix_contexts(x); @@ -317,18 +548,55 @@ void vp8_tokenize_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) return; } - cpi->skip_false_count++; + cpi->skip_false_count += skip_inc; plane_type = 3; if(has_y2_block) { - tokenize2nd_order_b(x, t, cpi); - plane_type = 0; + if ( tx_type == TX_8X8 ) + { + ENTROPY_CONTEXT * A = (ENTROPY_CONTEXT *)x->above_context; + ENTROPY_CONTEXT * L = (ENTROPY_CONTEXT *)x->left_context; + tokenize2nd_order_b_8x8(x, + x->block + 24, t, 1, x->frame_type, + A + vp8_block2above_8x8[24], + L + vp8_block2left_8x8[24], cpi); + } + else + tokenize2nd_order_b(x, t, cpi); + + plane_type = 0; } - tokenize1st_order_b(x, t, plane_type, cpi); + if ( tx_type == TX_8X8 ) + { + ENTROPY_CONTEXT * A = (ENTROPY_CONTEXT *)x->above_context; + ENTROPY_CONTEXT * L = (ENTROPY_CONTEXT *)x->left_context; + for (b = 0; b < 16; b+=4) + { + tokenize1st_order_b_8x8(x, + x->block + b, t, plane_type, x->frame_type, + A + vp8_block2above_8x8[b], + L + vp8_block2left_8x8[b], + cpi); + *(A + vp8_block2above_8x8[b] + 1) = *(A + vp8_block2above_8x8[b]); + *(L + vp8_block2left_8x8[b] + 1) = *(L + vp8_block2left_8x8[b] ); + } + for (b = 16; b < 24; b+=4) + { + tokenize1st_order_b_8x8(x, + x->block + b, t, 2, x->frame_type, + A + vp8_block2above_8x8[b], + L + vp8_block2left_8x8[b], + cpi); + *(A + vp8_block2above_8x8[b]+1) = *(A + vp8_block2above_8x8[b]); + *(L + vp8_block2left_8x8[b]+1 ) = *(L + vp8_block2left_8x8[b]); + } + } + else + tokenize1st_order_b(x, t, plane_type, cpi); } @@ -337,6 +605,7 @@ void vp8_tokenize_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) void init_context_counters(void) { vpx_memset(context_counters, 0, sizeof(context_counters)); + vpx_memset(context_counters_8x8, 0, sizeof(context_counters_8x8)); } void print_context_counters() @@ -358,6 +627,54 @@ void print_context_counters() type = 0; + do + { + fprintf(f, "%s\n { /* block Type %d */", Comma(type), type); + + band = 0; + + do + { + fprintf(f, "%s\n { /* Coeff Band %d */", Comma(band), band); + + pt = 0; + + do + { + fprintf(f, "%s\n {", Comma(pt)); + + t = 0; + + do + { + const _int64 x = context_counters [type] [band] [pt] [t]; + const int y = (int) x; + + assert(x == (INT64) y); /* no overflow handling yet */ + fprintf(f, "%s %d", Comma(t), y); + + } + while (++t < MAX_ENTROPY_TOKENS); + + fprintf(f, "}"); + } + while (++pt < PREV_COEF_CONTEXTS); + + fprintf(f, "\n }"); + + } + while (++band < COEF_BANDS); + + fprintf(f, "\n }"); + } + while (++type < BLOCK_TYPES); + + fprintf(f, "int Contexts_8x8[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS];\n\n"); + + fprintf(f, "const int default_contexts_8x8[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS] = {"); + + type = 0; + do { fprintf(f, "%s\n { /* block Type %d */", Comma(type), type); @@ -412,6 +729,133 @@ void vp8_tokenize_initialize() } +static __inline void stuff2nd_order_b_8x8 +( + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + (void) frametype; + (void) type; + (void) b; + + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs_8x8 [1] [0] [pt]; + //t->section = 11; + t->skip_eob_node = 0; + ++cpi->coef_counts_8x8 [1] [0] [pt] [DCT_EOB_TOKEN]; + ++t; + + *tp = t; + pt = 0; + *a = *l = pt; + +} + +static __inline void stuff1st_order_b_8x8 +( + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + (void) frametype; + (void) type; + (void) b; + + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs_8x8 [0] [1] [pt]; + //t->section = 8; + t->skip_eob_node = 0; + ++cpi->coef_counts_8x8 [0] [1] [pt] [DCT_EOB_TOKEN]; + ++t; + *tp = t; + pt = 0; /* 0 <-> all coeff data is zero */ + *a = *l = pt; + + +} + +static __inline +void stuff1st_order_buv_8x8 +( + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + (void) frametype; + (void) type; + (void) b; + + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs_8x8 [2] [0] [pt]; + //t->section = 13; + t->skip_eob_node = 0; + ++cpi->coef_counts_8x8[2] [0] [pt] [DCT_EOB_TOKEN]; + ++t; + *tp = t; + pt = 0; /* 0 <-> all coeff data is zero */ + *a = *l = pt; + +} + +void vp8_stuff_mb_8x8(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) +{ + ENTROPY_CONTEXT * A = (ENTROPY_CONTEXT *)x->above_context; + ENTROPY_CONTEXT * L = (ENTROPY_CONTEXT *)x->left_context; + int plane_type; + int b; + + stuff2nd_order_b_8x8(x->block + 24, t, 1, x->frame_type, + A + vp8_block2above_8x8[24], + L + vp8_block2left_8x8[24], cpi); + plane_type = 0; + + for (b = 0; b < 16; b+=4) + { + stuff1st_order_b_8x8(x->block + b, t, plane_type, x->frame_type, + A + vp8_block2above_8x8[b], + L + vp8_block2left_8x8[b], + cpi); + *(A + vp8_block2above_8x8[b] + 1) = *(A + vp8_block2above_8x8[b]); + *(L + vp8_block2left_8x8[b] + 1) = *(L + vp8_block2left_8x8[b] ); + } + + for (b = 16; b < 24; b+=4) + { + stuff1st_order_buv_8x8(x->block + b, t, 2, x->frame_type, + A + vp8_block2above[b], + L + vp8_block2left[b], + cpi); + *(A + vp8_block2above_8x8[b]+1) = *(A + vp8_block2above_8x8[b]); + *(L + vp8_block2left_8x8[b]+1 ) = *(L + vp8_block2left_8x8[b]); + } +} + + static __inline void stuff2nd_order_b ( TOKENEXTRA **tp, @@ -507,7 +951,9 @@ void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) void vp8_fix_contexts(MACROBLOCKD *x) { /* Clear entropy contexts for Y2 blocks */ - if (x->mode_info_context->mbmi.mode != B_PRED && x->mode_info_context->mbmi.mode != SPLITMV) + if (x->mode_info_context->mbmi.mode != B_PRED + && x->mode_info_context->mbmi.mode != I8X8_PRED + && x->mode_info_context->mbmi.mode != SPLITMV) { vpx_memset(x->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); vpx_memset(x->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); diff --git a/vp8/encoder/tokenize.h b/vp8/encoder/tokenize.h index 04a8879cf..0608102d0 100644 --- a/vp8/encoder/tokenize.h +++ b/vp8/encoder/tokenize.h @@ -33,13 +33,20 @@ typedef struct int rd_cost_mby(MACROBLOCKD *); +extern int mby_is_skippable(MACROBLOCKD *x,int has_y2_block); +extern int mbuv_is_skippable(MACROBLOCKD *x); +extern int mb_is_skippable(MACROBLOCKD *x,int has_y2_block); +extern int mby_is_skippable_8x8(MACROBLOCKD *x); +extern int mbuv_is_skippable_8x8(MACROBLOCKD *x); +extern int mb_is_skippable_8x8(MACROBLOCKD *x); + #ifdef ENTROPY_STATS void init_context_counters(); void print_context_counters(); extern _int64 context_counters[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; +extern _int64 context_counters_8x8[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; #endif - extern const int *vp8_dct_value_cost_ptr; /* TODO: The Token field should be broken out into a separate char array to * improve cache locality, since it's needed for costing when the rest of the diff --git a/vp8/encoder/treewriter.c b/vp8/encoder/treewriter.c index 03967c835..3a777f222 100644 --- a/vp8/encoder/treewriter.c +++ b/vp8/encoder/treewriter.c @@ -37,3 +37,9 @@ void vp8_cost_tokens(int *c, const vp8_prob *p, vp8_tree t) { cost(c, t, p, 0, 0); } + +void vp8_cost_tokens_skip(int *c, const vp8_prob *p, vp8_tree t) +{ + cost(c, t, p, 2, 0); +} + diff --git a/vp8/encoder/variance.h b/vp8/encoder/variance.h index d9bf66975..fde8ade09 100644 --- a/vp8/encoder/variance.h +++ b/vp8/encoder/variance.h @@ -315,11 +315,6 @@ extern prototype_getmbss(vp8_variance_getmbss); #endif extern prototype_variance(vp8_variance_mse16x16); -#ifndef vp8_variance_get4x4sse_cs -#define vp8_variance_get4x4sse_cs vp8_get4x4sse_cs_c -#endif -extern prototype_get16x16prederror(vp8_variance_get4x4sse_cs); - #ifndef vp8_ssimpf_8x8 #define vp8_ssimpf_8x8 vp8_ssim_parms_8x8_c #endif @@ -330,6 +325,11 @@ extern prototype_ssimpf(vp8_ssimpf_8x8) #endif extern prototype_ssimpf(vp8_ssimpf_16x16) +#ifndef vp8_variance_satd16x16 +#define vp8_variance_satd16x16 vp8_satd16x16_c +#endif +extern prototype_variance(vp8_variance_satd16x16); + typedef prototype_sad(*vp8_sad_fn_t); typedef prototype_sad_multi_same_address(*vp8_sad_multi_fn_t); typedef prototype_sad_multi_same_address_1(*vp8_sad_multi1_fn_t); @@ -368,8 +368,6 @@ typedef struct vp8_getmbss_fn_t getmbss; vp8_variance_fn_t mse16x16; - vp8_get16x16prederror_fn_t get4x4sse_cs; - vp8_sad_multi_fn_t sad16x16x3; vp8_sad_multi_fn_t sad16x8x3; vp8_sad_multi_fn_t sad8x16x3; @@ -397,6 +395,7 @@ typedef struct vp8_ssimpf_fn_t ssimpf_16x16; #endif + vp8_variance_fn_t satd16x16; } vp8_variance_rtcd_vtable_t; typedef struct diff --git a/vp8/encoder/variance_c.c b/vp8/encoder/variance_c.c index c7b9c2209..402ff0450 100644 --- a/vp8/encoder/variance_c.c +++ b/vp8/encoder/variance_c.c @@ -363,8 +363,13 @@ unsigned int vp8_variance_halfpixvar16x16_h_c( int recon_stride, unsigned int *sse) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 8, 0, + ref_ptr, recon_stride, sse); +#else return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 4, 0, ref_ptr, recon_stride, sse); +#endif } @@ -375,8 +380,13 @@ unsigned int vp8_variance_halfpixvar16x16_v_c( int recon_stride, unsigned int *sse) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 0, 8, + ref_ptr, recon_stride, sse); +#else return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 0, 4, ref_ptr, recon_stride, sse); +#endif } @@ -387,8 +397,13 @@ unsigned int vp8_variance_halfpixvar16x16_hv_c( int recon_stride, unsigned int *sse) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 8, 8, + ref_ptr, recon_stride, sse); +#else return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 4, 4, ref_ptr, recon_stride, sse); +#endif } diff --git a/vp8/encoder/x86/variance_impl_sse2.asm b/vp8/encoder/x86/variance_impl_sse2.asm index 762922091..b13beee6e 100644 --- a/vp8/encoder/x86/variance_impl_sse2.asm +++ b/vp8/encoder/x86/variance_impl_sse2.asm @@ -1348,6 +1348,25 @@ align 16 xmm_bi_rd: times 8 dw 64 align 16 +%if CONFIG_SIXTEENTH_SUBPEL_UV +vp8_bilinear_filters_sse2: + dw 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0 + dw 120, 120, 120, 120, 120, 120, 120, 120, 8, 8, 8, 8, 8, 8, 8, 8 + dw 112, 112, 112, 112, 112, 112, 112, 112, 16, 16, 16, 16, 16, 16, 16, 16 + dw 104, 104, 104, 104, 104, 104, 104, 104, 24, 24, 24, 24, 24, 24, 24, 24 + dw 96, 96, 96, 96, 96, 96, 96, 96, 32, 32, 32, 32, 32, 32, 32, 32 + dw 88, 88, 88, 88, 88, 88, 88, 88, 40, 40, 40, 40, 40, 40, 40, 40 + dw 80, 80, 80, 80, 80, 80, 80, 80, 48, 48, 48, 48, 48, 48, 48, 48 + dw 72, 72, 72, 72, 72, 72, 72, 72, 56, 56, 56, 56, 56, 56, 56, 56 + dw 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + dw 56, 56, 56, 56, 56, 56, 56, 56, 72, 72, 72, 72, 72, 72, 72, 72 + dw 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80 + dw 40, 40, 40, 40, 40, 40, 40, 40, 88, 88, 88, 88, 88, 88, 88, 88 + dw 32, 32, 32, 32, 32, 32, 32, 32, 96, 96, 96, 96, 96, 96, 96, 96 + dw 24, 24, 24, 24, 24, 24, 24, 24, 104, 104, 104, 104, 104, 104, 104, 104 + dw 16, 16, 16, 16, 16, 16, 16, 16, 112, 112, 112, 112, 112, 112, 112, 112 + dw 8, 8, 8, 8, 8, 8, 8, 8, 120, 120, 120, 120, 120, 120, 120, 120 +%else vp8_bilinear_filters_sse2: dw 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0 dw 112, 112, 112, 112, 112, 112, 112, 112, 16, 16, 16, 16, 16, 16, 16, 16 @@ -1357,3 +1376,4 @@ vp8_bilinear_filters_sse2: dw 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80 dw 32, 32, 32, 32, 32, 32, 32, 32, 96, 96, 96, 96, 96, 96, 96, 96 dw 16, 16, 16, 16, 16, 16, 16, 16, 112, 112, 112, 112, 112, 112, 112, 112 +%endif diff --git a/vp8/encoder/x86/variance_impl_ssse3.asm b/vp8/encoder/x86/variance_impl_ssse3.asm index 97e8b0e2e..d60d53daa 100644 --- a/vp8/encoder/x86/variance_impl_ssse3.asm +++ b/vp8/encoder/x86/variance_impl_ssse3.asm @@ -353,6 +353,25 @@ align 16 xmm_bi_rd: times 8 dw 64 align 16 +%if CONFIG_SIXTEENTH_SUBPEL_UV +vp8_bilinear_filters_ssse3: + times 8 db 128, 0 + times 8 db 120, 8 + times 8 db 112, 16 + times 8 db 104, 24 + times 8 db 96, 32 + times 8 db 88, 40 + times 8 db 80, 48 + times 8 db 72, 56 + times 8 db 64, 64 + times 8 db 56, 72 + times 8 db 48, 80 + times 8 db 40, 88 + times 8 db 32, 96 + times 8 db 24, 104 + times 8 db 16, 112 + times 8 db 8, 120 +%else vp8_bilinear_filters_ssse3: times 8 db 128, 0 times 8 db 112, 16 @@ -362,3 +381,4 @@ vp8_bilinear_filters_ssse3: times 8 db 48, 80 times 8 db 32, 96 times 8 db 16, 112 +%endif diff --git a/vp8/encoder/x86/variance_mmx.c b/vp8/encoder/x86/variance_mmx.c index 92b695f17..b84d00034 100644 --- a/vp8/encoder/x86/variance_mmx.c +++ b/vp8/encoder/x86/variance_mmx.c @@ -204,6 +204,27 @@ unsigned int vp8_variance8x16_mmx( // the mmx function that does the bilinear filtering and var calculation // // int one pass // /////////////////////////////////////////////////////////////////////////// +#if CONFIG_SIXTEENTH_SUBPEL_UV +DECLARE_ALIGNED(16, const short, vp8_vp7_bilinear_filters_mmx[16][8]) = +{ + { 128, 128, 128, 128, 0, 0, 0, 0 }, + { 120, 120, 120, 120, 8, 8, 8, 8 }, + { 112, 112, 112, 112, 16, 16, 16, 16 }, + { 104, 104, 104, 104, 24, 24, 24, 24 }, + { 96, 96, 96, 96, 32, 32, 32, 32 }, + { 88, 88, 88, 88, 40, 40, 40, 40 }, + { 80, 80, 80, 80, 48, 48, 48, 48 }, + { 72, 72, 72, 72, 56, 56, 56, 56 }, + { 64, 64, 64, 64, 64, 64, 64, 64 }, + { 56, 56, 56, 56, 72, 72, 72, 72 }, + { 48, 48, 48, 48, 80, 80, 80, 80 }, + { 40, 40, 40, 40, 88, 88, 88, 88 }, + { 32, 32, 32, 32, 96, 96, 96, 96 }, + { 24, 24, 24, 24, 104, 104, 104, 104 }, + { 16, 16, 16, 16, 112, 112, 112, 112 }, + { 8, 8, 8, 8, 120, 120, 120, 120 } +}; +#else DECLARE_ALIGNED(16, const short, vp8_vp7_bilinear_filters_mmx[8][8]) = { { 128, 128, 128, 128, 0, 0, 0, 0 }, @@ -215,6 +236,7 @@ DECLARE_ALIGNED(16, const short, vp8_vp7_bilinear_filters_mmx[8][8]) = { 32, 32, 32, 32, 96, 96, 96, 96 }, { 16, 16, 16, 16, 112, 112, 112, 112 } }; +#endif unsigned int vp8_sub_pixel_variance4x4_mmx ( @@ -279,7 +301,6 @@ unsigned int vp8_sub_pixel_variance16x16_mmx int xsum0, xsum1; unsigned int xxsum0, xxsum1; - vp8_filter_block2d_bil_var_mmx( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 16, @@ -287,7 +308,6 @@ unsigned int vp8_sub_pixel_variance16x16_mmx &xsum0, &xxsum0 ); - vp8_filter_block2d_bil_var_mmx( src_ptr + 8, src_pixels_per_line, dst_ptr + 8, dst_pixels_per_line, 16, @@ -386,8 +406,13 @@ unsigned int vp8_variance_halfpixvar16x16_h_mmx( int recon_stride, unsigned int *sse) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 8, 0, + ref_ptr, recon_stride, sse); +#else return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 4, 0, ref_ptr, recon_stride, sse); +#endif } @@ -398,8 +423,13 @@ unsigned int vp8_variance_halfpixvar16x16_v_mmx( int recon_stride, unsigned int *sse) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 0, 8, + ref_ptr, recon_stride, sse); +#else return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 0, 4, ref_ptr, recon_stride, sse); +#endif } @@ -410,6 +440,11 @@ unsigned int vp8_variance_halfpixvar16x16_hv_mmx( int recon_stride, unsigned int *sse) { +#if CONFIG_SIXTEENTH_SUBPEL_UV + return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 8, 8, + ref_ptr, recon_stride, sse); +#else return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 4, 4, ref_ptr, recon_stride, sse); +#endif } diff --git a/vp8/encoder/x86/variance_sse2.c b/vp8/encoder/x86/variance_sse2.c index 24062eb9b..e3c6268ea 100644 --- a/vp8/encoder/x86/variance_sse2.c +++ b/vp8/encoder/x86/variance_sse2.c @@ -13,6 +13,12 @@ #include "vp8/common/pragmas.h" #include "vpx_ports/mem.h" +#if CONFIG_SIXTEENTH_SUBPEL_UV +#define HALFNDX 8 +#else +#define HALFNDX 4 +#endif + extern void filter_block1d_h6_mmx(const unsigned char *src_ptr, unsigned short *output_ptr, unsigned int src_pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *vp7_filter); extern void filter_block1d_v6_mmx(const short *src_ptr, unsigned char *output_ptr, unsigned int pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *vp7_filter); extern void filter_block1d8_h6_sse2(const unsigned char *src_ptr, unsigned short *output_ptr, unsigned int src_pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *vp7_filter); @@ -135,7 +141,11 @@ void vp8_half_vert_variance16x_h_sse2 unsigned int *sumsquared ); +#if CONFIG_SIXTEENTH_SUBPEL_UV +DECLARE_ALIGNED(16, extern short, vp8_vp7_bilinear_filters_mmx[16][8]); +#else DECLARE_ALIGNED(16, extern short, vp8_vp7_bilinear_filters_mmx[8][8]); +#endif unsigned int vp8_variance4x4_wmt( const unsigned char *src_ptr, @@ -284,21 +294,21 @@ unsigned int vp8_sub_pixel_variance8x8_wmt int xsum; unsigned int xxsum; - if (xoffset == 4 && yoffset == 0) + if (xoffset == HALFNDX && yoffset == 0) { vp8_half_horiz_variance8x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 8, &xsum, &xxsum); } - else if (xoffset == 0 && yoffset == 4) + else if (xoffset == 0 && yoffset == HALFNDX) { vp8_half_vert_variance8x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 8, &xsum, &xxsum); } - else if (xoffset == 4 && yoffset == 4) + else if (xoffset == HALFNDX && yoffset == HALFNDX) { vp8_half_horiz_vert_variance8x_h_sse2( src_ptr, src_pixels_per_line, @@ -335,21 +345,21 @@ unsigned int vp8_sub_pixel_variance16x16_wmt // note we could avoid these if statements if the calling function // just called the appropriate functions inside. - if (xoffset == 4 && yoffset == 0) + if (xoffset == HALFNDX && yoffset == 0) { vp8_half_horiz_variance16x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 16, &xsum0, &xxsum0); } - else if (xoffset == 0 && yoffset == 4) + else if (xoffset == 0 && yoffset == HALFNDX) { vp8_half_vert_variance16x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 16, &xsum0, &xxsum0); } - else if (xoffset == 4 && yoffset == 4) + else if (xoffset == HALFNDX && yoffset == HALFNDX) { vp8_half_horiz_vert_variance16x_h_sse2( src_ptr, src_pixels_per_line, @@ -408,21 +418,21 @@ unsigned int vp8_sub_pixel_variance16x8_wmt int xsum0, xsum1; unsigned int xxsum0, xxsum1; - if (xoffset == 4 && yoffset == 0) + if (xoffset == HALFNDX && yoffset == 0) { vp8_half_horiz_variance16x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 8, &xsum0, &xxsum0); } - else if (xoffset == 0 && yoffset == 4) + else if (xoffset == 0 && yoffset == HALFNDX) { vp8_half_vert_variance16x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 8, &xsum0, &xxsum0); } - else if (xoffset == 4 && yoffset == 4) + else if (xoffset == HALFNDX && yoffset == HALFNDX) { vp8_half_horiz_vert_variance16x_h_sse2( src_ptr, src_pixels_per_line, @@ -464,21 +474,21 @@ unsigned int vp8_sub_pixel_variance8x16_wmt int xsum; unsigned int xxsum; - if (xoffset == 4 && yoffset == 0) + if (xoffset == HALFNDX && yoffset == 0) { vp8_half_horiz_variance8x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 16, &xsum, &xxsum); } - else if (xoffset == 0 && yoffset == 4) + else if (xoffset == 0 && yoffset == HALFNDX) { vp8_half_vert_variance8x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 16, &xsum, &xxsum); } - else if (xoffset == 4 && yoffset == 4) + else if (xoffset == HALFNDX && yoffset == HALFNDX) { vp8_half_horiz_vert_variance8x_h_sse2( src_ptr, src_pixels_per_line, diff --git a/vp8/encoder/x86/variance_ssse3.c b/vp8/encoder/x86/variance_ssse3.c index 73f2e01a2..fc2a3c3f2 100644 --- a/vp8/encoder/x86/variance_ssse3.c +++ b/vp8/encoder/x86/variance_ssse3.c @@ -13,6 +13,12 @@ #include "vp8/common/pragmas.h" #include "vpx_ports/mem.h" +#if CONFIG_SIXTEENTH_SUBPEL_UV +#define HALFNDX 8 +#else +#define HALFNDX 4 +#endif + extern unsigned int vp8_get16x16var_sse2 ( const unsigned char *src_ptr, @@ -81,21 +87,21 @@ unsigned int vp8_sub_pixel_variance16x16_ssse3 // note we could avoid these if statements if the calling function // just called the appropriate functions inside. - if (xoffset == 4 && yoffset == 0) + if (xoffset == HALFNDX && yoffset == 0) { vp8_half_horiz_variance16x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 16, &xsum0, &xxsum0); } - else if (xoffset == 0 && yoffset == 4) + else if (xoffset == 0 && yoffset == HALFNDX) { vp8_half_vert_variance16x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 16, &xsum0, &xxsum0); } - else if (xoffset == 4 && yoffset == 4) + else if (xoffset == HALFNDX && yoffset == HALFNDX) { vp8_half_horiz_vert_variance16x_h_sse2( src_ptr, src_pixels_per_line, @@ -130,21 +136,21 @@ unsigned int vp8_sub_pixel_variance16x8_ssse3 int xsum0; unsigned int xxsum0; - if (xoffset == 4 && yoffset == 0) + if (xoffset == HALFNDX && yoffset == 0) { vp8_half_horiz_variance16x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 8, &xsum0, &xxsum0); } - else if (xoffset == 0 && yoffset == 4) + else if (xoffset == 0 && yoffset == HALFNDX) { vp8_half_vert_variance16x_h_sse2( src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, 8, &xsum0, &xxsum0); } - else if (xoffset == 4 && yoffset == 4) + else if (xoffset == HALFNDX && yoffset == HALFNDX) { vp8_half_horiz_vert_variance16x_h_sse2( src_ptr, src_pixels_per_line, diff --git a/vp8/encoder/x86/variance_x86.h b/vp8/encoder/x86/variance_x86.h index 4b41b5436..0971f11b0 100644 --- a/vp8/encoder/x86/variance_x86.h +++ b/vp8/encoder/x86/variance_x86.h @@ -42,7 +42,6 @@ extern prototype_subpixvariance(vp8_sub_pixel_mse16x16_mmx); extern prototype_getmbss(vp8_get_mb_ss_mmx); extern prototype_variance(vp8_mse16x16_mmx); extern prototype_variance2(vp8_get8x8var_mmx); -extern prototype_get16x16prederror(vp8_get4x4sse_cs_mmx); #if !CONFIG_RUNTIME_CPU_DETECT #undef vp8_variance_sad4x4 @@ -108,9 +107,6 @@ extern prototype_get16x16prederror(vp8_get4x4sse_cs_mmx); #undef vp8_variance_mse16x16 #define vp8_variance_mse16x16 vp8_mse16x16_mmx -#undef vp8_variance_get4x4sse_cs -#define vp8_variance_get4x4sse_cs vp8_get4x4sse_cs_mmx - #endif #endif diff --git a/vp8/encoder/x86/x86_csystemdependent.c b/vp8/encoder/x86/x86_csystemdependent.c index 191d61c60..0c30e3707 100644 --- a/vp8/encoder/x86/x86_csystemdependent.c +++ b/vp8/encoder/x86/x86_csystemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_ports/x86.h" #include "vp8/encoder/variance.h" #include "vp8/encoder/onyx_int.h" @@ -152,8 +152,6 @@ void vp8_arch_x86_encoder_init(VP8_COMP *cpi) cpi->rtcd.variance.mse16x16 = vp8_mse16x16_mmx; cpi->rtcd.variance.getmbss = vp8_get_mb_ss_mmx; - cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_mmx; - cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_mmx; cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_mmx; cpi->rtcd.fdct.fast4x4 = vp8_short_fdct4x4_mmx; @@ -201,8 +199,6 @@ void vp8_arch_x86_encoder_init(VP8_COMP *cpi) cpi->rtcd.variance.mse16x16 = vp8_mse16x16_wmt; cpi->rtcd.variance.getmbss = vp8_get_mb_ss_sse2; - /* cpi->rtcd.variance.get4x4sse_cs not implemented for wmt */; - cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_sse2; cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_sse2; cpi->rtcd.fdct.fast4x4 = vp8_short_fdct4x4_sse2; @@ -217,12 +213,8 @@ void vp8_arch_x86_encoder_init(VP8_COMP *cpi) cpi->rtcd.encodemb.submby = vp8_subtract_mby_sse2; cpi->rtcd.encodemb.submbuv = vp8_subtract_mbuv_sse2; - cpi->rtcd.quantize.quantb = vp8_regular_quantize_b_sse2; cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_sse2; - -#if !(CONFIG_REALTIME_ONLY) cpi->rtcd.temporal.apply = vp8_temporal_filter_apply_sse2; -#endif #if CONFIG_INTERNAL_STATS #if ARCH_X86_64 @@ -278,8 +270,6 @@ void vp8_arch_x86_encoder_init(VP8_COMP *cpi) cpi->rtcd.variance.sad8x8x8 = vp8_sad8x8x8_sse4; cpi->rtcd.variance.sad4x4x8 = vp8_sad4x4x8_sse4; cpi->rtcd.search.full_search = vp8_full_search_sadx8; - - cpi->rtcd.quantize.quantb = vp8_regular_quantize_b_sse4; } #endif diff --git a/vp8/vp8_common.mk b/vp8/vp8_common.mk index f7fbea1f4..de645eb8a 100644 --- a/vp8/vp8_common.mk +++ b/vp8/vp8_common.mk @@ -19,7 +19,6 @@ VP8_COMMON_SRCS-yes += common/asm_com_offsets.c VP8_COMMON_SRCS-yes += common/blockd.c VP8_COMMON_SRCS-yes += common/coefupdateprobs.h VP8_COMMON_SRCS-yes += common/debugmodes.c -VP8_COMMON_SRCS-yes += common/default_coef_probs.h VP8_COMMON_SRCS-yes += common/entropy.c VP8_COMMON_SRCS-yes += common/entropymode.c VP8_COMMON_SRCS-yes += common/entropymv.c @@ -33,6 +32,7 @@ VP8_COMMON_SRCS-yes += common/alloccommon.h VP8_COMMON_SRCS-yes += common/blockd.h VP8_COMMON_SRCS-yes += common/common.h VP8_COMMON_SRCS-yes += common/common_types.h +VP8_COMMON_SRCS-yes += common/defaultcoefcounts.h VP8_COMMON_SRCS-yes += common/entropy.h VP8_COMMON_SRCS-yes += common/entropymode.h VP8_COMMON_SRCS-yes += common/entropymv.h @@ -46,16 +46,19 @@ VP8_COMMON_SRCS-yes += common/loopfilter.h VP8_COMMON_SRCS-yes += common/modecont.h VP8_COMMON_SRCS-yes += common/mv.h VP8_COMMON_SRCS-yes += common/onyxc_int.h +VP8_COMMON_SRCS-yes += common/pred_common.h +VP8_COMMON_SRCS-yes += common/pred_common.c VP8_COMMON_SRCS-yes += common/quant_common.h VP8_COMMON_SRCS-yes += common/recon.h VP8_COMMON_SRCS-yes += common/reconinter.h VP8_COMMON_SRCS-yes += common/reconintra.h VP8_COMMON_SRCS-yes += common/reconintra4x4.h +VP8_COMMON_SRCS-yes += common/seg_common.h +VP8_COMMON_SRCS-yes += common/seg_common.c VP8_COMMON_SRCS-yes += common/setupintrarecon.h VP8_COMMON_SRCS-yes += common/subpixel.h VP8_COMMON_SRCS-yes += common/swapyv12buffer.h VP8_COMMON_SRCS-yes += common/systemdependent.h -VP8_COMMON_SRCS-yes += common/threading.h VP8_COMMON_SRCS-yes += common/treecoder.h VP8_COMMON_SRCS-yes += common/invtrans.c VP8_COMMON_SRCS-yes += common/loopfilter.c @@ -72,6 +75,10 @@ VP8_COMMON_SRCS-yes += common/setupintrarecon.c VP8_COMMON_SRCS-yes += common/swapyv12buffer.c VP8_COMMON_SRCS-$(CONFIG_POSTPROC_VISUALIZER) += common/textblit.c VP8_COMMON_SRCS-yes += common/treecoder.c +VP8_COMMON_SRCS-yes += common/implicit_segmentation.c +VP8_COMMON_SRCS-yes += common/predict_rotated.c +VP8_COMMON_SRCS-yes += common/rotate.h +VP8_COMMON_SRCS-yes += common/rotate2.h VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/idct_x86.h VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/subpixel_x86.h @@ -101,6 +108,11 @@ VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/postproc_sse2.asm endif # common (c) +ifeq ($(CONFIG_CSM),yes) +VP8_COMMON_SRCS-yes += common/maskingmv.c +VP8_COMMON_SRCS-$(HAVE_SSE3) += common/x86/mask_sse3.asm +endif + VP8_COMMON_SRCS-$(ARCH_ARM) += common/arm/arm_systemdependent.c VP8_COMMON_SRCS-$(ARCH_ARM) += common/arm/bilinearfilter_arm.c VP8_COMMON_SRCS-$(ARCH_ARM) += common/arm/bilinearfilter_arm.h diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index 9f703a3c4..4f34569e0 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -56,13 +56,8 @@ static const struct extraconfig_map extracfg_map[] = 0, { NULL, -#if !(CONFIG_REALTIME_ONLY) VP8_BEST_QUALITY_ENCODING, /* Encoding Mode */ 0, /* cpu_used */ -#else - VP8_REAL_TIME_ENCODING, /* Encoding Mode */ - 4, /* cpu_used */ -#endif 0, /* enable_auto_alt_ref */ 0, /* noise_sensitivity */ 0, /* Sharpness */ @@ -149,11 +144,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK_HI(cfg, rc_max_quantizer, 63); RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer); RANGE_CHECK_HI(cfg, g_threads, 64); -#if !(CONFIG_REALTIME_ONLY) RANGE_CHECK_HI(cfg, g_lag_in_frames, 25); -#else - RANGE_CHECK_HI(cfg, g_lag_in_frames, 0); -#endif RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CQ); RANGE_CHECK_HI(cfg, rc_undershoot_pct, 1000); RANGE_CHECK_HI(cfg, rc_overshoot_pct, 1000); @@ -164,11 +155,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100); RANGE_CHECK_HI(cfg, rc_resize_up_thresh, 100); RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100); -#if !(CONFIG_REALTIME_ONLY) RANGE_CHECK(cfg, g_pass, VPX_RC_ONE_PASS, VPX_RC_LAST_PASS); -#else - RANGE_CHECK(cfg, g_pass, VPX_RC_ONE_PASS, VPX_RC_ONE_PASS); -#endif /* VP8 does not support a lower bound on the keyframe interval in * automatic keyframe placement mode. @@ -181,13 +168,8 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK_BOOL(vp8_cfg, enable_auto_alt_ref); RANGE_CHECK(vp8_cfg, cpu_used, -16, 16); -#if !(CONFIG_REALTIME_ONLY) RANGE_CHECK(vp8_cfg, encoding_mode, VP8_BEST_QUALITY_ENCODING, VP8_REAL_TIME_ENCODING); RANGE_CHECK_HI(vp8_cfg, noise_sensitivity, 6); -#else - RANGE_CHECK(vp8_cfg, encoding_mode, VP8_REAL_TIME_ENCODING, VP8_REAL_TIME_ENCODING); - RANGE_CHECK(vp8_cfg, noise_sensitivity, 0, 0); -#endif RANGE_CHECK(vp8_cfg, token_partitions, VP8_ONE_TOKENPARTITION, VP8_EIGHT_TOKENPARTITION); RANGE_CHECK_HI(vp8_cfg, Sharpness, 7); @@ -196,7 +178,6 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(vp8_cfg, arnr_type, 1, 3); RANGE_CHECK(vp8_cfg, cq_level, 0, 63); -#if !(CONFIG_REALTIME_ONLY) if (cfg->g_pass == VPX_RC_LAST_PASS) { size_t packet_sz = sizeof(FIRSTPASS_STATS); @@ -218,7 +199,6 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, if ((int)(stats->count + 0.5) != n_packets - 1) ERROR("rc_twopass_stats_in missing EOS stats packet"); } -#endif return VPX_CODEC_OK; } @@ -249,7 +229,6 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, vpx_codec_enc_cfg_t cfg, struct vp8_extracfg vp8_cfg) { - oxcf->multi_threaded = cfg.g_threads; oxcf->Version = cfg.g_profile; oxcf->Version |= vp8_cfg.experimental? 0x4 : 0; @@ -263,8 +242,6 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, oxcf->frame_rate = 30; } - oxcf->error_resilient_mode = cfg.g_error_resilient; - switch (cfg.g_pass) { case VPX_RC_ONE_PASS: @@ -289,25 +266,14 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, oxcf->lag_in_frames = cfg.g_lag_in_frames; } - oxcf->allow_df = (cfg.rc_dropframe_thresh > 0); - oxcf->drop_frames_water_mark = cfg.rc_dropframe_thresh; - - oxcf->allow_spatial_resampling = cfg.rc_resize_allowed; - oxcf->resample_up_water_mark = cfg.rc_resize_up_thresh; - oxcf->resample_down_water_mark = cfg.rc_resize_down_thresh; - - if (cfg.rc_end_usage == VPX_VBR) - { - oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; - } - else if (cfg.rc_end_usage == VPX_CBR) - { - oxcf->end_usage = USAGE_STREAM_FROM_SERVER; - } - else if (cfg.rc_end_usage == VPX_CQ) - { - oxcf->end_usage = USAGE_CONSTRAINED_QUALITY; - } + // VBR only supported for now. + // CBR code has been deprectated for experimental phase. + // CQ mode not yet tested + oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; + /*if (cfg.rc_end_usage == VPX_CQ) + oxcf->end_usage = USAGE_CONSTRAINED_QUALITY; + else + oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;*/ oxcf->target_bandwidth = cfg.rc_target_bitrate; oxcf->rc_max_intra_bitrate_pct = vp8_cfg.rc_max_intra_bitrate_pct; @@ -341,7 +307,6 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, oxcf->play_alternate = vp8_cfg.enable_auto_alt_ref; oxcf->noise_sensitivity = vp8_cfg.noise_sensitivity; oxcf->Sharpness = vp8_cfg.Sharpness; - oxcf->token_partitions = vp8_cfg.token_partitions; oxcf->two_pass_stats_in = cfg.rc_twopass_stats_in; oxcf->output_pkt_list = vp8_cfg.pkt_list; @@ -371,11 +336,6 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, printf("fixed_q: %d\n", oxcf->fixed_q); printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q); printf("best_allowed_q: %d\n", oxcf->best_allowed_q); - printf("allow_spatial_resampling: %d\n", oxcf->allow_spatial_resampling); - printf("resample_down_water_mark: %d\n", oxcf->resample_down_water_mark); - printf("resample_up_water_mark: %d\n", oxcf->resample_up_water_mark); - printf("allow_df: %d\n", oxcf->allow_df); - printf("drop_frames_water_mark: %d\n", oxcf->drop_frames_water_mark); printf("two_pass_vbrbias: %d\n", oxcf->two_pass_vbrbias); printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section); printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section); @@ -383,7 +343,6 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, printf("lag_in_frames: %d\n", oxcf->lag_in_frames); printf("play_alternate: %d\n", oxcf->play_alternate); printf("Version: %d\n", oxcf->Version); - printf("multi_threaded: %d\n", oxcf->multi_threaded); printf("encode_breakout: %d\n", oxcf->encode_breakout); */ return VPX_CODEC_OK; @@ -618,41 +577,11 @@ static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx, { unsigned int new_qc; -#if !(CONFIG_REALTIME_ONLY) /* Use best quality mode if no deadline is given. */ - new_qc = MODE_BESTQUALITY; - if (deadline) - { - uint64_t duration_us; - - /* Convert duration parameter from stream timebase to microseconds */ - duration_us = (uint64_t)duration * 1000000 - * (uint64_t)ctx->cfg.g_timebase.num - / (uint64_t)ctx->cfg.g_timebase.den; - - /* If the deadline is more that the duration this frame is to be shown, - * use good quality mode. Otherwise use realtime mode. - */ - new_qc = (deadline > duration_us) ? MODE_GOODQUALITY : MODE_REALTIME; - } - -#else - new_qc = MODE_REALTIME; -#endif - - switch (ctx->deprecated_mode) - { - case VP8_BEST_QUALITY_ENCODING: - new_qc = MODE_BESTQUALITY; - break; - case VP8_GOOD_QUALITY_ENCODING: new_qc = MODE_GOODQUALITY; - break; - case VP8_REAL_TIME_ENCODING: - new_qc = MODE_REALTIME; - break; - } + else + new_qc = MODE_BESTQUALITY; if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS) new_qc = MODE_FIRSTPASS; @@ -756,8 +685,8 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, if (ctx->base.init_flags & VPX_CODEC_USE_PSNR) ((VP8_COMP *)ctx->cpi)->b_calculate_psnr = 1; - if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION) - ((VP8_COMP *)ctx->cpi)->output_partition = 1; + //if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION) + // ((VP8_COMP *)ctx->cpi)->output_partition = 1; /* Convert API flags to internal codec lib flags */ lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0; @@ -826,11 +755,10 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, if (cpi->droppable) pkt.data.frame.flags |= VPX_FRAME_IS_DROPPABLE; - if (cpi->output_partition) + /*if (cpi->output_partition) { int i; - const int num_partitions = - (1 << cpi->common.multi_token_partition) + 1; + const int num_partitions = 1; pkt.data.frame.flags |= VPX_FRAME_IS_FRAGMENT; @@ -839,7 +767,7 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, pkt.data.frame.buf = cx_data; pkt.data.frame.sz = cpi->partition_sz[i]; pkt.data.frame.partition_id = i; - /* don't set the fragment bit for the last partition */ + // don't set the fragment bit for the last partition if (i == (num_partitions - 1)) pkt.data.frame.flags &= ~VPX_FRAME_IS_FRAGMENT; vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt); @@ -847,7 +775,7 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, cx_data_sz -= cpi->partition_sz[i]; } } - else + else*/ { pkt.data.frame.buf = cx_data; pkt.data.frame.sz = size; diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index ad8cd5e95..e59c877a1 100644 --- a/vp8/vp8_dx_iface.c +++ b/vp8/vp8_dx_iface.c @@ -19,9 +19,6 @@ #include "decoder/onyxd_int.h" #define VP8_CAP_POSTPROC (CONFIG_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0) -#define VP8_CAP_ERROR_CONCEALMENT (CONFIG_ERROR_CONCEALMENT ? \ - VPX_CODEC_CAP_ERROR_CONCEALMENT : 0) - typedef vpx_codec_stream_info_t vp8_stream_info_t; /* Structures for handling memory allocations */ @@ -396,11 +393,6 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, oxcf.Version = 9; oxcf.postprocess = 0; oxcf.max_threads = ctx->cfg.threads; - oxcf.error_concealment = - (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT); - oxcf.input_partition = - (ctx->base.init_flags & VPX_CODEC_USE_INPUT_PARTITION); - optr = vp8dx_create_decompressor(&oxcf); /* If postprocessing was enabled by the application and a @@ -740,7 +732,7 @@ CODEC_INTERFACE(vpx_codec_vp8_dx) = { "WebM Project VP8 Decoder" VERSION_STRING, VPX_CODEC_INTERNAL_ABI_VERSION, - VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC | VP8_CAP_ERROR_CONCEALMENT | + VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC | VPX_CODEC_CAP_INPUT_PARTITION, /* vpx_codec_caps_t caps; */ vp8_init, /* vpx_codec_init_fn_t init; */ @@ -771,7 +763,7 @@ vpx_codec_iface_t vpx_codec_vp8_algo = { "WebM Project VP8 Decoder (Deprecated API)" VERSION_STRING, VPX_CODEC_INTERNAL_ABI_VERSION, - VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC | VP8_CAP_ERROR_CONCEALMENT, + VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC, /* vpx_codec_caps_t caps; */ vp8_init, /* vpx_codec_init_fn_t init; */ vp8_destroy, /* vpx_codec_destroy_fn_t destroy; */ diff --git a/vp8/vp8cx.mk b/vp8/vp8cx.mk index b71a54aea..113490237 100644 --- a/vp8/vp8cx.mk +++ b/vp8/vp8cx.mk @@ -34,7 +34,6 @@ VP8_CX_SRCS-yes += vp8_cx_iface.c #INCLUDES += encoder VP8_CX_SRCS-yes += encoder/asm_enc_offsets.c -VP8_CX_SRCS-yes += encoder/defaultcoefcounts.h VP8_CX_SRCS-yes += encoder/bitstream.c VP8_CX_SRCS-yes += encoder/boolhuff.c VP8_CX_SRCS-yes += encoder/dct.c @@ -42,7 +41,6 @@ VP8_CX_SRCS-yes += encoder/encodeframe.c VP8_CX_SRCS-yes += encoder/encodeintra.c VP8_CX_SRCS-yes += encoder/encodemb.c VP8_CX_SRCS-yes += encoder/encodemv.c -VP8_CX_SRCS-$(CONFIG_MULTITHREAD) += encoder/ethreading.c VP8_CX_SRCS-yes += encoder/firstpass.c VP8_CX_SRCS-yes += encoder/generic/csystemdependent.c VP8_CX_SRCS-yes += encoder/block.h @@ -58,7 +56,6 @@ VP8_CX_SRCS-yes += encoder/lookahead.h VP8_CX_SRCS-yes += encoder/mcomp.h VP8_CX_SRCS-yes += encoder/modecosts.h VP8_CX_SRCS-yes += encoder/onyx_int.h -VP8_CX_SRCS-yes += encoder/pickinter.h VP8_CX_SRCS-yes += encoder/psnr.h VP8_CX_SRCS-yes += encoder/quantize.h VP8_CX_SRCS-yes += encoder/ratectrl.h @@ -69,13 +66,13 @@ VP8_CX_SRCS-yes += encoder/variance.h VP8_CX_SRCS-yes += encoder/mcomp.c VP8_CX_SRCS-yes += encoder/modecosts.c VP8_CX_SRCS-yes += encoder/onyx_if.c -VP8_CX_SRCS-yes += encoder/pickinter.c VP8_CX_SRCS-yes += encoder/picklpf.c VP8_CX_SRCS-yes += encoder/psnr.c VP8_CX_SRCS-yes += encoder/quantize.c VP8_CX_SRCS-yes += encoder/ratectrl.c VP8_CX_SRCS-yes += encoder/rdopt.c VP8_CX_SRCS-yes += encoder/sad_c.c +VP8_CX_SRCS-yes += encoder/satd_c.c VP8_CX_SRCS-yes += encoder/segmentation.c VP8_CX_SRCS-yes += encoder/segmentation.h VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += encoder/ssim.c @@ -86,11 +83,10 @@ VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/postproc.h VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/postproc.c VP8_CX_SRCS-yes += encoder/temporal_filter.c VP8_CX_SRCS-yes += encoder/temporal_filter.h +VP8_CX_SRCS-yes += encoder/find_rotation.c +VP8_CX_SRCS-yes += encoder/mbgraph.c +VP8_CX_SRCS-yes += encoder/mbgraph.h -ifeq ($(CONFIG_REALTIME_ONLY),yes) -VP8_CX_SRCS_REMOVE-yes += encoder/firstpass.c -VP8_CX_SRCS_REMOVE-yes += encoder/temporal_filter.c -endif VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/encodemb_x86.h VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/dct_x86.h @@ -123,9 +119,5 @@ VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/quantize_mmx.asm VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/encodeopt.asm VP8_CX_SRCS-$(ARCH_X86_64) += encoder/x86/ssim_opt.asm -ifeq ($(CONFIG_REALTIME_ONLY),yes) -VP8_CX_SRCS_REMOVE-$(HAVE_SSE2) += encoder/x86/temporal_filter_apply_sse2.asm -endif - VP8_CX_SRCS-yes := $(filter-out $(VP8_CX_SRCS_REMOVE-yes),$(VP8_CX_SRCS-yes)) diff --git a/vp8/vp8dx.mk b/vp8/vp8dx.mk index d88b595fb..5de493ddc 100644 --- a/vp8/vp8dx.mk +++ b/vp8/vp8dx.mk @@ -54,22 +54,15 @@ VP8_DX_SRCS-yes += decoder/decodemv.c VP8_DX_SRCS-yes += decoder/decodframe.c VP8_DX_SRCS-yes += decoder/dequantize.c VP8_DX_SRCS-yes += decoder/detokenize.c -VP8_DX_SRCS-$(CONFIG_ERROR_CONCEALMENT) += decoder/ec_types.h -VP8_DX_SRCS-$(CONFIG_ERROR_CONCEALMENT) += decoder/error_concealment.h -VP8_DX_SRCS-$(CONFIG_ERROR_CONCEALMENT) += decoder/error_concealment.c VP8_DX_SRCS-yes += decoder/generic/dsystemdependent.c VP8_DX_SRCS-yes += decoder/dboolhuff.h VP8_DX_SRCS-yes += decoder/decodemv.h -VP8_DX_SRCS-yes += decoder/decoderthreading.h VP8_DX_SRCS-yes += decoder/dequantize.h VP8_DX_SRCS-yes += decoder/detokenize.h VP8_DX_SRCS-yes += decoder/onyxd_int.h VP8_DX_SRCS-yes += decoder/treereader.h VP8_DX_SRCS-yes += decoder/onyxd_if.c -VP8_DX_SRCS-$(CONFIG_MULTITHREAD) += decoder/threading.c VP8_DX_SRCS-yes += decoder/idct_blk.c -VP8_DX_SRCS-$(CONFIG_MULTITHREAD) += decoder/reconintra_mt.h -VP8_DX_SRCS-$(CONFIG_MULTITHREAD) += decoder/reconintra_mt.c VP8_DX_SRCS-yes := $(filter-out $(VP8_DX_SRCS_REMOVE-yes),$(VP8_DX_SRCS-yes)) diff --git a/vpx/src/vpx_decoder.c b/vpx/src/vpx_decoder.c index 6e877b067..64c7ea5a4 100644 --- a/vpx/src/vpx_decoder.c +++ b/vpx/src/vpx_decoder.c @@ -36,9 +36,6 @@ vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx, res = VPX_CODEC_INCAPABLE; else if ((flags & VPX_CODEC_USE_POSTPROC) && !(iface->caps & VPX_CODEC_CAP_POSTPROC)) res = VPX_CODEC_INCAPABLE; - else if ((flags & VPX_CODEC_USE_ERROR_CONCEALMENT) && - !(iface->caps & VPX_CODEC_CAP_ERROR_CONCEALMENT)) - res = VPX_CODEC_INCAPABLE; else if ((flags & VPX_CODEC_USE_INPUT_PARTITION) && !(iface->caps & VPX_CODEC_CAP_INPUT_PARTITION)) res = VPX_CODEC_INCAPABLE; diff --git a/vpx/vpx_decoder.h b/vpx/vpx_decoder.h index 0fc38c69f..ea2569daf 100644 --- a/vpx/vpx_decoder.h +++ b/vpx/vpx_decoder.h @@ -53,8 +53,6 @@ extern "C" { #define VPX_CODEC_CAP_PUT_SLICE 0x10000 /**< Will issue put_slice callbacks */ #define VPX_CODEC_CAP_PUT_FRAME 0x20000 /**< Will issue put_frame callbacks */ #define VPX_CODEC_CAP_POSTPROC 0x40000 /**< Can postprocess decoded frame */ -#define VPX_CODEC_CAP_ERROR_CONCEALMENT 0x80000 /**< Can conceal errors due to - packet loss */ #define VPX_CODEC_CAP_INPUT_PARTITION 0x100000 /**< Can receive encoded frames one partition at a time */ @@ -66,8 +64,6 @@ extern "C" { * The available flags are specified by VPX_CODEC_USE_* defines. */ #define VPX_CODEC_USE_POSTPROC 0x10000 /**< Postprocess decoded frame */ -#define VPX_CODEC_USE_ERROR_CONCEALMENT 0x20000 /**< Conceal errors in decoded - frames */ #define VPX_CODEC_USE_INPUT_PARTITION 0x40000 /**< The input frame should be passed to the decoder one partition at a time */ diff --git a/vpx_mem/include/vpx_mem_intrnl.h b/vpx_mem/include/vpx_mem_intrnl.h index 63c6b777c..6e261ba7f 100644 --- a/vpx_mem/include/vpx_mem_intrnl.h +++ b/vpx_mem/include/vpx_mem_intrnl.h @@ -11,7 +11,7 @@ #ifndef __VPX_MEM_INTRNL_H__ #define __VPX_MEM_INTRNL_H__ -#include "vpx_config.h" +#include "vpx_ports/config.h" #ifndef CONFIG_MEM_MANAGER # if defined(VXWORKS) diff --git a/vpx_mem/vpx_mem_tracker.c b/vpx_mem/vpx_mem_tracker.c index b37076ec8..9e8623a9a 100644 --- a/vpx_mem/vpx_mem_tracker.c +++ b/vpx_mem/vpx_mem_tracker.c @@ -22,7 +22,7 @@ in the memory_tracker struct as well as calls to create/destroy/lock/unlock the mutex in vpx_memory_tracker_init/Destroy and memory_tracker_lock_mutex/unlock_mutex */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #if defined(__uClinux__) # include diff --git a/vpx_ports/arm.h b/vpx_ports/arm.h index 525a7641f..81af1f11f 100644 --- a/vpx_ports/arm.h +++ b/vpx_ports/arm.h @@ -12,7 +12,7 @@ #ifndef VPX_PORTS_ARM_H #define VPX_PORTS_ARM_H #include -#include "vpx_config.h" +#include "config.h" /*ARMv5TE "Enhanced DSP" instructions.*/ #define HAS_EDSP 0x01 diff --git a/vp8/encoder/pickinter.h b/vpx_ports/config.h similarity index 56% rename from vp8/encoder/pickinter.h rename to vpx_ports/config.h index 1c5d6a6e6..1abe70da9 100644 --- a/vp8/encoder/pickinter.h +++ b/vpx_ports/config.h @@ -7,13 +7,4 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ - - -#ifndef __INC_PICKINTER_H -#define __INC_PICKINTER_H #include "vpx_config.h" -#include "vp8/common/onyxc_int.h" - -extern void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra); -extern void vp8_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate); -#endif diff --git a/vpx_ports/mem_ops_aligned.h b/vpx_ports/mem_ops_aligned.h index 0fbba65e2..82a18b2e0 100644 --- a/vpx_ports/mem_ops_aligned.h +++ b/vpx_ports/mem_ops_aligned.h @@ -80,7 +80,7 @@ *mem = (uint##sz##_t)raw;\ } -#include "vpx_config.h" +#include "config.h" #if CONFIG_BIG_ENDIAN #define mem_get_be_aligned_generic(sz) mem_get_ne_aligned_generic(be,sz) #define mem_get_sbe_aligned_generic(sz) mem_get_sne_aligned_generic(be,sz) diff --git a/vpx_ports/vpxtypes.h b/vpx_ports/vpxtypes.h index c7ccc0510..2ab66b14b 100644 --- a/vpx_ports/vpxtypes.h +++ b/vpx_ports/vpxtypes.h @@ -12,7 +12,7 @@ #ifndef __VPXTYPES_H__ #define __VPXTYPES_H__ -#include "vpx_config.h" +#include "vpx_ports/config.h" //#include #ifdef _MSC_VER diff --git a/vpx_ports/x86.h b/vpx_ports/x86.h index 1f3d5ebe1..b0130fbfe 100644 --- a/vpx_ports/x86.h +++ b/vpx_ports/x86.h @@ -12,7 +12,7 @@ #ifndef VPX_PORTS_X86_H #define VPX_PORTS_X86_H #include -#include "vpx_config.h" +#include "config.h" typedef enum { diff --git a/vpx_scale/arm/scalesystemdependent.c b/vpx_scale/arm/scalesystemdependent.c index cdfc23efd..fee76fff7 100644 --- a/vpx_scale/arm/scalesystemdependent.c +++ b/vpx_scale/arm/scalesystemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_ports/arm.h" #include "vpx_scale/vpxscale.h" diff --git a/vpx_scale/generic/scalesystemdependent.c b/vpx_scale/generic/scalesystemdependent.c index 54217157b..92cebc4f4 100644 --- a/vpx_scale/generic/scalesystemdependent.c +++ b/vpx_scale/generic/scalesystemdependent.c @@ -9,7 +9,7 @@ */ -#include "vpx_config.h" +#include "vpx_ports/config.h" #include "vpx_scale/vpxscale.h" @@ -44,33 +44,6 @@ extern void vp8_yv12_copy_frame(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG ****************************************************************************/ void vp8_scale_machine_specific_config() { -#if CONFIG_SPATIAL_RESAMPLING - vp8_horizontal_line_1_2_scale = vp8cx_horizontal_line_1_2_scale_c; - vp8_vertical_band_1_2_scale = vp8cx_vertical_band_1_2_scale_c; - vp8_last_vertical_band_1_2_scale = vp8cx_last_vertical_band_1_2_scale_c; - vp8_horizontal_line_3_5_scale = vp8cx_horizontal_line_3_5_scale_c; - vp8_vertical_band_3_5_scale = vp8cx_vertical_band_3_5_scale_c; - vp8_last_vertical_band_3_5_scale = vp8cx_last_vertical_band_3_5_scale_c; - vp8_horizontal_line_3_4_scale = vp8cx_horizontal_line_3_4_scale_c; - vp8_vertical_band_3_4_scale = vp8cx_vertical_band_3_4_scale_c; - vp8_last_vertical_band_3_4_scale = vp8cx_last_vertical_band_3_4_scale_c; - vp8_horizontal_line_2_3_scale = vp8cx_horizontal_line_2_3_scale_c; - vp8_vertical_band_2_3_scale = vp8cx_vertical_band_2_3_scale_c; - vp8_last_vertical_band_2_3_scale = vp8cx_last_vertical_band_2_3_scale_c; - vp8_horizontal_line_4_5_scale = vp8cx_horizontal_line_4_5_scale_c; - vp8_vertical_band_4_5_scale = vp8cx_vertical_band_4_5_scale_c; - vp8_last_vertical_band_4_5_scale = vp8cx_last_vertical_band_4_5_scale_c; - - - vp8_vertical_band_5_4_scale = vp8cx_vertical_band_5_4_scale_c; - vp8_vertical_band_5_3_scale = vp8cx_vertical_band_5_3_scale_c; - vp8_vertical_band_2_1_scale = vp8cx_vertical_band_2_1_scale_c; - vp8_vertical_band_2_1_scale_i = vp8cx_vertical_band_2_1_scale_i_c; - vp8_horizontal_line_2_1_scale = vp8cx_horizontal_line_2_1_scale_c; - vp8_horizontal_line_5_3_scale = vp8cx_horizontal_line_5_3_scale_c; - vp8_horizontal_line_5_4_scale = vp8cx_horizontal_line_5_4_scale_c; -#endif - vp8_yv12_extend_frame_borders_ptr = vp8_yv12_extend_frame_borders; vp8_yv12_copy_frame_yonly_ptr = vp8_yv12_copy_frame_yonly; vp8_yv12_copy_frame_ptr = vp8_yv12_copy_frame; diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h index 3cc4746f7..e78046720 100644 --- a/vpx_scale/yv12config.h +++ b/vpx_scale/yv12config.h @@ -17,7 +17,14 @@ extern "C" #endif #define VP7BORDERINPIXELS 48 + +#if CONFIG_ENHANCED_INTERP +#define VP8BORDERINPIXELS 64 +#define INTERP_EXTEND 4 +#else #define VP8BORDERINPIXELS 32 +#define INTERP_EXTEND 3 +#endif /************************************* For INT_YUV: diff --git a/vpxdec.c b/vpxdec.c index 304608bb3..359cd2431 100644 --- a/vpxdec.c +++ b/vpxdec.c @@ -87,9 +87,6 @@ static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1, "Max threads to use"); static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, "Show version string"); -static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0, - "Enable decoder error-concealment"); - #if CONFIG_MD5 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, @@ -103,7 +100,6 @@ static const arg_def_t *all_args[] = #if CONFIG_MD5 &md5arg, #endif - &error_concealment, NULL }; @@ -704,7 +700,6 @@ int main(int argc, const char **argv_) FILE *infile; int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0; int stop_after = 0, postproc = 0, summary = 0, quiet = 1; - int ec_enabled = 0; vpx_codec_iface_t *iface = NULL; unsigned int fourcc; unsigned long dx_time = 0; @@ -849,10 +844,6 @@ int main(int argc, const char **argv_) vp8_dbg_display_mv = flags; } } - else if (arg_match(&arg, &error_concealment, argi)) - { - ec_enabled = 1; - } #endif else @@ -973,8 +964,7 @@ int main(int argc, const char **argv_) break; } - dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | - (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); + dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0); if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface, &cfg, dec_flags)) { diff --git a/vpxenc.c b/vpxenc.c index 3fec7758c..efbbbc05d 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -32,6 +32,8 @@ #include #include #endif +#include "vpx_config.h" +#include "vpx_version.h" #include "vpx/vp8cx.h" #include "vpx_ports/mem_ops.h" #include "vpx_ports/vpx_timer.h" @@ -75,6 +77,9 @@ static const struct codec_item unsigned int fourcc; } codecs[] = { +#if CONFIG_EXPERIMENTAL && CONFIG_VP8_ENCODER + {"vp8x", &vpx_codec_vp8x_cx_algo, 0x78385056}, +#endif #if CONFIG_VP8_ENCODER {"vp8", &vpx_codec_vp8_cx_algo, 0x30385056}, #endif @@ -623,18 +628,6 @@ write_webm_seek_info(EbmlGlobal *ebml) //segment info EbmlLoc startInfo; uint64_t frame_time; - char version_string[64]; - - /* Assemble version string */ - if(ebml->debug) - strcpy(version_string, "vpxenc"); - else - { - strcpy(version_string, "vpxenc "); - strncat(version_string, - vpx_codec_version_str(), - sizeof(version_string) - 1 - strlen(version_string)); - } frame_time = (uint64_t)1000 * ebml->framerate.den / ebml->framerate.num; @@ -643,8 +636,10 @@ write_webm_seek_info(EbmlGlobal *ebml) Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000); Ebml_SerializeFloat(ebml, Segment_Duration, ebml->last_pts_ms + frame_time); - Ebml_SerializeString(ebml, 0x4D80, version_string); - Ebml_SerializeString(ebml, 0x5741, version_string); + Ebml_SerializeString(ebml, 0x4D80, + ebml->debug ? "vpxenc" : "vpxenc" VERSION_STRING); + Ebml_SerializeString(ebml, 0x5741, + ebml->debug ? "vpxenc" : "vpxenc" VERSION_STRING); Ebml_EndSubElement(ebml, &startInfo); } } @@ -893,7 +888,7 @@ static unsigned int murmur ( const void * key, int len, unsigned int seed ) } #include "math.h" - +#define MAX_PSNR 100 static double vp8_mse2psnr(double Samples, double Peak, double Mse) { double psnr; @@ -901,10 +896,10 @@ static double vp8_mse2psnr(double Samples, double Peak, double Mse) if ((double)Mse > 0.0) psnr = 10.0 * log10(Peak * Peak * Samples / Mse); else - psnr = 60; // Limit to prevent / 0 + psnr = MAX_PSNR; // Limit to prevent / 0 - if (psnr > 60) - psnr = 60; + if (psnr > MAX_PSNR) + psnr = MAX_PSNR; return psnr; } @@ -1701,7 +1696,11 @@ int main(int argc, const char **argv_) /* Handle codec specific options */ #if CONFIG_VP8_ENCODER - if (codec->iface == &vpx_codec_vp8_cx_algo) + if (codec->iface == &vpx_codec_vp8_cx_algo +#if CONFIG_EXPERIMENTAL + || codec->iface == &vpx_codec_vp8x_cx_algo +#endif + ) { ctrl_args = vp8_args; ctrl_args_map = vp8_arg_ctrl_map;