Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 1 | /******************************************************************** |
| 2 | * * |
| 3 | * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE. * |
| 4 | * * |
| 5 | * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * |
| 6 | * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE. * |
| 7 | * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * |
| 8 | * * |
| 9 | * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006 * |
| 10 | * BY Hitachi Systems & Services, Ltd. * |
Stefan Weil | e7d8100 | 2011-12-10 00:19:46 +0100 | [diff] [blame] | 11 | * (Noriaki Yamazaki, Research & Development Center) * |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 12 | * * |
| 13 | * * |
| 14 | ******************************************************************** |
| 15 | Redistribution and use in source and binary forms, with or without |
| 16 | modification, are permitted provided that the following conditions |
| 17 | are met: |
| 18 | |
| 19 | - Redistributions of source code must retain the above copyright |
| 20 | notice, this list of conditions and the following disclaimer. |
| 21 | |
| 22 | - Redistributions in binary form must reproduce the above copyright |
| 23 | notice, this list of conditions and the following disclaimer in the |
| 24 | documentation and/or other materials provided with the distribution. |
| 25 | |
| 26 | - Neither the name of the Hitachi Systems & Services, Ltd. nor |
| 27 | the names of its contributors may be used to endorse or promote |
| 28 | products derived from this software without specific prior written |
| 29 | permission. |
| 30 | |
| 31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 32 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 33 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 34 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION |
| 35 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 36 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 37 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 38 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 39 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 40 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 41 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 42 | ********************************************************************/ |
| 43 | |
Markus Armbruster | 121d071 | 2016-06-29 10:12:57 +0200 | [diff] [blame] | 44 | #ifndef VNC_ENC_ZYWRLE_H |
| 45 | #define VNC_ENC_ZYWRLE_H |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 46 | |
| 47 | /* Tables for Coefficients filtering. */ |
| 48 | #ifndef ZYWRLE_QUANTIZE |
| 49 | /* Type A:lower bit omitting of EZW style. */ |
| 50 | static const unsigned int zywrle_param[3][3]={ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 51 | {0x0000F000, 0x00000000, 0x00000000}, |
| 52 | {0x0000C000, 0x00F0F0F0, 0x00000000}, |
| 53 | {0x0000C000, 0x00C0C0C0, 0x00F0F0F0}, |
Amarjargal Gundjalam | ef99aa2 | 2022-10-25 22:28:08 +0800 | [diff] [blame] | 54 | /* {0x0000FF00, 0x00000000, 0x00000000}, |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 55 | {0x0000FF00, 0x00FFFFFF, 0x00000000}, |
| 56 | {0x0000FF00, 0x00FFFFFF, 0x00FFFFFF}, */ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 57 | }; |
| 58 | #else |
| 59 | /* Type B:Non liner quantization filter. */ |
| 60 | static const int8_t zywrle_conv[4][256]={ |
Amarjargal Gundjalam | ef99aa2 | 2022-10-25 22:28:08 +0800 | [diff] [blame] | 61 | { /* bi=5, bo=5 r=0.0:PSNR=24.849 */ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 62 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 63 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 64 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 65 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 66 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 67 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 68 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 69 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 70 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 71 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 72 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 73 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 74 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 75 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 76 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 77 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 78 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 79 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 80 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 81 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 82 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 83 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 84 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 85 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 86 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 87 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 88 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 89 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 90 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 91 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 92 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 93 | 0, 0, 0, 0, 0, 0, 0, 0, |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 94 | }, |
Amarjargal Gundjalam | ef99aa2 | 2022-10-25 22:28:08 +0800 | [diff] [blame] | 95 | { /* bi=5, bo=5 r=2.0:PSNR=74.031 */ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 96 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 97 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 98 | 0, 0, 0, 0, 0, 0, 0, 32, |
| 99 | 32, 32, 32, 32, 32, 32, 32, 32, |
| 100 | 32, 32, 32, 32, 32, 32, 32, 32, |
| 101 | 48, 48, 48, 48, 48, 48, 48, 48, |
| 102 | 48, 48, 48, 56, 56, 56, 56, 56, |
| 103 | 56, 56, 56, 56, 64, 64, 64, 64, |
| 104 | 64, 64, 64, 64, 72, 72, 72, 72, |
| 105 | 72, 72, 72, 72, 80, 80, 80, 80, |
| 106 | 80, 80, 88, 88, 88, 88, 88, 88, |
| 107 | 88, 88, 88, 88, 88, 88, 96, 96, |
| 108 | 96, 96, 96, 104, 104, 104, 104, 104, |
| 109 | 104, 104, 104, 104, 104, 112, 112, 112, |
| 110 | 112, 112, 112, 112, 112, 112, 120, 120, |
| 111 | 120, 120, 120, 120, 120, 120, 120, 120, |
| 112 | 0, -120, -120, -120, -120, -120, -120, -120, |
| 113 | -120, -120, -120, -112, -112, -112, -112, -112, |
| 114 | -112, -112, -112, -112, -104, -104, -104, -104, |
| 115 | -104, -104, -104, -104, -104, -104, -96, -96, |
| 116 | -96, -96, -96, -88, -88, -88, -88, -88, |
| 117 | -88, -88, -88, -88, -88, -88, -88, -80, |
| 118 | -80, -80, -80, -80, -80, -72, -72, -72, |
| 119 | -72, -72, -72, -72, -72, -64, -64, -64, |
| 120 | -64, -64, -64, -64, -64, -56, -56, -56, |
| 121 | -56, -56, -56, -56, -56, -56, -48, -48, |
| 122 | -48, -48, -48, -48, -48, -48, -48, -48, |
| 123 | -48, -32, -32, -32, -32, -32, -32, -32, |
| 124 | -32, -32, -32, -32, -32, -32, -32, -32, |
| 125 | -32, -32, 0, 0, 0, 0, 0, 0, |
| 126 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 127 | 0, 0, 0, 0, 0, 0, 0, 0, |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 128 | }, |
Amarjargal Gundjalam | ef99aa2 | 2022-10-25 22:28:08 +0800 | [diff] [blame] | 129 | { /* bi=5, bo=4 r=2.0:PSNR=64.441 */ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 130 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 131 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 132 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 133 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 134 | 48, 48, 48, 48, 48, 48, 48, 48, |
| 135 | 48, 48, 48, 48, 48, 48, 48, 48, |
| 136 | 48, 48, 48, 48, 48, 48, 48, 48, |
| 137 | 64, 64, 64, 64, 64, 64, 64, 64, |
| 138 | 64, 64, 64, 64, 64, 64, 64, 64, |
| 139 | 80, 80, 80, 80, 80, 80, 80, 80, |
| 140 | 80, 80, 80, 80, 80, 88, 88, 88, |
| 141 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 142 | 104, 104, 104, 104, 104, 104, 104, 104, |
| 143 | 104, 104, 104, 112, 112, 112, 112, 112, |
| 144 | 112, 112, 112, 112, 120, 120, 120, 120, |
| 145 | 120, 120, 120, 120, 120, 120, 120, 120, |
| 146 | 0, -120, -120, -120, -120, -120, -120, -120, |
| 147 | -120, -120, -120, -120, -120, -112, -112, -112, |
| 148 | -112, -112, -112, -112, -112, -112, -104, -104, |
| 149 | -104, -104, -104, -104, -104, -104, -104, -104, |
| 150 | -104, -88, -88, -88, -88, -88, -88, -88, |
| 151 | -88, -88, -88, -88, -80, -80, -80, -80, |
| 152 | -80, -80, -80, -80, -80, -80, -80, -80, |
| 153 | -80, -64, -64, -64, -64, -64, -64, -64, |
| 154 | -64, -64, -64, -64, -64, -64, -64, -64, |
| 155 | -64, -48, -48, -48, -48, -48, -48, -48, |
| 156 | -48, -48, -48, -48, -48, -48, -48, -48, |
| 157 | -48, -48, -48, -48, -48, -48, -48, -48, |
| 158 | -48, 0, 0, 0, 0, 0, 0, 0, |
| 159 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 160 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 161 | 0, 0, 0, 0, 0, 0, 0, 0, |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 162 | }, |
Amarjargal Gundjalam | ef99aa2 | 2022-10-25 22:28:08 +0800 | [diff] [blame] | 163 | { /* bi=5, bo=2 r=2.0:PSNR=43.175 */ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 164 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 165 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 166 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 167 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 168 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 169 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 170 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 171 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 172 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 173 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 174 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 175 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 176 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 177 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 178 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 179 | 88, 88, 88, 88, 88, 88, 88, 88, |
| 180 | 0, -88, -88, -88, -88, -88, -88, -88, |
| 181 | -88, -88, -88, -88, -88, -88, -88, -88, |
| 182 | -88, -88, -88, -88, -88, -88, -88, -88, |
| 183 | -88, -88, -88, -88, -88, -88, -88, -88, |
| 184 | -88, -88, -88, -88, -88, -88, -88, -88, |
| 185 | -88, -88, -88, -88, -88, -88, -88, -88, |
| 186 | -88, -88, -88, -88, -88, -88, -88, -88, |
| 187 | -88, -88, -88, -88, -88, -88, -88, -88, |
| 188 | -88, 0, 0, 0, 0, 0, 0, 0, |
| 189 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 190 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 191 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 192 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 193 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 194 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 195 | 0, 0, 0, 0, 0, 0, 0, 0, |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 196 | } |
| 197 | }; |
| 198 | |
| 199 | static const int8_t *zywrle_param[3][3][3]={ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 200 | {{zywrle_conv[0], zywrle_conv[2], zywrle_conv[0]}, |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 201 | {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}, |
| 202 | {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}}, |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 203 | {{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]}, |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 204 | {zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]}, |
| 205 | {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}}, |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 206 | {{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]}, |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 207 | {zywrle_conv[2], zywrle_conv[2], zywrle_conv[2]}, |
| 208 | {zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]}}, |
| 209 | }; |
| 210 | #endif |
| 211 | |
| 212 | /* Load/Save pixel stuffs. */ |
| 213 | #define ZYWRLE_YMASK15 0xFFFFFFF8 |
| 214 | #define ZYWRLE_UVMASK15 0xFFFFFFF8 |
| 215 | #define ZYWRLE_LOAD_PIXEL15(src, r, g, b) \ |
| 216 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 217 | r = (((uint8_t*)src)[S_1]<< 1)& 0xF8; \ |
| 218 | g = (((uint8_t*)src)[S_1]<< 6) | (((uint8_t*)src)[S_0]>> 2); \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 219 | g &= 0xF8; \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 220 | b = (((uint8_t*)src)[S_0]<< 3)& 0xF8; \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 221 | } while (0) |
| 222 | |
| 223 | #define ZYWRLE_SAVE_PIXEL15(dst, r, g, b) \ |
| 224 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 225 | r &= 0xF8; \ |
| 226 | g &= 0xF8; \ |
| 227 | b &= 0xF8; \ |
| 228 | ((uint8_t*)dst)[S_1] = (uint8_t)((r >> 1)|(g >> 6)); \ |
| 229 | ((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 2))& 0xFF); \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 230 | } while (0) |
| 231 | |
| 232 | #define ZYWRLE_YMASK16 0xFFFFFFFC |
| 233 | #define ZYWRLE_UVMASK16 0xFFFFFFF8 |
| 234 | #define ZYWRLE_LOAD_PIXEL16(src, r, g, b) \ |
| 235 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 236 | r = ((uint8_t*)src)[S_1] & 0xF8; \ |
| 237 | g = (((uint8_t*)src)[S_1]<< 5) | (((uint8_t*)src)[S_0] >> 3); \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 238 | g &= 0xFC; \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 239 | b = (((uint8_t*)src)[S_0]<< 3) & 0xF8; \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 240 | } while (0) |
| 241 | |
| 242 | #define ZYWRLE_SAVE_PIXEL16(dst, r, g,b) \ |
| 243 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 244 | r &= 0xF8; \ |
| 245 | g &= 0xFC; \ |
| 246 | b &= 0xF8; \ |
| 247 | ((uint8_t*)dst)[S_1] = (uint8_t)(r | (g >> 5)); \ |
| 248 | ((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 3)) & 0xFF); \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 249 | } while (0) |
| 250 | |
| 251 | #define ZYWRLE_YMASK32 0xFFFFFFFF |
| 252 | #define ZYWRLE_UVMASK32 0xFFFFFFFF |
| 253 | #define ZYWRLE_LOAD_PIXEL32(src, r, g, b) \ |
| 254 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 255 | r = ((uint8_t*)src)[L_2]; \ |
| 256 | g = ((uint8_t*)src)[L_1]; \ |
| 257 | b = ((uint8_t*)src)[L_0]; \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 258 | } while (0) |
| 259 | #define ZYWRLE_SAVE_PIXEL32(dst, r, g, b) \ |
| 260 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 261 | ((uint8_t*)dst)[L_2] = (uint8_t)r; \ |
| 262 | ((uint8_t*)dst)[L_1] = (uint8_t)g; \ |
| 263 | ((uint8_t*)dst)[L_0] = (uint8_t)b; \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 264 | } while (0) |
| 265 | |
| 266 | static inline void harr(int8_t *px0, int8_t *px1) |
| 267 | { |
| 268 | /* Piecewise-Linear Harr(PLHarr) */ |
| 269 | int x0 = (int)*px0, x1 = (int)*px1; |
| 270 | int orgx0 = x0, orgx1 = x1; |
| 271 | |
| 272 | if ((x0 ^ x1) & 0x80) { |
| 273 | /* differ sign */ |
| 274 | x1 += x0; |
| 275 | if (((x1 ^ orgx1) & 0x80) == 0) { |
| 276 | /* |x1| > |x0| */ |
Amarjargal Gundjalam | ef99aa2 | 2022-10-25 22:28:08 +0800 | [diff] [blame] | 277 | x0 -= x1; /* H = -B */ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 278 | } |
| 279 | } else { |
| 280 | /* same sign */ |
| 281 | x0 -= x1; |
| 282 | if (((x0 ^ orgx0) & 0x80) == 0) { |
| 283 | /* |x0| > |x1| */ |
Amarjargal Gundjalam | ef99aa2 | 2022-10-25 22:28:08 +0800 | [diff] [blame] | 284 | x1 += x0; /* L = A */ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 285 | } |
| 286 | } |
| 287 | *px0 = (int8_t)x1; |
| 288 | *px1 = (int8_t)x0; |
| 289 | } |
| 290 | |
| 291 | /* |
| 292 | 1D-Wavelet transform. |
| 293 | |
| 294 | In coefficients array, the famous 'pyramid' decomposition is well used. |
| 295 | |
| 296 | 1D Model: |
| 297 | |L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0 |
| 298 | |L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1 |
| 299 | |
| 300 | But this method needs line buffer because H/L is different position from X0/X1. |
| 301 | So, I used 'interleave' decomposition instead of it. |
| 302 | |
| 303 | 1D Model: |
| 304 | |L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0 |
| 305 | |L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1 |
| 306 | |
| 307 | In this method, H/L and X0/X1 is always same position. |
Stefan Weil | 59b0096 | 2013-10-11 21:34:33 +0200 | [diff] [blame] | 308 | This leads us to more speed and less memory. |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 309 | Of cause, the result of both method is quite same |
| 310 | because it's only difference that coefficient position. |
| 311 | */ |
| 312 | static inline void wavelet_level(int *data, int size, int l, int skip_pixel) |
| 313 | { |
| 314 | int s, ofs; |
| 315 | int8_t *px0; |
| 316 | int8_t *end; |
| 317 | |
| 318 | px0 = (int8_t*)data; |
| 319 | s = (8 << l) * skip_pixel; |
| 320 | end = px0 + (size >> (l + 1)) * s; |
| 321 | s -= 2; |
| 322 | ofs = (4 << l) * skip_pixel; |
| 323 | |
| 324 | while (px0 < end) { |
| 325 | harr(px0, px0 + ofs); |
| 326 | px0++; |
| 327 | harr(px0, px0 + ofs); |
| 328 | px0++; |
| 329 | harr(px0, px0 + ofs); |
| 330 | px0 += s; |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | #ifndef ZYWRLE_QUANTIZE |
| 335 | /* Type A:lower bit omitting of EZW style. */ |
| 336 | static inline void filter_wavelet_square(int *buf, int width, int height, |
| 337 | int level, int l) |
| 338 | { |
| 339 | int r, s; |
| 340 | int x, y; |
| 341 | int *h; |
| 342 | const unsigned int *m; |
| 343 | |
| 344 | m = &(zywrle_param[level - 1][l]); |
| 345 | s = 2 << l; |
| 346 | |
| 347 | for (r = 1; r < 4; r++) { |
| 348 | h = buf; |
| 349 | if (r & 0x01) { |
| 350 | h += s >> 1; |
| 351 | } |
| 352 | if (r & 0x02) { |
| 353 | h += (s >> 1) * width; |
| 354 | } |
| 355 | for (y = 0; y < height / s; y++) { |
| 356 | for (x = 0; x < width / s; x++) { |
| 357 | /* |
| 358 | these are same following code. |
| 359 | h[x] = h[x] / (~m[x]+1) * (~m[x]+1); |
| 360 | ( round h[x] with m[x] bit ) |
| 361 | '&' operator isn't 'round' but is 'floor'. |
| 362 | So, we must offset when h[x] is negative. |
| 363 | */ |
| 364 | if (((int8_t*)h)[0] & 0x80) { |
| 365 | ((int8_t*)h)[0] += ~((int8_t*)m)[0]; |
| 366 | } |
| 367 | if (((int8_t*)h)[1] & 0x80) { |
| 368 | ((int8_t*)h)[1] += ~((int8_t*)m)[1]; |
| 369 | } |
| 370 | if (((int8_t*)h)[2] & 0x80) { |
| 371 | ((int8_t*)h)[2] += ~((int8_t*)m)[2]; |
| 372 | } |
| 373 | *h &= *m; |
| 374 | h += s; |
| 375 | } |
| 376 | h += (s-1)*width; |
| 377 | } |
| 378 | } |
| 379 | } |
| 380 | #else |
| 381 | /* |
| 382 | Type B:Non liner quantization filter. |
| 383 | |
| 384 | Coefficients have Gaussian curve and smaller value which is |
| 385 | large part of coefficients isn't more important than larger value. |
| 386 | So, I use filter of Non liner quantize/dequantize table. |
| 387 | In general, Non liner quantize formula is explained as following. |
| 388 | |
| 389 | y=f(x) = sign(x)*round( ((abs(x)/(2^7))^ r )* 2^(bo-1) )*2^(8-bo) |
| 390 | x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi) |
| 391 | ( r:power coefficient bi:effective MSB in input bo:effective MSB in output ) |
| 392 | |
| 393 | r < 1.0 : Smaller value is more important than larger value. |
| 394 | r > 1.0 : Larger value is more important than smaller value. |
| 395 | r = 1.0 : Liner quantization which is same with EZW style. |
| 396 | |
| 397 | r = 0.75 is famous non liner quantization used in MP3 audio codec. |
| 398 | In contrast to audio data, larger value is important in wavelet coefficients. |
| 399 | So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ). |
| 400 | |
| 401 | As compared with EZW style liner quantization, this filter tended to be |
| 402 | more sharp edge and be more compression rate but be more blocking noise and be |
| 403 | less quality. Especially, the surface of graphic objects has distinguishable |
| 404 | noise in middle quality mode. |
| 405 | |
| 406 | We need only quantized-dequantized(filtered) value rather than quantized value |
| 407 | itself because all values are packed or palette-lized in later ZRLE section. |
| 408 | This lead us not to need to modify client decoder when we change |
| 409 | the filtering procedure in future. |
| 410 | Client only decodes coefficients given by encoder. |
| 411 | */ |
| 412 | static inline void filter_wavelet_square(int *buf, int width, int height, |
| 413 | int level, int l) |
| 414 | { |
| 415 | int r, s; |
| 416 | int x, y; |
| 417 | int *h; |
| 418 | const int8_t **m; |
| 419 | |
| 420 | m = zywrle_param[level - 1][l]; |
| 421 | s = 2 << l; |
| 422 | |
| 423 | for (r = 1; r < 4; r++) { |
| 424 | h = buf; |
| 425 | if (r & 0x01) { |
| 426 | h += s >> 1; |
| 427 | } |
| 428 | if (r & 0x02) { |
| 429 | h += (s >> 1) * width; |
| 430 | } |
| 431 | for (y = 0; y < height / s; y++) { |
| 432 | for (x = 0; x < width / s; x++) { |
| 433 | ((int8_t*)h)[0] = m[0][((uint8_t*)h)[0]]; |
| 434 | ((int8_t*)h)[1] = m[1][((uint8_t*)h)[1]]; |
| 435 | ((int8_t*)h)[2] = m[2][((uint8_t*)h)[2]]; |
| 436 | h += s; |
| 437 | } |
| 438 | h += (s - 1) * width; |
| 439 | } |
| 440 | } |
| 441 | } |
| 442 | #endif |
| 443 | |
| 444 | static inline void wavelet(int *buf, int width, int height, int level) |
| 445 | { |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 446 | int l, s; |
| 447 | int *top; |
| 448 | int *end; |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 449 | |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 450 | for (l = 0; l < level; l++) { |
| 451 | top = buf; |
| 452 | end = buf + height * width; |
| 453 | s = width << l; |
| 454 | while (top < end) { |
| 455 | wavelet_level(top, width, l, 1); |
| 456 | top += s; |
| 457 | } |
| 458 | top = buf; |
| 459 | end = buf + width; |
| 460 | s = 1<<l; |
| 461 | while (top < end) { |
| 462 | wavelet_level(top, height, l, width); |
| 463 | top += s; |
| 464 | } |
| 465 | filter_wavelet_square(buf, width, height, level, l); |
| 466 | } |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 467 | } |
| 468 | |
| 469 | |
| 470 | /* Load/Save coefficients stuffs. |
| 471 | Coefficients manages as 24 bits little-endian pixel. */ |
| 472 | #define ZYWRLE_LOAD_COEFF(src, r, g, b) \ |
| 473 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 474 | r = ((int8_t*)src)[2]; \ |
| 475 | g = ((int8_t*)src)[1]; \ |
| 476 | b = ((int8_t*)src)[0]; \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 477 | } while (0) |
| 478 | |
| 479 | #define ZYWRLE_SAVE_COEFF(dst, r, g, b) \ |
| 480 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 481 | ((int8_t*)dst)[2] = (int8_t)r; \ |
| 482 | ((int8_t*)dst)[1] = (int8_t)g; \ |
| 483 | ((int8_t*)dst)[0] = (int8_t)b; \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 484 | } while (0) |
| 485 | |
| 486 | /* |
| 487 | RGB <=> YUV conversion stuffs. |
Michael Tokarev | d4761b6 | 2023-08-23 09:53:14 +0300 | [diff] [blame] | 488 | YUV conversion is explained as following formula in strict meaning: |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 489 | Y = 0.299R + 0.587G + 0.114B ( 0<=Y<=255) |
| 490 | U = -0.169R - 0.331G + 0.500B (-128<=U<=127) |
| 491 | V = 0.500R - 0.419G - 0.081B (-128<=V<=127) |
| 492 | |
| 493 | I use simple conversion RCT(reversible color transform) which is described |
| 494 | in JPEG-2000 specification. |
| 495 | Y = (R + 2G + B)/4 ( 0<=Y<=255) |
| 496 | U = B-G (-256<=U<=255) |
| 497 | V = R-G (-256<=V<=255) |
| 498 | */ |
| 499 | |
| 500 | /* RCT is N-bit RGB to N-bit Y and N+1-bit UV. |
| 501 | For make Same N-bit, UV is lossy. |
| 502 | More exact PLHarr, we reduce to odd range(-127<=x<=127). */ |
| 503 | #define ZYWRLE_RGBYUV_(r, g, b, y, u, v, ymask, uvmask) \ |
| 504 | do { \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 505 | y = (r + (g << 1) + b) >> 2; \ |
| 506 | u = b - g; \ |
| 507 | v = r - g; \ |
| 508 | y -= 128; \ |
| 509 | u >>= 1; \ |
| 510 | v >>= 1; \ |
| 511 | y &= ymask; \ |
| 512 | u &= uvmask; \ |
| 513 | v &= uvmask; \ |
| 514 | if (y == -128) { \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 515 | y += (0xFFFFFFFF - ymask + 1); \ |
| 516 | } \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 517 | if (u == -128) { \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 518 | u += (0xFFFFFFFF - uvmask + 1); \ |
| 519 | } \ |
Paolo Bonzini | b86d01b | 2018-12-14 12:38:28 +0100 | [diff] [blame] | 520 | if (v == -128) { \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 521 | v += (0xFFFFFFFF - uvmask + 1); \ |
| 522 | } \ |
| 523 | } while (0) |
| 524 | |
| 525 | |
| 526 | /* |
| 527 | coefficient packing/unpacking stuffs. |
| 528 | Wavelet transform makes 4 sub coefficient image from 1 original image. |
| 529 | |
| 530 | model with pyramid decomposition: |
| 531 | +------+------+ |
| 532 | | | | |
| 533 | | L | Hx | |
| 534 | | | | |
| 535 | +------+------+ |
| 536 | | | | |
| 537 | | H | Hxy | |
| 538 | | | | |
| 539 | +------+------+ |
| 540 | |
| 541 | So, we must transfer each sub images individually in strict meaning. |
Michael Tokarev | d4761b6 | 2023-08-23 09:53:14 +0300 | [diff] [blame] | 542 | But at least ZRLE meaning, following one decomposition image is same as |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 543 | avobe individual sub image. I use this format. |
| 544 | (Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L) |
| 545 | for simplified procedure for any wavelet level.) |
| 546 | |
| 547 | +------+------+ |
| 548 | | L | |
| 549 | +------+------+ |
| 550 | | Hx | |
| 551 | +------+------+ |
| 552 | | Hy | |
| 553 | +------+------+ |
| 554 | | Hxy | |
| 555 | +------+------+ |
| 556 | */ |
| 557 | #define ZYWRLE_INC_PTR(data) \ |
| 558 | do { \ |
| 559 | data++; \ |
| 560 | if( data - p >= (w + uw) ) { \ |
| 561 | data += scanline-(w + uw); \ |
| 562 | p = data; \ |
| 563 | } \ |
| 564 | } while (0) |
| 565 | |
| 566 | #define ZYWRLE_TRANSFER_COEFF(buf, data, t, w, h, scanline, level, TRANS) \ |
| 567 | do { \ |
| 568 | ph = buf; \ |
| 569 | s = 2 << level; \ |
| 570 | if (t & 0x01) { \ |
| 571 | ph += s >> 1; \ |
| 572 | } \ |
| 573 | if (t & 0x02) { \ |
| 574 | ph += (s >> 1) * w; \ |
| 575 | } \ |
| 576 | end = ph + h * w; \ |
| 577 | while (ph < end) { \ |
| 578 | line = ph + w; \ |
| 579 | while (ph < line) { \ |
| 580 | TRANS \ |
| 581 | ZYWRLE_INC_PTR(data); \ |
| 582 | ph += s; \ |
| 583 | } \ |
| 584 | ph += (s - 1) * w; \ |
| 585 | } \ |
| 586 | } while (0) |
| 587 | |
Amarjargal Gundjalam | ef99aa2 | 2022-10-25 22:28:08 +0800 | [diff] [blame] | 588 | #define ZYWRLE_PACK_COEFF(buf, data, t, width, height, scanline, level) \ |
Corentin Chary | 148954f | 2011-02-04 09:06:01 +0100 | [diff] [blame] | 589 | ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \ |
| 590 | ZYWRLE_LOAD_COEFF(ph, r, g, b); \ |
| 591 | ZYWRLE_SAVE_PIXEL(data, r, g, b);) |
| 592 | |
| 593 | #define ZYWRLE_UNPACK_COEFF(buf, data, t, width, height, scanline, level) \ |
| 594 | ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \ |
| 595 | ZYWRLE_LOAD_PIXEL(data, r, g, b); \ |
| 596 | ZYWRLE_SAVE_COEFF(ph, r, g, b);) |
| 597 | |
| 598 | #define ZYWRLE_SAVE_UNALIGN(data, TRANS) \ |
| 599 | do { \ |
| 600 | top = buf + w * h; \ |
| 601 | end = buf + (w + uw) * (h + uh); \ |
| 602 | while (top < end) { \ |
| 603 | TRANS \ |
| 604 | ZYWRLE_INC_PTR(data); \ |
| 605 | top++; \ |
| 606 | } \ |
| 607 | } while (0) |
| 608 | |
| 609 | #define ZYWRLE_LOAD_UNALIGN(data,TRANS) \ |
| 610 | do { \ |
| 611 | top = buf + w * h; \ |
| 612 | if (uw) { \ |
| 613 | p = data + w; \ |
| 614 | end = (int*)(p + h * scanline); \ |
| 615 | while (p < (ZRLE_PIXEL*)end) { \ |
| 616 | line = (int*)(p + uw); \ |
| 617 | while (p < (ZRLE_PIXEL*)line) { \ |
| 618 | TRANS \ |
| 619 | p++; \ |
| 620 | top++; \ |
| 621 | } \ |
| 622 | p += scanline - uw; \ |
| 623 | } \ |
| 624 | } \ |
| 625 | if (uh) { \ |
| 626 | p = data + h * scanline; \ |
| 627 | end = (int*)(p + uh * scanline); \ |
| 628 | while (p < (ZRLE_PIXEL*)end) { \ |
| 629 | line = (int*)(p + w); \ |
| 630 | while (p < (ZRLE_PIXEL*)line) { \ |
| 631 | TRANS \ |
| 632 | p++; \ |
| 633 | top++; \ |
| 634 | } \ |
| 635 | p += scanline - w; \ |
| 636 | } \ |
| 637 | } \ |
| 638 | if (uw && uh) { \ |
| 639 | p= data + w + h * scanline; \ |
| 640 | end = (int*)(p + uh * scanline); \ |
| 641 | while (p < (ZRLE_PIXEL*)end) { \ |
| 642 | line = (int*)(p + uw); \ |
| 643 | while (p < (ZRLE_PIXEL*)line) { \ |
| 644 | TRANS \ |
| 645 | p++; \ |
| 646 | top++; \ |
| 647 | } \ |
| 648 | p += scanline-uw; \ |
| 649 | } \ |
| 650 | } \ |
| 651 | } while (0) |
| 652 | |
| 653 | static inline void zywrle_calc_size(int *w, int *h, int level) |
| 654 | { |
| 655 | *w &= ~((1 << level) - 1); |
| 656 | *h &= ~((1 << level) - 1); |
| 657 | } |
| 658 | |
| 659 | #endif |