/* ** ** $Id: algo.c,v 1.3 2008-05-13 13:47:11 thor Exp $ ** ** */ /************************************************************************* * * This software module was originally contributed by Microsoft * Corporation in the course of development of the * ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for * reference purposes and its performance may not have been optimized. * * This software module is an implementation of one or more * tools as specified by the JPEG XR standard. * * ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive * copyright license to copy, distribute, and make derivative works * of this software module or modifications thereof for use in * products claiming conformance to the JPEG XR standard as * specified by ITU-T T.832 | ISO/IEC 29199-2. * * ITU/ISO/IEC give users the same free license to this software * module or modifications thereof for research purposes and further * ITU/ISO/IEC standardization. * * Those intending to use this software module in products are advised * that its use may infringe existing patents. ITU/ISO/IEC have no * liability for use of this software module or modifications thereof. * * Copyright is not released for products that do not conform to * to the JPEG XR standard as specified by ITU-T T.832 | * ISO/IEC 29199-2. * * Microsoft Corporation retains full right to modify and use the code * for its own purpose, to assign or donate the code to a third party, * and to inhibit third parties from using the code for products that * do not conform to the JPEG XR standard as specified by ITU-T T.832 | * ISO/IEC 29199-2. * * This copyright notice must be included in all copies or derivative * works. * * Copyright (c) ITU-T/ISO/IEC 2008, 2009. ***********************************************************************/ #ifdef _MSC_VER #pragma comment (user,"$Id: algo.c,v 1.3 2008-05-13 13:47:11 thor Exp $") #else #ident "$Id: algo.c,v 1.3 2008-05-13 13:47:11 thor Exp $" #endif /* * This file contains many common algorithms of JPEGXR processing. */ # include "jxr_priv.h" # include # include # include # include static void InitVLCTable2(jxr_image_t image, int vlc_select); const int _jxr_hp_scan_map[16] = { 0, 1, 4, 5, 2, 3, 6, 7, 8, 9,12,13, 10,11,14,15 }; static const unsigned ScanTotals[15] ={32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4}; static int long_word_flag = 0; /* * These two functions implemented floor(x/2) and ceil(x/2). Note that * in C/C++ x/2 is NOT the same as floor(x/2) if x<0. It may be on * some systems, but not in general. So we do all arithmetic with * positive values and get the floor/ceil right by manipulating signs * and rounding afterwards. The YUV444 --> RGB transform must get this * rounding exactly right or there may be losses in the lossless transform. */ int _jxr_floor_div2(int x) { if (x >= 0) return x/2; else return -((-x+1)/2); } int _jxr_ceil_div2(int x) { if (x >= 0) return (x+1)/2; else return -((-x)/2); } int _jxr_quant_map(jxr_image_t image, int x, int shift) { int man, exp; if (x == 0) return 1; if (image->scaled_flag) { if (x < 16) { man = x; exp = shift; } else { man = 16 + (x%16); exp = ((x>>4) - 1) + shift; } } else { if (x < 32) { man = (x + 3) >> 2; exp = 0; } else if (x < 48) { man = (16 + (x%16) + 1) >> 1; exp = (x>>4) - 2; } else { man = 16 + (x%16); exp = (x>>4) - 3; } } return man << exp; } int _jxr_vlc_select(int band, int chroma_flag) { int vlc_select = 0; /* Based on the band and the chroma flag, select the vlc table that we want to use for the ABSLEVEL_INDEX decoder. */ switch (band) { case 0: /* DC */ if (chroma_flag) vlc_select = AbsLevelIndDCChr; else vlc_select = AbsLevelIndDCLum; break; case 1: /* LP */ if (chroma_flag) vlc_select = AbsLevelIndLP1; else vlc_select = AbsLevelIndLP0; break; case 2: /* HP */ if (chroma_flag) vlc_select = AbsLevelIndHP1; else vlc_select = AbsLevelIndHP0; break; default: assert(0); break; } return vlc_select; } void _jxr_InitVLCTable(jxr_image_t image, int vlc_select) { struct adaptive_vlc_s*table = image->vlc_table + vlc_select; table->table = 0; table->deltatable = 0; table->discriminant = 0; } static void InitVLCTable2(jxr_image_t image, int vlc_select) { struct adaptive_vlc_s*table = image->vlc_table + vlc_select; table->table = 1; table->deltatable = 0; table->delta2table = 1; table->discriminant = 0; table->discriminant2 = 0; } /* * This function is for running the adapt for VLC machines that have * only 2 tables. In this case, only the table and discriminant * members are used, and the table is 0 or 1. */ void _jxr_AdaptVLCTable(jxr_image_t image, int vlc_select) { const int cLowerBound = -8; const int cUpperBound = 8; struct adaptive_vlc_s*table = image->vlc_table + vlc_select; const int max_index = 1; /* Only 2 code tables. */ table->deltatable = 0; if ((table->discriminant < cLowerBound) && (table->table != 0)) { table->table -= 1; table->discriminant = 0; } else if ((table->discriminant > cUpperBound) && (table->table != max_index)) { table->table += 1; table->discriminant = 0; } else { if (table->discriminant < -64) table->discriminant = -64; if (table->discriminant > 64) table->discriminant = 64; } } static void AdaptVLCTable2(jxr_image_t image, int vlc_select, int max_index) { const int LOWER_BOUND = -8; const int UPPER_BOUND = 8; struct adaptive_vlc_s*table = image->vlc_table + vlc_select; int disc_lo = table->discriminant; int disc_hi = table->discriminant2; int change_flag = 0; if (disc_lo < LOWER_BOUND && table->table > 0) { table->table -= 1; change_flag = 1; } else if (disc_hi > UPPER_BOUND && table->table < max_index) { table->table += 1; change_flag = 1; } if (change_flag) { table->discriminant = 0; table->discriminant2 = 0; if (table->table == max_index) { table->deltatable = table->table - 1; table->delta2table = table->table - 1; } else if (table->table == 0) { table->deltatable = table->table; table->delta2table = table->table; } else { table->deltatable = table->table - 1; table->delta2table = table->table; } } else { if (table->discriminant < -64) table->discriminant = -64; if (table->discriminant > 64) table->discriminant = 64; if (table->discriminant2 < -64) table->discriminant2 = -64; if (table->discriminant2 > 64) table->discriminant2 = 64; } } void _jxr_AdaptLP(jxr_image_t image) { AdaptVLCTable2(image, DecFirstIndLPLum, 4); AdaptVLCTable2(image, DecIndLPLum0, 3); AdaptVLCTable2(image, DecIndLPLum1, 3); AdaptVLCTable2(image, DecFirstIndLPChr, 4); AdaptVLCTable2(image, DecIndLPChr0, 3); AdaptVLCTable2(image, DecIndLPChr1, 3); _jxr_AdaptVLCTable(image, AbsLevelIndLP0); _jxr_AdaptVLCTable(image, AbsLevelIndLP1); DEBUG(" AdaptLP: DecFirstIndLPLum=%d\n", image->vlc_table[DecFirstIndLPLum].table); DEBUG(" : DecIndLPLum0=%d\n", image->vlc_table[DecIndLPLum0].table); DEBUG(" : DecIndLPLum1=%d\n", image->vlc_table[DecIndLPLum1].table); DEBUG(" : DecFirstIndLPChr=%d\n", image->vlc_table[DecFirstIndLPChr].table); DEBUG(" : DecIndLPChr0=%d\n", image->vlc_table[DecIndLPChr0].table); DEBUG(" : DecIndLPChr1=%d\n", image->vlc_table[DecIndLPChr1].table); } void _jxr_AdaptHP(jxr_image_t image) { AdaptVLCTable2(image, DecFirstIndHPLum, 4); AdaptVLCTable2(image, DecIndHPLum0, 3); AdaptVLCTable2(image, DecIndHPLum1, 3); AdaptVLCTable2(image, DecFirstIndHPChr, 4); AdaptVLCTable2(image, DecIndHPChr0, 3); AdaptVLCTable2(image, DecIndHPChr1, 3); _jxr_AdaptVLCTable(image, AbsLevelIndHP0); _jxr_AdaptVLCTable(image, AbsLevelIndHP1); _jxr_AdaptVLCTable(image, DecNumCBP); _jxr_AdaptVLCTable(image, DecNumBlkCBP); } /* * Despite the name, this function doesn't actually reset a * context. It uses the tx (X position of the time) and mx (X position * of the macroblock in the tile) to calculate true or false that the * caller should invoke a context reset. */ int _jxr_InitContext(jxr_image_t image, unsigned tx, unsigned ty, unsigned mx, unsigned my) { if (mx == 0 && my == 0) return 1; else return 0; } /* * This function guards Adapt?? functions that are called during the * parse. At the end of a MB where this function returns true, the * processing function will call the Adapt?? function. * * NOTE: It is *correct* that this function is true for the first and * the last macroblock. This allows some far right context of a tile * to inform the first column of the next line, but also allows crazy * differences to be adapted away. */ int _jxr_ResetContext(jxr_image_t image, unsigned tx, unsigned mx) { assert(tx < image->tile_columns); assert(image->tile_column_width); /* Return true for every 16 macroblocks in the tile. */ if (mx%16 == 0) return 1; /* Return true for the final macroblock in the tile. */ if (image->tile_column_width[tx] == mx+1) return 1; return 0; } int _jxr_ResetTotals(jxr_image_t image, unsigned mx) { if (mx%16 == 0) return 1; else return 0; } void _jxr_InitializeModelMB(struct model_s*model, int band) { assert(band <= 2); model->state[0] = 0; model->state[1] = 0; model->bits[0] = (2-band) * 4; model->bits[1] = (2-band) * 4; } void _jxr_UpdateModelMB(jxr_image_t image, int lap_mean[2], struct model_s*model, int band) { const int modelweight = 70; static const int weight0[3] = { 240, 12, 1 }; static const int weight1[3][MAX_CHANNELS] = { {0,240,120,80, 60,48,40,34, 30,27,24,22, 20,18,17,16 }, {0,12,6,4, 3,2,2,2, 2,1,1,1, 1,1,1,1 }, {0,16,8,5, 4,3,3,2, 2,2,2,1, 1,1,1,1 } }; static const int weight2[6] = { 120,37,2, 120,18,1 }; int j; assert(band < 3); lap_mean[0] *= weight0[band]; switch (image->use_clr_fmt) { case 1: /* YUV420 */ lap_mean[1] *= weight2[band]; break; case 2: /* YUV422 */ lap_mean[1] *= weight2[3+band]; break; default: lap_mean[1] *= weight1[band][image->num_channels-1]; if (band == 2 /*HP*/) lap_mean[1] >>= 4; break; } for (j = 0; j < 2; j += 1) { int ms = model->state[j]; int delta = (lap_mean[j] - modelweight) >> 2; if (delta <= -8) { delta += 4; if (delta < -16) delta = -16; ms += delta; if (ms < -8) { if (model->bits[j] == 0) { ms = -8; } else { ms = 0; model->bits[j] -= 1; } } } else if (delta >= 8) { delta -= 4; if (delta > 15) delta = 15; ms += delta; if (ms > 8) { if (model->bits[j] >= 15) { model->bits[j] = 15; ms = 8; } else { ms = 0; model->bits[j] += 1; } } } model->state[j] = ms; /* If clr_fmt == YONLY, then we really only want to do this loop once, for j==0. */ if (image->use_clr_fmt == 0/*YONLY*/) break; } } void _jxr_InitializeCountCBPLP(jxr_image_t image) { image->count_max_CBPLP = 1; image->count_zero_CBPLP = 1; } void _jxr_UpdateCountCBPLP(jxr_image_t image, int cbplp, int max) { image->count_zero_CBPLP += 1; if (cbplp == 0) image->count_zero_CBPLP -= 4; if (image->count_zero_CBPLP > 7) image->count_zero_CBPLP = 7; if (image->count_zero_CBPLP < -8) image->count_zero_CBPLP = -8; image->count_max_CBPLP += 1; if (cbplp == max) image->count_max_CBPLP -= 4; if (image->count_max_CBPLP > 7) image->count_max_CBPLP = 7; if (image->count_max_CBPLP < -8) image->count_max_CBPLP = -8; } void _jxr_InitLPVLC(jxr_image_t image) { DEBUG(" ... InitLPVLC\n"); InitVLCTable2(image, DecFirstIndLPLum); InitVLCTable2(image, DecIndLPLum0); InitVLCTable2(image, DecIndLPLum1); InitVLCTable2(image, DecFirstIndLPChr); InitVLCTable2(image, DecIndLPChr0); InitVLCTable2(image, DecIndLPChr1); _jxr_InitVLCTable(image, AbsLevelIndLP0); _jxr_InitVLCTable(image, AbsLevelIndLP1); } void _jxr_InitializeAdaptiveScanLP(jxr_image_t image) { static const int ScanOrderLP[15] = { 4, 1, 5, 8, 2, 9, 6, 12, 3, 10, 13, 7, 14, 11, 15}; int idx; for (idx = 0 ; idx < 15 ; idx += 1) { image->lopass_scanorder[idx] = ScanOrderLP[idx]; image->lopass_scantotals[idx] = ScanTotals[idx]; } } /* */ void _jxr_InitializeAdaptiveScanHP(jxr_image_t image) { static const unsigned ScanOrderHor[15] ={ 4, 1, 5, 8, 2, 9, 6, 12, 3, 10, 13, 7, 14, 11, 15}; static const unsigned ScanOrderVer[15] ={ 1, 2, 5, 4, 3, 6, 9, 8, 7, 12, 15, 13, 10, 11, 14}; int idx; for (idx = 0 ; idx < 15 ; idx += 1) { image->hipass_hor_scanorder[idx] = ScanOrderHor[idx]; image->hipass_hor_scantotals[idx] = ScanTotals[idx]; image->hipass_ver_scanorder[idx] = ScanOrderVer[idx]; image->hipass_ver_scantotals[idx] = ScanTotals[idx]; } } void _jxr_InitializeCBPModel(jxr_image_t image) { image->hp_cbp_model.state[0] = 0; image->hp_cbp_model.state[1] = 0; image->hp_cbp_model.count0[0] = -4; image->hp_cbp_model.count0[1] = -4; image->hp_cbp_model.count1[0] = 4; image->hp_cbp_model.count1[1] = 4; } void _jxr_InitHPVLC(jxr_image_t image) { InitVLCTable2(image, DecFirstIndHPLum); InitVLCTable2(image, DecIndHPLum0); InitVLCTable2(image, DecIndHPLum1); InitVLCTable2(image, DecFirstIndHPChr); InitVLCTable2(image, DecIndHPChr0); InitVLCTable2(image, DecIndHPChr1); _jxr_InitVLCTable(image, AbsLevelIndHP0); _jxr_InitVLCTable(image, AbsLevelIndHP1); /* _jxr_InitVLCTable(image, DecNumCBP); */ /* _jxr_InitVLCTable(image, DecNumBlkCBP); */ } void _jxr_InitCBPVLC(jxr_image_t image) { _jxr_InitVLCTable(image, DecNumCBP); _jxr_InitVLCTable(image, DecNumBlkCBP); } static int num_ones(int val) { int cnt = 0; assert(val >= 0); while (val > 0) { if (val&1) cnt += 1; val >>= 1; } return cnt; } # define SAT(x) do { if ((x) > 15) (x)=15 ; else if ((x) < -16) (x)=-16; } while(0); static void update_cbp_model(jxr_image_t image, int c1, int norig) { const int ndiff = 3; struct cbp_model_s*hp_cbp_model = & (image->hp_cbp_model); hp_cbp_model->count0[c1] += norig - ndiff; SAT(hp_cbp_model->count0[c1]); hp_cbp_model->count1[c1] += 16 - norig - ndiff; SAT(hp_cbp_model->count1[c1]); if (hp_cbp_model->count0[c1] < 0) { if (hp_cbp_model->count0[c1] < hp_cbp_model->count1[c1]) hp_cbp_model->state[c1] = 1; else hp_cbp_model->state[c1] = 2; } else if (hp_cbp_model->count1[c1] < 0) { hp_cbp_model->state[c1] = 2; } else { hp_cbp_model->state[c1] = 0; } } int _jxr_PredCBP444(jxr_image_t image, int*diff_cbp, int channel, unsigned tx, unsigned mx, unsigned my) { int chroma_flag = 0; int cbp; int norig; if (channel > 0) chroma_flag = 1; DEBUG(" PredCBP444: Prediction mode = %d\n", image->hp_cbp_model.state[chroma_flag]); cbp = diff_cbp[channel]; if (image->hp_cbp_model.state[chroma_flag] == 0) { if (mx == 0) { if (my == 0) cbp ^= 1; else cbp ^= (MACROBLK_UP1_HPCBP(image, channel, tx, mx)>>10)&1; } else { cbp ^= (MACROBLK_CUR_HPCBP(image, channel, tx, mx-1)>>5)&1; } cbp ^= 0x02 & (cbp<<1); cbp ^= 0x10 & (cbp<<3); cbp ^= 0x20 & (cbp<<1); cbp ^= (cbp&0x33) << 2; cbp ^= (cbp&0xcc) << 6; cbp ^= (cbp&0x3300) << 2; } else if (image->hp_cbp_model.state[chroma_flag] == 2) { cbp ^= 0xffff; } norig = num_ones(cbp); DEBUG(" PredCBP444: NOrig=%d, CBPModel.Count0/1[%d]= %d/%d\n", norig, chroma_flag, image->hp_cbp_model.count0[chroma_flag], image->hp_cbp_model.count1[chroma_flag]); update_cbp_model(image, chroma_flag, norig); DEBUG(" PredCBP444: ...becomes CBPModel.Count0/1[%d]= %d/%d, new state=%d\n", chroma_flag, image->hp_cbp_model.count0[chroma_flag], image->hp_cbp_model.count1[chroma_flag], image->hp_cbp_model.state[chroma_flag]); return cbp; } void _jxr_w_PredCBP444(jxr_image_t image, int ch, unsigned tx, unsigned mx, int my) { int chroma_flag = 0; int cbp; int norig; if (ch > 0) chroma_flag = 1; DEBUG(" PredCBP444: Prediction mode = %d\n", image->hp_cbp_model.state[chroma_flag]); cbp = MACROBLK_UP1_HPCBP(image,ch,tx,mx); norig = num_ones(cbp); DEBUG(" PredCBP444: ... cbp starts as 0x%x\n", cbp); if (image->hp_cbp_model.state[chroma_flag] == 0) { cbp ^= (cbp&0x3300) << 2; cbp ^= (cbp&0xcc) << 6; cbp ^= (cbp&0x33) << 2; cbp ^= 0x20 & (cbp<<1); cbp ^= 0x10 & (cbp<<3); cbp ^= 0x02 & (cbp<<1); if (mx == 0) { if (my == 0) cbp ^= 1; else cbp ^= (MACROBLK_CUR_HPCBP(image,ch, tx, mx)>>10)&1; } else { cbp ^= (MACROBLK_UP1_HPCBP(image,ch, tx, mx-1)>>5)&1; } } else if (image->hp_cbp_model.state[chroma_flag] == 2){ cbp ^= 0xffff; } DEBUG(" PredCBP444: ... diff_cbp 0x%04x\n", cbp); MACROBLK_UP1(image,ch,tx,mx).hp_diff_cbp = cbp; update_cbp_model(image, chroma_flag, norig); } int _jxr_PredCBP422(jxr_image_t image, int*diff_cbp, int channel, unsigned tx, unsigned mx, unsigned my) { int cbp; int norig; assert(channel > 0); DEBUG(" PredCBP422: Prediction mode = %d, channel=%d, cbp_mode.State[1]=%d\n", image->hp_cbp_model.state[1], channel, image->hp_cbp_model.state[1]); cbp = diff_cbp[channel]; if (image->hp_cbp_model.state[1] == 0) { if (mx == 0) { if (my == 0) cbp ^= 1; else cbp ^= (MACROBLK_UP1_HPCBP(image, channel, tx, mx)>>6)&1; } else { cbp ^= (MACROBLK_CUR_HPCBP(image, channel, tx, mx-1)>>1)&1; } cbp ^= 0x02 & (cbp<<1); cbp ^= 0x0c & (cbp<<2); cbp ^= 0x30 & (cbp<<2); cbp ^= 0xc0 & (cbp<<2); } else if (image->hp_cbp_model.state[1] == 2) { cbp ^= 0xff; } norig = num_ones(cbp) * 2; update_cbp_model(image, 1, norig); return cbp; } void _jxr_w_PredCBP422(jxr_image_t image, int ch, unsigned tx, unsigned mx, int my) { int cbp; int norig; assert(ch > 0); DEBUG(" PredCBP422: Prediction mode = %d\n", image->hp_cbp_model.state[1]); cbp = MACROBLK_UP1_HPCBP(image,ch,tx,mx); norig = num_ones(cbp) * 2; DEBUG(" PredCBP422: ... cbp[%d] starts as 0x%x\n", ch, cbp); if (image->hp_cbp_model.state[1] == 0) { cbp ^= 0xc0 & (cbp<<2); cbp ^= 0x30 & (cbp<<2); cbp ^= 0x0c & (cbp<<2); cbp ^= 0x02 & (cbp<<1); if (mx == 0) { if (my == 0) cbp ^= 1; else cbp ^= (MACROBLK_CUR_HPCBP(image, ch, tx, mx)>>6)&1; } else { cbp ^= (MACROBLK_UP1_HPCBP(image, ch, tx, mx-1)>>1)&1; } } else if (image->hp_cbp_model.state[1] == 2) { cbp ^= 0xff; } DEBUG(" PredCBP422: ... diff_cbp 0x%04x\n", cbp); MACROBLK_UP1(image,ch,tx,mx).hp_diff_cbp = cbp; update_cbp_model(image, 1, norig); } int _jxr_PredCBP420(jxr_image_t image, int*diff_cbp, int channel, unsigned tx, unsigned mx, unsigned my) { int cbp; int norig; assert(channel > 0); DEBUG(" PredCBP420: Prediction mode = %d, channel=%d, cbp_mode.State[1]=%d\n", image->hp_cbp_model.state[1], channel, image->hp_cbp_model.state[1]); cbp = diff_cbp[channel]; if (image->hp_cbp_model.state[1] == 0) { if (mx == 0) { if (my == 0) cbp ^= 1; else cbp ^= (MACROBLK_UP1_HPCBP(image, channel, tx, mx)>>2)&1; } else { cbp ^= (MACROBLK_CUR_HPCBP(image, channel, tx, mx-1)>>1)&1; } cbp ^= 0x02 & (cbp<<1); cbp ^= 0x0c & (cbp<<2); } else if (image->hp_cbp_model.state[1] == 2) { cbp ^= 0xf; } norig = num_ones(cbp) * 4; update_cbp_model(image, 1, norig); return cbp; } void _jxr_w_PredCBP420(jxr_image_t image, int ch, unsigned tx, unsigned mx, int my) { int cbp; int norig; assert(ch > 0); DEBUG(" PredCBP420: Prediction mode = %d\n", image->hp_cbp_model.state[1]); cbp = MACROBLK_UP1_HPCBP(image,ch,tx,mx); norig = num_ones(cbp) * 4; DEBUG(" PredCBP420: ... cbp[%d] starts as 0x%x\n", ch, cbp); if (image->hp_cbp_model.state[1] == 0) { cbp ^= 0x0c & (cbp<<2); cbp ^= 0x02 & (cbp<<1); if (mx == 0) { if (my == 0) cbp ^= 1; else cbp ^= (MACROBLK_CUR_HPCBP(image, ch, tx, mx)>>2)&1; } else { cbp ^= (MACROBLK_UP1_HPCBP(image, ch, tx, mx-1)>>1)&1; } } else if (image->hp_cbp_model.state[1] == 2) { cbp ^= 0xf; } DEBUG(" PredCBP420: ... diff_cbp 0x%04x\n", cbp); MACROBLK_UP1(image,ch,tx,mx).hp_diff_cbp = cbp; update_cbp_model(image, 1, norig); } void _jxr_ResetTotalsAdaptiveScanLP(jxr_image_t image) { int idx; for (idx = 0 ; idx < 15 ; idx += 1) { image->lopass_scantotals[idx] = ScanTotals[idx]; } } void _jxr_ResetTotalsAdaptiveScanHP(jxr_image_t image) { int idx; for (idx = 0 ; idx < 15 ; idx += 1) { image->hipass_hor_scantotals[idx] = ScanTotals[idx]; image->hipass_ver_scantotals[idx] = ScanTotals[idx]; } } static int calculate_mbdc_mode(jxr_image_t image, int tx, int mx, int my) { long left; long top; long topleft; long strhor; long strvert; if (mx == 0 && my == 0) return 3; /* No prediction. */ if (mx == 0) return 1; /* Predictions from top only. */ if (my == 0) return 0; /* prediction from left only */ left = MACROBLK_CUR_DC(image, 0, tx, mx-1); top = MACROBLK_UP_DC(image, 0, tx, mx); topleft = MACROBLK_UP_DC(image, 0, tx, mx-1); strhor = 0; strvert = 0; if (image->use_clr_fmt==0 || image->use_clr_fmt==6) {/* YONLY or NCOMPONENT */ strhor = labs(topleft - left); strvert = labs(topleft - top); } else { long left_u = MACROBLK_CUR_DC(image, 1, tx, mx-1); long top_u = MACROBLK_UP_DC(image, 1, tx, mx); long topleft_u = MACROBLK_UP_DC(image, 1, tx, mx-1); long left_v = MACROBLK_CUR_DC(image, 2, tx, mx-1); long top_v = MACROBLK_UP_DC(image, 2, tx, mx); long topleft_v = MACROBLK_UP_DC(image, 2, tx, mx-1); long scale = 2; if (image->use_clr_fmt == 2 /*YUV422*/) scale = 4; if (image->use_clr_fmt == 1 /*YUV420*/) scale = 8; strhor = labs(topleft - left)*scale + labs(topleft_u - left_u) + labs(topleft_v - left_v); strvert = labs(topleft - top)*scale + labs(topleft_u - top_u) + labs(topleft_v - top_v); } if ((strhor*4) < strvert) return 1; if ((strvert*4) < strhor) return 0; return 2; } static void predict_lp444(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode); static void predict_lp422(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode, int mbdc_mode); static void predict_lp420(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode); void _jxr_complete_cur_dclp(jxr_image_t image, int tx, int mx, int my) { /* Calculate the mbcd prediction mode. This mode is used for all the planes of DC data. */ int mbdc_mode = calculate_mbdc_mode(image, tx, mx, image->cur_my); int mblp_mode; /* Now process all the planes of DC data. */ int ch; for (ch = 0 ; ch < image->num_channels ; ch += 1) { long left = mx>0? MACROBLK_CUR_DC(image,ch,tx,mx-1) : 0; long top = MACROBLK_UP_DC(image,ch,tx,mx); DEBUG(" MBDC_MODE=%d for TX=%d, MBx=%d, MBy=%d (cur_my=%d), ch=%d, left=0x%lx, top=0x%lx, cur=0x%x\n", mbdc_mode, tx, mx, my, image->cur_my, ch, left, top, MACROBLK_CUR_DC(image,ch,tx,mx)); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[0] = MACROBLK_CUR_DC(image,ch,tx,mx); CHECK1(image->lwf_test, MACROBLK_CUR_DC(image,ch,tx,mx)); switch (mbdc_mode) { case 0: /* left */ MACROBLK_CUR_DC(image,ch,tx,mx) += left; break; case 1: /* top */ MACROBLK_CUR_DC(image,ch,tx,mx) += top; break; case 2:/* top and left */ /* Note that we really MEAN >>1 and NOT /2. in particular, if the sum is -1, we want the result to also be -1. That extra stuff after the "|" is there to make sure the sign bit is not lost. Also, the chroma planes for YUV42X formats round *up* the mean, where all other planes round down. */ if (ch>0 && (image->use_clr_fmt==1/*YUV420*/||image->use_clr_fmt==2/*YUV422*/)) MACROBLK_CUR_DC(image,ch,tx,mx) += (left+top+1) >> 1 | ((left+top+1)&~INT_MAX); else MACROBLK_CUR_DC(image,ch,tx,mx) += (left+top) >> 1 | ((left+top)&~INT_MAX); break; default: break; } } mblp_mode = 0; if (mbdc_mode==0 && MACROBLK_CUR_LP_QUANT(image,0,tx,mx) == MACROBLK_CUR_LP_QUANT(image,0,tx,mx-1)) { mblp_mode = 0; } else if (mbdc_mode==1 && MACROBLK_CUR_LP_QUANT(image,0,tx,mx) == MACROBLK_UP1_LP_QUANT(image,0,tx,mx)) { mblp_mode = 1; } else { mblp_mode = 2; } DEBUG(" MBLP_MODE=%d for MBx=%d, MBy=%d (lp_quant=%d,lp_quant_ctx=%d)\n", mblp_mode, mx, image->cur_my, MACROBLK_CUR_LP_QUANT(image,0,tx,mx), mbdc_mode==0? MACROBLK_CUR_LP_QUANT(image,0,tx,mx-1) : mbdc_mode==1 ? MACROBLK_UP1_LP_QUANT(image,0,tx,mx) : -1); predict_lp444(image, tx, mx, my, 0, mblp_mode); for (ch = 1 ; ch < image->num_channels ; ch += 1) { switch (image->use_clr_fmt) { case 1: /* YUV420 */ predict_lp420(image, tx, mx, my, ch, mblp_mode); break; case 2: /* YUV422 */ predict_lp422(image, tx, mx, my, ch, mblp_mode, mbdc_mode); break; default: predict_lp444(image,tx, mx, my, ch, mblp_mode); break; } } } static void predict_lp444(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode) { #if defined(DETAILED_DEBUG) { int jdx; DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Difference:", my, mx, ch); DEBUG(" 0x%08x", MACROBLK_CUR(image,ch,tx,mx).pred_dclp[0]); for (jdx = 0; jdx < 15 ; jdx += 1) { DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); if ((jdx+1)%4 == 3 && jdx != 14) DEBUG("\n%*s:", 46, ""); } DEBUG("\n"); } #endif switch (mblp_mode) { case 0: /* left */ CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,7), MACROBLK_CUR_LP(image,ch,tx,mx,11)); MACROBLK_CUR_LP(image,ch,tx,mx,3) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[4]; MACROBLK_CUR_LP(image,ch,tx,mx,7) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[5]; MACROBLK_CUR_LP(image,ch,tx,mx,11)+= MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[6]; break; case 1: /* up */ CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,0), MACROBLK_CUR_LP(image,ch,tx,mx,1), MACROBLK_CUR_LP(image,ch,tx,mx,2)); MACROBLK_CUR_LP(image,ch,tx,mx,0) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[1]; MACROBLK_CUR_LP(image,ch,tx,mx,1) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[2]; MACROBLK_CUR_LP(image,ch,tx,mx,2) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[3]; break; case 2: break; } #if defined(DETAILED_DEBUG) { int jdx; DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Predicted:", my, mx, ch); DEBUG(" 0x%08x", MACROBLK_CUR_DC(image,ch,tx,mx)); for (jdx = 0; jdx < 15 ; jdx += 1) { DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); if ((jdx+1)%4 == 3 && jdx != 14) DEBUG("\n%*s:", 45, ""); } DEBUG("\n"); } #endif MACROBLK_CUR(image,ch,tx,mx).pred_dclp[1] = MACROBLK_CUR_LP(image,ch,tx,mx,0); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[2] = MACROBLK_CUR_LP(image,ch,tx,mx,1); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[3] = MACROBLK_CUR_LP(image,ch,tx,mx,2); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[4] = MACROBLK_CUR_LP(image,ch,tx,mx,3); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[5] = MACROBLK_CUR_LP(image,ch,tx,mx,7); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[6] = MACROBLK_CUR_LP(image,ch,tx,mx,11); } static void predict_lp422(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode, int mbdc_mode) { #if defined(DETAILED_DEBUG) { int jdx; DEBUG(" DC/LP (strip=%3d, tx=%d, mbx=%4d, ch=%d) Difference:", my, tx, mx, ch); DEBUG(" 0x%08x", MACROBLK_CUR(image,ch,tx,mx).pred_dclp[0]); for (jdx = 0; jdx < 7 ; jdx += 1) { DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); if ((jdx+1)%4 == 3 && jdx != 6) DEBUG("\n%*s:", 52, ""); } DEBUG("\n"); } #endif switch (mblp_mode) { case 0: /* left */ CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,1), MACROBLK_CUR_LP(image,ch,tx,mx,5)); MACROBLK_CUR_LP(image,ch,tx,mx,3) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[4]; MACROBLK_CUR_LP(image,ch,tx,mx,1) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[2]; MACROBLK_CUR_LP(image,ch,tx,mx,5) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[6]; break; case 1: /* up */ CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,0), MACROBLK_CUR_LP(image,ch,tx,mx,4)); MACROBLK_CUR_LP(image,ch,tx,mx,3) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[4]; MACROBLK_CUR_LP(image,ch,tx,mx,0) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[5]; MACROBLK_CUR_LP(image,ch,tx,mx,4) += MACROBLK_CUR_LP(image,ch,tx,mx,0); break; case 2: if (mbdc_mode == 1) { CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,4)); MACROBLK_CUR_LP(image,ch,tx,mx,4) += MACROBLK_CUR_LP(image,ch,tx,mx,0); } break; } #if defined(DETAILED_DEBUG) { int jdx; DEBUG(" DC/LP (strip=%3d, tx=%d, mbx=%4d, ch=%d) Predicted:", my, tx, mx, ch); DEBUG(" 0x%08x", MACROBLK_CUR_DC(image,ch,tx,mx)); for (jdx = 0; jdx < 7 ; jdx += 1) { DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); if ((jdx+1)%4 == 3 && jdx != 6) DEBUG("\n%*s:", 51, ""); } DEBUG("\n"); } #endif MACROBLK_CUR(image,ch,tx,mx).pred_dclp[1] = MACROBLK_CUR_LP(image,ch,tx,mx,0); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[2] = MACROBLK_CUR_LP(image,ch,tx,mx,1); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[4] = MACROBLK_CUR_LP(image,ch,tx,mx,3); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[5] = MACROBLK_CUR_LP(image,ch,tx,mx,4); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[6] = MACROBLK_CUR_LP(image,ch,tx,mx,5); } static void predict_lp420(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode) { switch (mblp_mode) { case 0: /* left */ CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,1)); MACROBLK_CUR_LP(image,ch,tx,mx,1) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[2]; break; case 1: /* up */ CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,0)); MACROBLK_CUR_LP(image,ch,tx,mx,0) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[1]; break; } #if defined(DETAILED_DEBUG) { int jdx; DEBUG(" DC/LP (strip=%3d, tx=%d, mbx=%4d, ch=%d) Predicted:", tx, my, mx, ch); DEBUG(" 0x%08x", MACROBLK_CUR_DC(image,ch,tx,mx)); for (jdx = 0; jdx < 3 ; jdx += 1) { DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); } DEBUG("\n"); } #endif MACROBLK_CUR(image,ch,tx,mx).pred_dclp[1] = MACROBLK_CUR_LP(image,ch,tx,mx,0); MACROBLK_CUR(image,ch,tx,mx).pred_dclp[2] = MACROBLK_CUR_LP(image,ch,tx,mx,1); } /* * TRANSFORM functions, forward and inverse. */ static void _InvPermute(int*coeff) { static const int inverse[16] = {0, 8, 4, 13, 2, 15, 3, 14, 1, 12, 5, 9, 7, 11, 6, 10}; int t[16]; int idx; for (idx = 0 ; idx < 16 ; idx += 1) t[inverse[idx]] = coeff[idx]; for (idx = 0 ; idx < 16 ; idx += 1) coeff[idx] = t[idx]; } static void _FwdPermute(int*coeff) { static const int fwd[16] = {0, 8, 4, 6, 2, 10, 14, 12, 1, 11, 15, 13, 9, 3, 7, 5}; int t[16]; int idx; for (idx = 0 ; idx < 16 ; idx += 1) t[fwd[idx]] = coeff[idx]; for (idx = 0 ; idx < 16 ; idx += 1) coeff[idx] = t[idx]; } static void _2x2T_h(int*a, int*b, int*c, int*d, int R_flag) { int t1; int t2; *a += *d; *b -= *c; t1 = ((*a - *b + R_flag) >> 1); t2 = *c; *c = t1 - *d; *d = t1 - t2; CHECK5(long_word_flag, *a, *b, t1, *c, *d); *a -= *d; *b += *c; CHECK2(long_word_flag, *a, *b); } static void _2x2T_h_POST(int*a, int*b, int*c, int*d) { int t1; *b -= *c; *a += (*d * 3 + 4) >> 3; *d -= *b >> 1; t1 = ((*a - *b) >> 1) - *c; CHECK4(long_word_flag, *b, *a, *d, t1); *c = *d; *d = t1; *a -= *d; *b += *c; CHECK2(long_word_flag, *a, *b); } static void _2x2T_h_Enc(int*a, int*b, int*c, int*d) { int t1; int t2; *a += *d; *b -= *c; CHECK2(long_word_flag, *a, *b); t1 = *d; t2 = *c; *c = ((*a - *b) >> 1) - t1; *d = t2 + (*b >> 1); *b += *c; *a -= (*d * 3 + 4) >> 3; CHECK4(long_word_flag, *c, *d, *b, *a); } static void _InvT_odd(int*a, int*b, int*c, int*d) { *b += *d; *a -= *c; *d -= *b >> 1; *c += (*a + 1) >> 1; CHECK4(long_word_flag, *a, *b, *c, *d); *a -= ((*b)*3 + 4) >> 3; *b += ((*a)*3 + 4) >> 3; *c -= ((*d)*3 + 4) >> 3; *d += ((*c)*3 + 4) >> 3; CHECK4(long_word_flag, *a, *b, *c, *d); *c -= (*b + 1) >> 1; *d = ((*a + 1) >> 1) - *d; *b += *c; *a -= *d; CHECK4(long_word_flag, *a, *b, *c, *d); } static void _InvT_odd_odd(int*a, int*b, int*c, int*d) { int t1, t2; *d += *a; *c -= *b; t1 = *d >> 1; t2 = *c >> 1; *a -= t1; *b += t2; CHECK4(long_word_flag, *a, *b, *c, *d); *a -= ((*b)*3 + 3) >> 3; *b += ((*a)*3 + 3) >> 2; CHECK2(long_word_flag, *a, *b); *a -= ((*b)*3 + 4) >> 3; *b -= t2; CHECK2(long_word_flag, *a, *b); *a += t1; *c += *b; *d -= *a; *b = -*b; *c = -*c; CHECK4(long_word_flag, *a, *b, *c, *d); } static void _InvT_odd_odd_POST(int*a, int*b, int*c, int*d) { int t1, t2; *d += *a; *c -= *b; t1 = *d >> 1; t2 = *c >> 1; *a -= t1; *b += t2; CHECK4(long_word_flag, *d, *c, *a, *b); *a -= (*b * 3 + 6) >> 3; *b += (*a * 3 + 2) >> 2; CHECK2(long_word_flag, *a, *b); *a -= (*b * 3 + 4) >> 3; *b -= t2; CHECK2(long_word_flag, *a, *b); *a += t1; *c += *b; *d -= *a; CHECK3(long_word_flag, *a, *c, *d); } static void _T_odd(int*a, int*b, int*c, int*d) { *b -= *c; *a += *d; *c += (*b + 1) >> 1; *d = ((*a + 1) >> 1) - *d; CHECK4(long_word_flag, *b, *a, *c, *d); *b -= (*a * 3 + 4) >> 3; *a += (*b * 3 + 4) >> 3; *d -= (*c * 3 + 4) >> 3; *c += (*d * 3 + 4) >> 3; CHECK4(long_word_flag, *b, *a, *d, *c); *d += *b >> 1; *c -= (*a + 1) >> 1; *b -= *d; *a += *c; CHECK4(long_word_flag, *d, *c, *b, *a); } static void _T_odd_odd(int*a, int*b, int*c, int*d) { int t1; int t2; *b = -*b; *c = -*c; CHECK2(long_word_flag, *b, *c); *d += *a; *c -= *b; t1 = *d >> 1; t2 = *c >> 1; *a -= t1; *b += t2; CHECK4(long_word_flag, *d, *c, *a, *b); *a += (*b * 3 + 4) >> 3; *b -= (*a * 3 + 3) >> 2; CHECK2(long_word_flag, *a, *b); *a += (*b * 3 + 3) >> 3; *b -= t2; CHECK2(long_word_flag, *a, *b); *a += t1; *c += *b; *d -= *a; CHECK3(long_word_flag, *a, *c, *d); } void _jxr_InvPermute2pt(int*a, int*b) { int t1 = *a; *a = *b; *b = t1; } void _jxr_2ptT(int*a, int*b) { *a -= (*b + 1) >> 1; *b += *a; CHECK2(long_word_flag, *a, *b); } /* This is the inverse of the 2ptT function */ void _jxr_2ptFwdT(int*a, int*b) { *b -= *a; *a += (*b + 1) >> 1; CHECK2(long_word_flag, *b, *a); } void _jxr_2x2IPCT(int*coeff) { _2x2T_h(coeff+0, coeff+1, coeff+2, coeff+3, 0); /* _2x2T_h(coeff+0, coeff+2, coeff+1, coeff+3, 0); */ } void _jxr_4x4IPCT(int*coeff) { /* Permute */ _InvPermute(coeff); #if defined(DETAILED_DEBUG) && 0 { int idx; DEBUG(" InvPermute:\n%*s", 4, ""); for (idx = 0 ; idx < 16 ; idx += 1) { DEBUG(" 0x%08x", coeff[idx]); if (idx%4 == 3 && idx != 15) DEBUG("\n%*s", 4, ""); } DEBUG("\n"); } #endif _2x2T_h (coeff+0, coeff+ 1, coeff+4, coeff+ 5, 1); _InvT_odd(coeff+2, coeff+ 3, coeff+6, coeff+ 7); _InvT_odd(coeff+8, coeff+12, coeff+9, coeff+13); _InvT_odd_odd(coeff+10, coeff+11, coeff+14, coeff+15); #if defined(DETAILED_DEBUG) && 0 { int idx; DEBUG(" stage 1:\n%*s", 4, ""); for (idx = 0 ; idx < 16 ; idx += 1) { DEBUG(" 0x%08x", coeff[idx]); if (idx%4 == 3 && idx != 15) DEBUG("\n%*s", 4, ""); } DEBUG("\n"); } #endif _2x2T_h(coeff+0, coeff+3, coeff+12, coeff+15, 0); _2x2T_h(coeff+5, coeff+6, coeff+ 9, coeff+10, 0); _2x2T_h(coeff+1, coeff+2, coeff+13, coeff+14, 0); _2x2T_h(coeff+4, coeff+7, coeff+ 8, coeff+11, 0); } void _jxr_4x4PCT(int*coeff) { _2x2T_h(coeff+0, coeff+3, coeff+12, coeff+15, 0); _2x2T_h(coeff+5, coeff+6, coeff+ 9, coeff+10, 0); _2x2T_h(coeff+1, coeff+2, coeff+13, coeff+14, 0); _2x2T_h(coeff+4, coeff+7, coeff+ 8, coeff+11, 0); _2x2T_h (coeff+0, coeff+ 1, coeff+4, coeff+ 5, 1); _T_odd(coeff+2, coeff+ 3, coeff+6, coeff+ 7); _T_odd(coeff+8, coeff+12, coeff+9, coeff+13); _T_odd_odd(coeff+10, coeff+11, coeff+14, coeff+15); _FwdPermute(coeff); } static void _InvRotate(int*a, int*b) { *a -= (*b + 1) >> 1; *b += (*a + 1) >> 1; CHECK2(long_word_flag, *a, *b); } static void _InvScale(int*a, int*b) { *a += *b; *b = (*a >> 1) - *b; CHECK2(long_word_flag, *a, *b); *a += (*b * 3 + 0) >> 3; *b -= *a >> 10; CHECK2(long_word_flag, *a, *b); *b += *a >> 7; *b += (*a * 3 + 0) >> 4; CHECK1(long_word_flag, *b); } void _jxr_4x4OverlapFilter(int*a, int*b, int*c, int*d, int*e, int*f, int*g, int*h, int*i, int*j, int*k, int*l, int*m, int*n, int*o, int*p) { _2x2T_h(a, d, m, p, 0); _2x2T_h(b, c, n, o, 0); _2x2T_h(e, h, i, l, 0); _2x2T_h(f, g, j, k, 0); _InvRotate(n, m); _InvRotate(j, i); _InvRotate(h, d); _InvRotate(g, c); _InvT_odd_odd_POST(k, l, o, p); _InvScale(a, p); _InvScale(b, o); _InvScale(e, l); _InvScale(f, k); _2x2T_h_POST(a, d, m, p); _2x2T_h_POST(b, c, n, o); _2x2T_h_POST(e, h, i, l); _2x2T_h_POST(f, g, j, k); } void _jxr_4OverlapFilter(int*a, int*b, int*c, int*d) { *a += *d; *b += *c; *d -= ((*a + 1) >> 1); *c -= ((*b + 1) >> 1); CHECK4(long_word_flag, *a, *b, *d, *c); _InvScale(a, d); _InvScale(b, c); *a += ((*d * 3 + 4) >> 3); *b += ((*c * 3 + 4) >> 3); *d -= (*a >> 1); *c -= (*b >> 1); CHECK4(long_word_flag, *a, *b, *d, *c); *a += *d; *b += *c; *d *= -1; *c *= -1; CHECK4(long_word_flag, *a, *b, *d, *c); _InvRotate(c, d); *d += ((*a + 1) >> 1); *c += ((*b + 1) >> 1); *a -= *d; *b -= *c; CHECK4(long_word_flag, *a, *b, *d, *c); } void _jxr_2x2OverlapFilter(int*a, int*b, int*c, int*d) { *a += *d; *b += *c; *d -= (*a + 1) >> 1; *c -= (*b + 1) >> 1; CHECK4(long_word_flag, *a, *b, *d, *c); *b += (*a + 2) >> 2; *a += (*b + 1) >> 1; *a += (*b >> 5); *a += (*b >> 9); *a += (*b >> 13); CHECK2(long_word_flag, *a, *b); *b += (*a + 2) >> 2; *d += (*a + 1) >> 1; *c += (*b + 1) >> 1; *a -= *d; CHECK4(long_word_flag, *a, *b, *d, *c); *b -= *c; CHECK1(long_word_flag, *b); } void _jxr_2OverlapFilter(int*a, int*b) { *b += ((*a + 2) >> 2); *a += ((*b + 1) >> 1); *a += (*b >> 5); *a += (*b >> 9); CHECK2(long_word_flag, *a, *b); *a += (*b >> 13); *b += ((*a + 2) >> 2); CHECK2(long_word_flag, *a, *b); } /* Prefiltering... */ static void fwdT_Odd_Odd_PRE(int*a, int*b, int*c, int*d) { int t1; int t2; *d += *a; *c -= *b; t1 = *d >> 1; t2 = *c >> 1; *a -= t1; *b += t2; CHECK4(long_word_flag, *d, *c, *a, *b); *a += (*b * 3 + 4) >> 3; *b -= (*a * 3 + 2) >> 2; CHECK2(long_word_flag, *a, *b); *a += (*b * 3 + 6) >> 3; *b -= t2; CHECK2(long_word_flag, *a, *b); *a += t1; *c += *b; *d -= *a; CHECK3(long_word_flag, *a, *c, *d); } static void fwdScale(int*a, int*b) { *b -= (*a * 3 + 0) >> 4; CHECK1(long_word_flag, *b); *b -= *a >> 7; CHECK1(long_word_flag, *b); *b += *a >> 10; *a -= (*b * 3 + 0) >> 3; CHECK2(long_word_flag, *b, *a); *b = (*a >> 1) - *b; *a -= *b; CHECK2(long_word_flag, *b, *a); } static void fwdRotate(int*a, int*b) { *b -= (*a + 1) >> 1; *a += (*b + 1) >> 1; CHECK2(long_word_flag, *b, *a); } void _jxr_4x4PreFilter(int*a, int*b, int*c, int*d, int*e, int*f, int*g, int*h, int*i, int*j, int*k, int*l, int*m, int*n, int*o, int*p) { _2x2T_h_Enc(a, d, m, p); _2x2T_h_Enc(b, c, n, o); _2x2T_h_Enc(e, h, i, l); _2x2T_h_Enc(f, g, j, k); fwdScale(a, p); fwdScale(b, o); fwdScale(e, l); fwdScale(f, k); fwdRotate(n, m); fwdRotate(j, i); fwdRotate(h, d); fwdRotate(g, c); fwdT_Odd_Odd_PRE(k, l, o, p); _2x2T_h(a, m, d, p, 0); _2x2T_h(b, c, n, o, 0); _2x2T_h(e, h, i, l, 0); _2x2T_h(f, g, j, k, 0); } void _jxr_4PreFilter(int*a, int*b, int*c, int*d) { *a += *d; *b += *c; *d -= ((*a + 1) >> 1); *c -= ((*b + 1) >> 1); CHECK4(long_word_flag, *a, *b, *d, *c); fwdRotate(c, d); *d *= -1; *c *= -1; *a -= *d; *b -= *c; CHECK4(long_word_flag, *d, *c, *a, *b); *d += (*a >> 1); *c += (*b >> 1); *a -= ((*d * 3 + 4) >> 3); *b -= ((*c * 3 + 4) >> 3); CHECK4(long_word_flag, *d, *c, *a, *b); fwdScale(a, d); fwdScale(b, c); *d += ((*a + 1) >> 1); *c += ((*b + 1) >> 1); *a -= *d; *b -= *c; CHECK4(long_word_flag, *d, *c, *a, *b); } void _jxr_2x2PreFilter(int*a, int*b, int*c, int*d) { *a += *d; *b += *c; *d -= ((*a + 1) >> 1); *c -= ((*b + 1) >> 1); CHECK4(long_word_flag, *a, *b, *d, *c); *b -= ((*a + 2) >> 2); *a -= (*b >> 5); CHECK2(long_word_flag, *b, *a); *a -= (*b >> 9); CHECK1(long_word_flag, *a); *a -= (*b >> 13); CHECK1(long_word_flag, *a); *a -= ((*b + 1) >> 1); *b -= ((*a + 2) >> 2); *d += ((*a + 1) >> 1); *c += ((*b + 1) >> 1); CHECK4(long_word_flag, *a, *b, *d, *c); *a -= *d; *b -= *c; CHECK2(long_word_flag, *a, *b); } void _jxr_2PreFilter(int*a, int*b) { *b -= ((*a + 2) >> 2); *a -= (*b >> 13); CHECK2(long_word_flag, *b, *a); *a -= (*b >> 9); CHECK1(long_word_flag, *a); *a -= (*b >> 5); CHECK1(long_word_flag, *a); *a -= ((*b + 1) >> 1); *b -= ((*a + 2) >> 2); CHECK2(long_word_flag, *a, *b); } uint8_t _jxr_read_lwf_test_flag() { return long_word_flag; } /* * $Log: algo.c,v $ * * Revision 1.58 2009/05/29 12:00:00 microsoft * Reference Software v1.6 updates. * * Revision 1.57 2009/05/29 12:00:00 microsoft * Reference Software v1.6 updates. * * Revision 1.56 2009/04/13 12:00:00 microsoft * Reference Software v1.5 updates. * * Revision 1.55 2008-05-13 13:47:11 thor * Some experiments with a smarter selection for the quantization size, * does not yet compile. * * Revision 1.54 2008-05-09 19:57:48 thor * Reformatted for unix LF. * * Revision 1.53 2008-04-15 14:28:12 thor * Start of the repository for the jpegxr reference software. * * Revision 1.52 2008/03/20 18:11:50 steve * Clarify MBLPMode calculations. * * Revision 1.51 2008/03/14 00:54:08 steve * Add second prefilter for YUV422 and YUV420 encode. * * Revision 1.50 2008/03/13 22:32:26 steve * Fix CBP prediction for YUV422, mode==0. * * Revision 1.49 2008/03/13 17:49:31 steve * Fix problem with YUV422 CBP prediction for UV planes * * Add support for YUV420 encoding. * * Revision 1.48 2008/03/13 00:07:22 steve * Encode HP of YUV422 * * Revision 1.47 2008/03/12 21:10:27 steve * Encode LP of YUV422 * * Revision 1.46 2008/03/11 22:12:48 steve * Encode YUV422 through DC. * * Revision 1.45 2008/02/26 23:52:44 steve * Remove ident for MS compilers. * * Revision 1.44 2008/02/22 23:01:33 steve * Compress macroblock HP CBP packets. * * Revision 1.43 2008/02/01 22:49:52 steve * Handle compress of YUV444 color DCONLY * * Revision 1.42 2008/01/08 23:23:32 steve * Minor math error in overlap code. * * Revision 1.41 2008/01/08 01:06:20 steve * Add first pass overlap filtering. * * Revision 1.40 2008/01/04 17:07:35 steve * API interface for setting QP values. * * Revision 1.39 2008/01/01 01:08:23 steve * Compile warning. * * Revision 1.38 2008/01/01 01:07:25 steve * Add missing HP prediction. * * Revision 1.37 2007/12/30 00:16:00 steve * Add encoding of HP values. * * Revision 1.36 2007/12/17 23:02:57 steve * Implement MB_CBP encoding. * * Revision 1.35 2007/12/14 17:10:39 steve * HP CBP Prediction * * Revision 1.34 2007/12/12 00:36:46 steve * Use T_odd instead of InvT_odd for PCT transform. * * Revision 1.33 2007/12/06 23:12:40 steve * Stubs for LP encode operations. * * Revision 1.32 2007/11/26 01:47:15 steve * Add copyright notices per MS request. * * Revision 1.31 2007/11/21 23:24:09 steve * Account for tiles selecting LP_QUANT for pred math. * * Revision 1.30 2007/11/16 20:03:57 steve * Store MB Quant, not qp_index. * * Revision 1.29 2007/11/13 03:27:23 steve * Add Frequency mode LP support. * * Revision 1.28 2007/10/30 21:32:46 steve * Support for multiple tile columns. * * Revision 1.27 2007/10/23 00:34:12 steve * Level1 filtering for YUV422 and YUV420 * * Revision 1.26 2007/10/22 21:52:37 steve * Level2 filtering for YUV420 * * Revision 1.25 2007/10/19 22:07:11 steve * Prediction of YUV420 chroma planes. * * Revision 1.24 2007/10/19 16:20:21 steve * Parse YUV420 HP * * Revision 1.23 2007/10/17 23:43:19 steve * Add support for YUV420 * * Revision 1.22 2007/10/04 00:30:47 steve * Fix prediction of HP CBP for YUV422 data. * * Revision 1.21 2007/10/02 20:36:29 steve * Fix YUV42X DC prediction, add YUV42X HP parsing. * * Revision 1.20 2007/10/01 20:39:33 steve * Add support for YUV422 LP bands. * * Revision 1.19 2007/09/20 18:04:10 steve * support render of YUV422 images. * * Revision 1.18 2007/09/13 23:12:34 steve * Support color HP bands. * * Revision 1.17 2007/09/11 00:40:06 steve * Fix rendering of chroma to add the missing *2. * Fix handling of the chroma LP samples * Parse some of the HP CBP data in chroma. * * Revision 1.16 2007/09/08 01:01:43 steve * YUV444 color parses properly. * * Revision 1.15 2007/09/04 19:10:46 steve * Finish level1 overlap filtering. * * Revision 1.14 2007/08/31 23:31:49 steve * Initialize CBP VLC tables at the right time. * * Revision 1.13 2007/08/28 21:58:52 steve * Rewrite filtering to match rewritten 4.7 * * Revision 1.12 2007/08/14 23:39:56 steve * Fix UpdateModelMB / Add filtering functions. * * Revision 1.11 2007/08/04 00:10:51 steve * Fix subtle loss of -1 values during DC prediction. */