/* Maps each possible size (n) in the split k-tokenizer to a different value. Possible values of n are: 2, 3, 4, 7, 8, 14, 15, 16, 31, 32, 63, 64, 127, 128 Since we don't care about the order (even in the bit-stream) the simplest ordering (implemented here) is: 14, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 */ int od_pvq_size_ctx(int n) { int logn; int odd; logn = OD_ILOG(n - 1); odd = n & 1; return 2*logn - 1 - odd - 7*(n == 14); }
int image_init(image *img, jpeg_header *header) { int hmax; int vmax; int i; memset(img, 0, sizeof(image)); img->width = header->width; img->height = header->height; img->nplanes = header->ncomps; hmax = 0; vmax = 0; for (i = 0; i < img->nplanes; i++) { jpeg_component *comp; comp = &header->comp[i]; hmax = OD_MAXI(hmax, comp->hsamp); vmax = OD_MAXI(vmax, comp->vsamp); } for (i = 0; i < img->nplanes; i++) { jpeg_component *comp; image_plane *plane; comp = &header->comp[i]; plane = &img->plane[i]; plane->width = comp->hblocks << 3; plane->height = comp->vblocks << 3; /* TODO support 16-bit images */ plane->xstride = 1; plane->ystride = plane->xstride*plane->width; plane->xdec = OD_ILOG(hmax) - OD_ILOG(comp->hsamp); plane->ydec = OD_ILOG(vmax) - OD_ILOG(comp->vsamp); plane->data = od_aligned_malloc(plane->ystride*plane->height, IMAGE_ALIGN); if (plane->data == NULL) { image_clear(img); return EXIT_FAILURE; } plane->coef = od_aligned_malloc(plane->width*plane->height*sizeof(short), IMAGE_ALIGN); if (plane->coef == NULL) { image_clear(img); return EXIT_FAILURE; } } img->pixels = od_aligned_malloc(img->width*img->height*3, IMAGE_ALIGN); if (img->pixels == NULL) { image_clear(img); return EXIT_FAILURE; } return EXIT_SUCCESS; }
/* Computes an upper-bound on the number of bits required to store the L2 norm of a vector (excluding sign). */ int od_vector_log_mag(const od_coeff *x, int n) { int i; int32_t sum; sum = 0; for (i = 0; i < n; i++) { int16_t tmp; tmp = x[i] >> 8; sum += tmp*(int32_t)tmp; } /* We add one full bit (instead of rounding OD_ILOG() up) for safety because the >> 8 above causes the sum to be slightly underestimated. */ return 8 + 1 + OD_ILOG(n + sum)/2; }
static int32_t od_pow(int32_t x, od_val16 beta) { int16_t t; int xshift; int log2_x; od_val32 logr; /*FIXME: this conditional is to avoid doing log2(0).*/ if (x == 0) return 0; log2_x = (OD_ILOG(x) - 1); xshift = log2_x - OD_LOG2_INSHIFT; /*t should be in range [0.0, 1.0[ in Q(OD_LOG2_INSHIFT).*/ t = OD_VSHR(x, xshift) - (1 << OD_LOG2_INSHIFT); /*log2(g/OD_COMPAND_SCALE) = log2(x) - OD_COMPAND_SHIFT in Q(OD_LOG2_OUTSHIFT).*/ logr = od_log2(t) + (log2_x - OD_COMPAND_SHIFT)*OD_LOG2_OUTSCALE; logr = OD_MULT16_32_QBETA(beta, logr); return od_exp2(logr); }
static od_val16 od_rcp(od_val16 x) { int i; od_val16 n; od_val16 r; i = OD_ILOG(x) - 1; /*n is Q15 with range [0,1).*/ n = OD_VSHR_ROUND(x, i - OD_RCP_INSHIFT) - (1 << OD_RCP_INSHIFT); /*Start with a linear approximation: r = 1.8823529411764706-0.9411764705882353*n. The coefficients and the result are Q14 in the range [15420,30840].*/ r = 30840 + OD_MULT16_16_Q15(-15420, n); /*Perform two Newton iterations: r -= r*((r*n)-1.Q15) = r*((r*n)+(r-1.Q15)).*/ r = r - OD_MULT16_16_Q15(r, (OD_MULT16_16_Q15(r, n) + r - 32768)); /*We subtract an extra 1 in the second iteration to avoid overflow; it also neatly compensates for truncation error in the rest of the process.*/ r = r - (1 + OD_MULT16_16_Q15(r, OD_MULT16_16_Q15(r, n) + r - 32768)); /*r is now the Q15 solution to 2/(n+1), with a maximum relative error of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute error of 1.24665/32768.*/ return OD_VSHR_ROUND(r, i - OD_RCP_OUTSHIFT); }
/** Applies Householder reflection from compute_householder(). The * reflection is its own inverse. * * @param [out] out reflected vector * @param [in] x vector to be reflected * @param [in] r reflection * @param [in] n number of dimensions in x,r */ void od_apply_householder(od_val16 *out, const od_val16 *x, const od_val16 *r, int n) { int i; od_val32 proj; od_val16 proj_1; od_val32 l2r; #if !defined(OD_FLOAT_PVQ) od_val16 proj_norm; od_val16 l2r_norm; od_val16 rcp; int proj_shift; int l2r_shift; int outshift; #endif /*FIXME: Can we get l2r and/or l2r_shift from an earlier computation?*/ l2r = 0; for (i = 0; i < n; i++) { l2r += OD_MULT16_16(r[i], r[i]); } /* Apply Householder reflection */ proj = 0; for (i = 0; i < n; i++) { proj += OD_MULT16_16(r[i], x[i]); } #if defined(OD_FLOAT_PVQ) proj_1 = proj*2./(1e-100 + l2r); for (i = 0; i < n; i++) { out[i] = x[i] - r[i]*proj_1; } #else /*l2r_norm is [0.5, 1.0[ in Q15.*/ l2r_shift = (OD_ILOG(l2r) - 1) - 14; l2r_norm = OD_VSHR_ROUND(l2r, l2r_shift); rcp = od_rcp(l2r_norm); proj_shift = (OD_ILOG(abs(proj)) - 1) - 14; /*proj_norm is [0.5, 1.0[ in Q15.*/ proj_norm = OD_VSHR_ROUND(proj, proj_shift); proj_1 = OD_MULT16_16_Q15(proj_norm, rcp); /*The proj*2. in the float code becomes -1 in the final outshift. The sign of l2r_shift is positive since we're taking the reciprocal of l2r_norm and this is a right shift.*/ outshift = OD_MINI(30, OD_RCP_OUTSHIFT - proj_shift - 1 + l2r_shift); if (outshift >= 0) { for (i = 0; i < n; i++) { int32_t tmp; tmp = OD_MULT16_16(r[i], proj_1); tmp = OD_SHR_ROUND(tmp, outshift); out[i] = x[i] - tmp; } } else { /*FIXME: Can we make this case impossible? Right now, if r[] is all zeros except for 1, 2, or 3 ones, and if x[] is all zeros except for large values at the same position as the ones in r[], then we can end up with a shift of -1.*/ for (i = 0; i < n; i++) { int32_t tmp; tmp = OD_MULT16_16(r[i], proj_1); tmp = OD_SHL(tmp, -outshift); out[i] = x[i] - tmp; } } #endif }