postprocess.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. //*@@@+++@@@@******************************************************************
  2. //
  3. // Copyright © Microsoft Corp.
  4. // All rights reserved.
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are met:
  8. //
  9. // • Redistributions of source code must retain the above copyright notice,
  10. // this list of conditions and the following disclaimer.
  11. // • Redistributions in binary form must reproduce the above copyright notice,
  12. // this list of conditions and the following disclaimer in the documentation
  13. // and/or other materials provided with the distribution.
  14. //
  15. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  19. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. // POSSIBILITY OF SUCH DAMAGE.
  26. //
  27. //*@@@---@@@@******************************************************************
  28. #include "windowsmediaphoto.h"
  29. #include "strcodec.h"
  30. Void smoothMB(PixelI * p1, PixelI * p0, PixelI * q0, PixelI * q1)
  31. {
  32. // p1 p0 | q0 q1
  33. PixelI delta = ((((*q0 - *p0) << 2) + (*p1 - *q1)) >> 3);
  34. *q0 -= delta;
  35. *p0 += delta;
  36. }
  37. Void smooth(PixelI * p2, PixelI * p1, PixelI * p0, PixelI * q0, PixelI * q1, PixelI * q2)
  38. {
  39. // p2 p1 p0 | q0 q1 q2
  40. PixelI delta = ((((*q0 - *p0) << 2) + (*p1 - *q1)) >> 3);
  41. *q0 -= delta;
  42. *p0 += delta;
  43. *p1 = (*p1 >> 1) + ((*p0 + *p2) >> 2);
  44. *q1 = (*q1 >> 1) + ((*q0 + *q2) >> 2);
  45. }
  46. Int initPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t mbWidth, size_t iNumChannels)
  47. {
  48. size_t i, j, k, l;
  49. Bool b32bit = sizeof(int) == 4;
  50. for(j = 0; j < iNumChannels; j ++){
  51. for(i = 0; i < 2; i ++){
  52. // 2 more are allocated to avoid boundary check
  53. if(b32bit) // integer overlow/underflow check for 32-bit system
  54. if((((mbWidth + 2) >> 16) * sizeof(struct tagPostProcInfo)) & 0xffff0000)
  55. return ICERR_ERROR;
  56. strPostProcInfo[j][i] = (struct tagPostProcInfo *)malloc((mbWidth + 2) * sizeof(struct tagPostProcInfo));
  57. assert(strPostProcInfo[j][i] != NULL);
  58. if(strPostProcInfo[j][i] == NULL){
  59. return ICERR_ERROR;
  60. }
  61. strPostProcInfo[j][i] ++;
  62. // initialize out-of-bound MBs as bumpy (no post at all) to avoid boundary check
  63. // left boundary
  64. strPostProcInfo[j][i][-1].ucMBTexture = 3;
  65. for(l = 0; l < 4; l ++){
  66. for(k = 0; k < 4; k ++){
  67. strPostProcInfo[j][i][-1].ucBlockTexture[l][k] = 3;
  68. }
  69. }
  70. // right boundary
  71. strPostProcInfo[j][i][mbWidth] = strPostProcInfo[j][i][-1];
  72. }
  73. }
  74. return ICERR_OK;
  75. }
  76. Void termPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels)
  77. {
  78. size_t i, j;
  79. for(j = 0; j < iNumChannels; j ++){
  80. for(i = 0; i < 2; i ++){
  81. if(strPostProcInfo[j][i] != NULL){
  82. free(strPostProcInfo[j][i] - 1);
  83. }
  84. }
  85. }
  86. }
  87. Void slideOneMBRow(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels, size_t mbWidth, Bool top, Bool bottom)
  88. {
  89. size_t i, j;
  90. struct tagPostProcInfo * bar;
  91. for(i = 0; i < iNumChannels; i ++){
  92. // swap previous row and current row
  93. bar = strPostProcInfo[i][0];
  94. strPostProcInfo[i][0] = strPostProcInfo[i][1];
  95. strPostProcInfo[i][1] = bar;
  96. if(top){ // if top row, previous row is out of boundary
  97. for(j = 0; j < mbWidth; j ++){
  98. strPostProcInfo[i][0][j] = strPostProcInfo[i][0][-1]; // set as bumpy
  99. }
  100. }
  101. if(bottom){ // if bottom bottom row, set current row of MBs (out of boundary) as bumpy
  102. for(j = 0; j < mbWidth; j ++){
  103. strPostProcInfo[i][1][j] = strPostProcInfo[i][1][-1]; // set as bumpy
  104. }
  105. }
  106. }
  107. }
  108. // get DC and texture infomation right before transform
  109. Void updatePostProcInfo(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * pMB, size_t mbX, size_t cc)
  110. {
  111. size_t i, j;
  112. struct tagPostProcInfo * pMBInfo = strPostProcInfo[cc][1] + mbX;
  113. // DC of MB
  114. pMBInfo->iMBDC = pMB[0];
  115. // texture of MB
  116. pMBInfo->ucMBTexture = 0; // smooth
  117. for(i = 16; i < 256; i += 16){
  118. if(pMB[i] != 0){
  119. pMBInfo->ucMBTexture = 3; // bumpy
  120. break;
  121. }
  122. }
  123. // DCs of blocks not available yet, will collect after demacroblocking
  124. // textures of blocks
  125. for(j = 0; j < 4; j ++)
  126. for(i = 0; i < 4; i ++){
  127. PixelI * p = pMB + i * 64 + j * 16;
  128. size_t k;
  129. for(k = 1, pMBInfo->ucBlockTexture[j][i] = 0; k < 16; k ++){
  130. if(p[k] != 0){
  131. pMBInfo->ucBlockTexture[j][i] = 3;
  132. break;
  133. }
  134. }
  135. }
  136. }
  137. // demacroblock critirion: two MBs have same texture other than bumpy and DCs differ less than 1
  138. #define DMB(a, b) (a->ucMBTexture + b->ucMBTexture == 0) && (abs(a->iMBDC - b->iMBDC) <= threshold)
  139. // demacroblock and get DCs of blocks
  140. Void postProcMB(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold)
  141. {
  142. /* 4 MBs involved, current MB is d, we have 4 2-pixel boundary segments */
  143. /* | */
  144. /* a | b */
  145. /* - - + + */
  146. /* c ! d */
  147. /* ! */
  148. struct tagPostProcInfo * pMBb = strPostProcInfo[cc][0] + mbX, * pMBa = pMBb - 1, * pMBd = strPostProcInfo[cc][1] + mbX, * pMBc = pMBd - 1;
  149. // demacroblock segment --
  150. if(DMB(pMBa, pMBc)){
  151. smoothMB(p0 - 256 + 10 * 16, p0 - 256 + 11 * 16, p1 - 256 + 8 * 16, p1 - 256 + 9 * 16);
  152. smoothMB(p0 - 256 + 14 * 16, p0 - 256 + 15 * 16, p1 - 256 + 12 * 16, p1 - 256 + 13 * 16);
  153. }
  154. // demacroblock segment ++
  155. if(DMB(pMBb, pMBd)){
  156. smoothMB(p0 + 2 * 16, p0 + 3 * 16, p1 + 0 * 16, p1 + 1 * 16);
  157. smoothMB(p0 + 6 * 16, p0 + 7 * 16, p1 + 4 * 16, p1 + 5 * 16);
  158. }
  159. // demacroblock segment |
  160. if(DMB(pMBa, pMBb)){
  161. smoothMB(p0 - 256 + 10 * 16, p0 - 256 + 14 * 16, p0 + 2 * 16, p0 + 6 * 16);
  162. smoothMB(p0 - 256 + 11 * 16, p0 - 256 + 15 * 16, p0 + 3 * 16, p0 + 7 * 16);
  163. }
  164. // demacroblock segment !
  165. if(DMB(pMBc, pMBd)){
  166. smoothMB(p1 - 256 + 8 * 16, p1 - 256 + 12 * 16, p1 + 0 * 16, p1 + 4 * 16);
  167. smoothMB(p1 - 256 + 9 * 16, p1 - 256 + 13 * 16, p1 + 1 * 16, p1 + 5 * 16);
  168. }
  169. /* update DCs of blocks */
  170. // MB d
  171. pMBd->iBlockDC[0][0] = p1[0 * 16];
  172. pMBd->iBlockDC[0][1] = p1[4 * 16];
  173. pMBd->iBlockDC[1][0] = p1[1 * 16];
  174. pMBd->iBlockDC[1][1] = p1[5 * 16];
  175. // MB b
  176. pMBb->iBlockDC[2][0] = p0[2 * 16];
  177. pMBb->iBlockDC[2][1] = p0[6 * 16];
  178. pMBb->iBlockDC[3][0] = p0[3 * 16];
  179. pMBb->iBlockDC[3][1] = p0[7 * 16];
  180. // MB c
  181. pMBc->iBlockDC[0][2] = p1[ 8 * 16 - 256];
  182. pMBc->iBlockDC[0][3] = p1[12 * 16 - 256];
  183. pMBc->iBlockDC[1][2] = p1[ 9 * 16 - 256];
  184. pMBc->iBlockDC[1][3] = p1[13 * 16 - 256];
  185. // MB a
  186. pMBa->iBlockDC[2][2] = p0[10 * 16 - 256];
  187. pMBa->iBlockDC[2][3] = p0[14 * 16 - 256];
  188. pMBa->iBlockDC[3][2] = p0[11 * 16 - 256];
  189. pMBa->iBlockDC[3][3] = p0[15 * 16 - 256];
  190. }
  191. /* deblock and destair blocks */
  192. /* 4 MBs involved, need to process 16 blocks of a */
  193. /* | */
  194. /* a | b */
  195. /* - - - - */
  196. /* c | d */
  197. /* | */
  198. Void postProcBlock(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold)
  199. {
  200. size_t i, j, k;
  201. Int dc[5][5];
  202. U8 texture[5][5];
  203. struct tagPostProcInfo * pMBb = strPostProcInfo[cc][0] + mbX, * pMBa = pMBb - 1, * pMBd = strPostProcInfo[cc][1] + mbX, * pMBc = pMBd - 1;
  204. PixelI * pc, * pt;
  205. /* copy DC and Texture info, can be optimized out */
  206. for(j = 0; j < 4; j ++){
  207. // from MB a
  208. for(i = 0; i < 4; i ++){
  209. dc[j][i] = pMBa->iBlockDC[j][i];
  210. texture[j][i] = pMBa->ucBlockTexture[j][i];
  211. }
  212. // 4 blocks from MB c
  213. dc[4][j] = pMBc->iBlockDC[0][j];
  214. texture[4][j] = pMBc->ucBlockTexture[0][j];
  215. // 4 blocks from MB b
  216. dc[j][4] = pMBb->iBlockDC[j][0];
  217. texture[j][4] = pMBb->ucBlockTexture[j][0];
  218. }
  219. // 1 block from MB d
  220. dc[4][4] = pMBd->iBlockDC[0][0];
  221. texture[4][4] = pMBd->ucBlockTexture[0][0];
  222. /* block boundaries */
  223. /* | */
  224. /* | */
  225. /* --- */
  226. for(j = 0; j < 4; j ++){
  227. for(i = 0; i < 4; i ++){
  228. pc = p0 - 256 + i * 64 + j * 16;
  229. // deblock
  230. if(texture[j][i] + texture[j + 1][i] < 3 && abs(dc[j][i] - dc[j + 1][i]) <= threshold){
  231. // smooth horizontal boundary ----
  232. pt = (j < 3 ? pc + 16 : p1 - 256 + i * 64);
  233. for(k = 0; k < 4; k ++){
  234. smooth(pc + idxCC[1][k], pc + idxCC[2][k], pc + idxCC[3][k], pt + idxCC[0][k], pt + idxCC[1][k], pt + idxCC[2][k]);
  235. }
  236. }
  237. // two horizontally adjacent blocks have same texture and similiar DCs
  238. if(texture[j][i] + texture[j][i + 1] < 3 && abs(dc[j][i] - dc[j][i + 1]) <= threshold){
  239. // smooth vertical boundary |
  240. pt = pc + 64;
  241. for(k = 0; k < 4; k ++){
  242. smooth(pc + idxCC[k][1], pc + idxCC[k][2], pc + idxCC[k][3], pt + idxCC[k][0], pt + idxCC[k][1], pt + idxCC[k][2]);
  243. }
  244. }
  245. }
  246. }
  247. }