1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /*------------------------------------------------------------------------------ 18 19 Table of contents 20 21 1. Include headers 22 2. External compiler flags 23 3. Module defines 24 4. Local function prototypes 25 5. Functions 26 h264bsdConceal 27 ConcealMb 28 Transform 29 30 ------------------------------------------------------------------------------*/ 31 32 /*------------------------------------------------------------------------------ 33 1. Include headers 34 ------------------------------------------------------------------------------*/ 35 36 #include "h264bsd_conceal.h" 37 #include "h264bsd_util.h" 38 #include "h264bsd_reconstruct.h" 39 #include "h264bsd_dpb.h" 40 41 /*------------------------------------------------------------------------------ 42 2. External compiler flags 43 -------------------------------------------------------------------------------- 44 45 -------------------------------------------------------------------------------- 46 3. Module defines 47 ------------------------------------------------------------------------------*/ 48 49 /*lint -e702 disable lint warning on right shift of signed quantity */ 50 51 /*------------------------------------------------------------------------------ 52 4. Local function prototypes 53 ------------------------------------------------------------------------------*/ 54 55 static u32 ConcealMb(mbStorage_t *pMb, image_t *currImage, u32 row, u32 col, 56 u32 sliceType, u8 *data); 57 58 static void Transform(i32 *data); 59 60 /*------------------------------------------------------------------------------ 61 62 Function name: h264bsdConceal 63 64 Functional description: 65 Perform error concealment for a picture. Two types of concealment 66 is performed based on sliceType: 67 1) copy from previous picture for P-slices. 68 2) concealment from neighbour pixels for I-slices 69 70 I-type concealment is based on ideas presented by Jarno Tulkki. 71 The concealment algorithm determines frequency domain coefficients 72 from the neighbour pixels, applies integer transform (the same 73 transform used in the residual processing) and uses the results as 74 pixel values for concealed macroblocks. Transform produces 4x4 75 array and one pixel value has to be used for 4x4 luma blocks and 76 2x2 chroma blocks. 77 78 Similar concealment is performed for whole picture (the choise 79 of the type is based on last successfully decoded slice header of 80 the picture but it is handled by the calling function). It is 81 acknowledged that this may result in wrong type of concealment 82 when a picture contains both types of slices. However, 83 determination of slice type macroblock-by-macroblock cannot 84 be done due to the fact that it is impossible to know to which 85 slice each corrupted (not successfully decoded) macroblock 86 belongs. 87 88 The error concealment is started by searching the first propoerly 89 decoded macroblock and concealing the row containing the macroblock 90 in question. After that all macroblocks above the row in question 91 are concealed. Finally concealment of rows below is performed. 92 The order of concealment for 4x4 picture where macroblock 9 is the 93 first properly decoded one is as follows (properly decoded 94 macroblocks marked with 'x', numbers indicating the order of 95 concealment): 96 97 4 6 8 10 98 3 5 7 9 99 1 x x 2 100 11 12 13 14 101 102 If all macroblocks of the picture are lost, the concealment is 103 copy of previous picture for P-type and setting the image to 104 constant gray (pixel value 128) for I-type. 105 106 Concealment sets quantization parameter of the concealed 107 macroblocks to value 40 and macroblock type to intra to enable 108 deblocking filter to smooth the edges of the concealed areas. 109 110 Inputs: 111 pStorage pointer to storage structure 112 currImage pointer to current image structure 113 sliceType type of the slice 114 115 Outputs: 116 currImage concealed macroblocks will be written here 117 118 Returns: 119 HANTRO_OK 120 121 ------------------------------------------------------------------------------*/ 122 123 u32 h264bsdConceal(storage_t *pStorage, image_t *currImage, u32 sliceType) 124 { 125 126 /* Variables */ 127 128 u32 i, j; 129 u32 row, col; 130 u32 width, height; 131 u8 *refData; 132 mbStorage_t *mb; 133 134 /* Code */ 135 136 ASSERT(pStorage); 137 ASSERT(currImage); 138 139 DEBUG(("Concealing %s slice\n", IS_I_SLICE(sliceType) ? 140 "intra" : "inter")); 141 142 width = currImage->width; 143 height = currImage->height; 144 refData = NULL; 145 /* use reference picture with smallest available index */ 146 if (IS_P_SLICE(sliceType) || (pStorage->intraConcealmentFlag != 0)) 147 { 148 i = 0; 149 do 150 { 151 refData = h264bsdGetRefPicData(pStorage->dpb, i); 152 i++; 153 if (i >= 16) 154 break; 155 } while (refData == NULL); 156 } 157 158 i = row = col = 0; 159 /* find first properly decoded macroblock -> start point for concealment */ 160 while (i < pStorage->picSizeInMbs && !pStorage->mb[i].decoded) 161 { 162 i++; 163 col++; 164 if (col == width) 165 { 166 row++; 167 col = 0; 168 } 169 } 170 171 /* whole picture lost -> copy previous or set grey */ 172 if (i == pStorage->picSizeInMbs) 173 { 174 if ( (IS_I_SLICE(sliceType) && (pStorage->intraConcealmentFlag == 0)) || 175 refData == NULL) 176 H264SwDecMemset(currImage->data, 128, width*height*384); 177 else 178 H264SwDecMemcpy(currImage->data, refData, width*height*384); 179 180 pStorage->numConcealedMbs = pStorage->picSizeInMbs; 181 182 /* no filtering if whole picture concealed */ 183 for (i = 0; i < pStorage->picSizeInMbs; i++) 184 pStorage->mb[i].disableDeblockingFilterIdc = 1; 185 186 return(HANTRO_OK); 187 } 188 189 /* start from the row containing the first correct macroblock, conceal the 190 * row in question, all rows above that row and then continue downwards */ 191 mb = pStorage->mb + row * width; 192 for (j = col; j--;) 193 { 194 ConcealMb(mb+j, currImage, row, j, sliceType, refData); 195 mb[j].decoded = 1; 196 pStorage->numConcealedMbs++; 197 } 198 for (j = col + 1; j < width; j++) 199 { 200 if (!mb[j].decoded) 201 { 202 ConcealMb(mb+j, currImage, row, j, sliceType, refData); 203 mb[j].decoded = 1; 204 pStorage->numConcealedMbs++; 205 } 206 } 207 /* if previous row(s) could not be concealed -> conceal them now */ 208 if (row) 209 { 210 for (j = 0; j < width; j++) 211 { 212 i = row - 1; 213 mb = pStorage->mb + i*width + j; 214 do 215 { 216 ConcealMb(mb, currImage, i, j, sliceType, refData); 217 mb->decoded = 1; 218 pStorage->numConcealedMbs++; 219 mb -= width; 220 } while(i--); 221 } 222 } 223 224 /* process rows below the one containing the first correct macroblock */ 225 for (i = row + 1; i < height; i++) 226 { 227 mb = pStorage->mb + i * width; 228 229 for (j = 0; j < width; j++) 230 { 231 if (!mb[j].decoded) 232 { 233 ConcealMb(mb+j, currImage, i, j, sliceType, refData); 234 mb[j].decoded = 1; 235 pStorage->numConcealedMbs++; 236 } 237 } 238 } 239 240 return(HANTRO_OK); 241 } 242 243 /*------------------------------------------------------------------------------ 244 245 Function name: ConcealMb 246 247 Functional description: 248 Perform error concealment for one macroblock, location of the 249 macroblock in the picture indicated by row and col 250 251 ------------------------------------------------------------------------------*/ 252 253 u32 ConcealMb(mbStorage_t *pMb, image_t *currImage, u32 row, u32 col, 254 u32 sliceType, u8 *refData) 255 { 256 257 /* Variables */ 258 259 u32 i, j, comp; 260 u32 hor, ver; 261 u32 mbNum; 262 u32 width, height; 263 u8 *mbPos; 264 u8 data[384]; 265 u8 *pData; 266 i32 tmp; 267 i32 firstPhase[16]; 268 i32 *pTmp; 269 /* neighbours above, below, left and right */ 270 i32 a[4] = { 0,0,0,0 }, b[4], l[4] = { 0,0,0,0 }, r[4]; 271 u32 A, B, L, R; 272 #ifdef H264DEC_OMXDL 273 u8 fillBuff[32*21 + 15 + 32]; 274 u8 *pFill; 275 #endif 276 /* Code */ 277 278 ASSERT(pMb); 279 ASSERT(!pMb->decoded); 280 ASSERT(currImage); 281 ASSERT(col < currImage->width); 282 ASSERT(row < currImage->height); 283 284 #ifdef H264DEC_OMXDL 285 pFill = ALIGN(fillBuff, 16); 286 #endif 287 width = currImage->width; 288 height = currImage->height; 289 mbNum = row * width + col; 290 291 h264bsdSetCurrImageMbPointers(currImage, mbNum); 292 293 mbPos = currImage->data + row * 16 * width * 16 + col * 16; 294 A = B = L = R = HANTRO_FALSE; 295 296 /* set qpY to 40 to enable some filtering in deblocking (stetson value) */ 297 pMb->qpY = 40; 298 pMb->disableDeblockingFilterIdc = 0; 299 /* mbType set to intra to perform filtering despite the values of other 300 * boundary strength determination fields */ 301 pMb->mbType = I_4x4; 302 pMb->filterOffsetA = 0; 303 pMb->filterOffsetB = 0; 304 pMb->chromaQpIndexOffset = 0; 305 306 if (IS_I_SLICE(sliceType)) 307 H264SwDecMemset(data, 0, sizeof(data)); 308 else 309 { 310 mv_t mv = {0,0}; 311 image_t refImage; 312 refImage.width = width; 313 refImage.height = height; 314 refImage.data = refData; 315 if (refImage.data) 316 { 317 #ifndef H264DEC_OMXDL 318 h264bsdPredictSamples(data, &mv, &refImage, col*16, row*16, 319 0, 0, 16, 16); 320 #else 321 h264bsdPredictSamples(data, &mv, &refImage, 322 ((row*16) + ((col*16)<<16)), 323 0x00001010, pFill); 324 #endif 325 h264bsdWriteMacroblock(currImage, data); 326 327 return(HANTRO_OK); 328 } 329 else 330 H264SwDecMemset(data, 0, sizeof(data)); 331 } 332 333 H264SwDecMemset(firstPhase, 0, sizeof(firstPhase)); 334 335 /* counter for number of neighbours used */ 336 j = 0; 337 hor = ver = 0; 338 if (row && (pMb-width)->decoded) 339 { 340 A = HANTRO_TRUE; 341 pData = mbPos - width*16; 342 a[0] = *pData++; a[0] += *pData++; a[0] += *pData++; a[0] += *pData++; 343 a[1] = *pData++; a[1] += *pData++; a[1] += *pData++; a[1] += *pData++; 344 a[2] = *pData++; a[2] += *pData++; a[2] += *pData++; a[2] += *pData++; 345 a[3] = *pData++; a[3] += *pData++; a[3] += *pData++; a[3] += *pData++; 346 j++; 347 hor++; 348 firstPhase[0] += a[0] + a[1] + a[2] + a[3]; 349 firstPhase[1] += a[0] + a[1] - a[2] - a[3]; 350 } 351 if ((row != height - 1) && (pMb+width)->decoded) 352 { 353 B = HANTRO_TRUE; 354 pData = mbPos + 16*width*16; 355 b[0] = *pData++; b[0] += *pData++; b[0] += *pData++; b[0] += *pData++; 356 b[1] = *pData++; b[1] += *pData++; b[1] += *pData++; b[1] += *pData++; 357 b[2] = *pData++; b[2] += *pData++; b[2] += *pData++; b[2] += *pData++; 358 b[3] = *pData++; b[3] += *pData++; b[3] += *pData++; b[3] += *pData++; 359 j++; 360 hor++; 361 firstPhase[0] += b[0] + b[1] + b[2] + b[3]; 362 firstPhase[1] += b[0] + b[1] - b[2] - b[3]; 363 } 364 if (col && (pMb-1)->decoded) 365 { 366 L = HANTRO_TRUE; 367 pData = mbPos - 1; 368 l[0] = pData[0]; l[0] += pData[16*width]; 369 l[0] += pData[32*width]; l[0] += pData[48*width]; 370 pData += 64*width; 371 l[1] = pData[0]; l[1] += pData[16*width]; 372 l[1] += pData[32*width]; l[1] += pData[48*width]; 373 pData += 64*width; 374 l[2] = pData[0]; l[2] += pData[16*width]; 375 l[2] += pData[32*width]; l[2] += pData[48*width]; 376 pData += 64*width; 377 l[3] = pData[0]; l[3] += pData[16*width]; 378 l[3] += pData[32*width]; l[3] += pData[48*width]; 379 j++; 380 ver++; 381 firstPhase[0] += l[0] + l[1] + l[2] + l[3]; 382 firstPhase[4] += l[0] + l[1] - l[2] - l[3]; 383 } 384 if ((col != width - 1) && (pMb+1)->decoded) 385 { 386 R = HANTRO_TRUE; 387 pData = mbPos + 16; 388 r[0] = pData[0]; r[0] += pData[16*width]; 389 r[0] += pData[32*width]; r[0] += pData[48*width]; 390 pData += 64*width; 391 r[1] = pData[0]; r[1] += pData[16*width]; 392 r[1] += pData[32*width]; r[1] += pData[48*width]; 393 pData += 64*width; 394 r[2] = pData[0]; r[2] += pData[16*width]; 395 r[2] += pData[32*width]; r[2] += pData[48*width]; 396 pData += 64*width; 397 r[3] = pData[0]; r[3] += pData[16*width]; 398 r[3] += pData[32*width]; r[3] += pData[48*width]; 399 j++; 400 ver++; 401 firstPhase[0] += r[0] + r[1] + r[2] + r[3]; 402 firstPhase[4] += r[0] + r[1] - r[2] - r[3]; 403 } 404 405 /* at least one properly decoded neighbour available */ 406 ASSERT(j); 407 408 /*lint -esym(644,l,r,a,b) variable initialized above */ 409 if (!hor && L && R) 410 firstPhase[1] = (l[0]+l[1]+l[2]+l[3]-r[0]-r[1]-r[2]-r[3]) >> 5; 411 else if (hor) 412 firstPhase[1] >>= (3+hor); 413 414 if (!ver && A && B) 415 firstPhase[4] = (a[0]+a[1]+a[2]+a[3]-b[0]-b[1]-b[2]-b[3]) >> 5; 416 else if (ver) 417 firstPhase[4] >>= (3+ver); 418 419 switch (j) 420 { 421 case 1: 422 firstPhase[0] >>= 4; 423 break; 424 425 case 2: 426 firstPhase[0] >>= 5; 427 break; 428 429 case 3: 430 /* approximate (firstPhase[0]*4/3)>>6 */ 431 firstPhase[0] = (21 * firstPhase[0]) >> 10; 432 break; 433 434 default: /* 4 */ 435 firstPhase[0] >>= 6; 436 break; 437 438 } 439 440 441 Transform(firstPhase); 442 443 for (i = 0, pData = data, pTmp = firstPhase; i < 256;) 444 { 445 tmp = pTmp[(i & 0xF)>>2]; 446 /*lint -e734 CLIP1 macro results in value that fits into 8 bits */ 447 *pData++ = CLIP1(tmp); 448 /*lint +e734 */ 449 450 i++; 451 if (!(i & 0x3F)) 452 pTmp += 4; 453 } 454 455 /* chroma components */ 456 mbPos = currImage->data + width * height * 256 + 457 row * 8 * width * 8 + col * 8; 458 for (comp = 0; comp < 2; comp++) 459 { 460 461 H264SwDecMemset(firstPhase, 0, sizeof(firstPhase)); 462 463 /* counter for number of neighbours used */ 464 j = 0; 465 hor = ver = 0; 466 if (A) 467 { 468 pData = mbPos - width*8; 469 a[0] = *pData++; a[0] += *pData++; 470 a[1] = *pData++; a[1] += *pData++; 471 a[2] = *pData++; a[2] += *pData++; 472 a[3] = *pData++; a[3] += *pData++; 473 j++; 474 hor++; 475 firstPhase[0] += a[0] + a[1] + a[2] + a[3]; 476 firstPhase[1] += a[0] + a[1] - a[2] - a[3]; 477 } 478 if (B) 479 { 480 pData = mbPos + 8*width*8; 481 b[0] = *pData++; b[0] += *pData++; 482 b[1] = *pData++; b[1] += *pData++; 483 b[2] = *pData++; b[2] += *pData++; 484 b[3] = *pData++; b[3] += *pData++; 485 j++; 486 hor++; 487 firstPhase[0] += b[0] + b[1] + b[2] + b[3]; 488 firstPhase[1] += b[0] + b[1] - b[2] - b[3]; 489 } 490 if (L) 491 { 492 pData = mbPos - 1; 493 l[0] = pData[0]; l[0] += pData[8*width]; 494 pData += 16*width; 495 l[1] = pData[0]; l[1] += pData[8*width]; 496 pData += 16*width; 497 l[2] = pData[0]; l[2] += pData[8*width]; 498 pData += 16*width; 499 l[3] = pData[0]; l[3] += pData[8*width]; 500 j++; 501 ver++; 502 firstPhase[0] += l[0] + l[1] + l[2] + l[3]; 503 firstPhase[4] += l[0] + l[1] - l[2] - l[3]; 504 } 505 if (R) 506 { 507 pData = mbPos + 8; 508 r[0] = pData[0]; r[0] += pData[8*width]; 509 pData += 16*width; 510 r[1] = pData[0]; r[1] += pData[8*width]; 511 pData += 16*width; 512 r[2] = pData[0]; r[2] += pData[8*width]; 513 pData += 16*width; 514 r[3] = pData[0]; r[3] += pData[8*width]; 515 j++; 516 ver++; 517 firstPhase[0] += r[0] + r[1] + r[2] + r[3]; 518 firstPhase[4] += r[0] + r[1] - r[2] - r[3]; 519 } 520 if (!hor && L && R) 521 firstPhase[1] = (l[0]+l[1]+l[2]+l[3]-r[0]-r[1]-r[2]-r[3]) >> 4; 522 else if (hor) 523 firstPhase[1] >>= (2+hor); 524 525 if (!ver && A && B) 526 firstPhase[4] = (a[0]+a[1]+a[2]+a[3]-b[0]-b[1]-b[2]-b[3]) >> 4; 527 else if (ver) 528 firstPhase[4] >>= (2+ver); 529 530 switch (j) 531 { 532 case 1: 533 firstPhase[0] >>= 3; 534 break; 535 536 case 2: 537 firstPhase[0] >>= 4; 538 break; 539 540 case 3: 541 /* approximate (firstPhase[0]*4/3)>>5 */ 542 firstPhase[0] = (21 * firstPhase[0]) >> 9; 543 break; 544 545 default: /* 4 */ 546 firstPhase[0] >>= 5; 547 break; 548 549 } 550 551 Transform(firstPhase); 552 553 pData = data + 256 + comp*64; 554 for (i = 0, pTmp = firstPhase; i < 64;) 555 { 556 tmp = pTmp[(i & 0x7)>>1]; 557 /*lint -e734 CLIP1 macro results in value that fits into 8 bits */ 558 *pData++ = CLIP1(tmp); 559 /*lint +e734 */ 560 561 i++; 562 if (!(i & 0xF)) 563 pTmp += 4; 564 } 565 566 /* increment pointers for cr */ 567 mbPos += width * height * 64; 568 } 569 570 h264bsdWriteMacroblock(currImage, data); 571 572 return(HANTRO_OK); 573 574 } 575 576 577 /*------------------------------------------------------------------------------ 578 579 Function name: Transform 580 581 Functional description: 582 Simplified transform, assuming that only dc component and lowest 583 horizontal and lowest vertical component may be non-zero 584 585 ------------------------------------------------------------------------------*/ 586 587 void Transform(i32 *data) 588 { 589 590 u32 col; 591 i32 tmp0, tmp1; 592 593 if (!data[1] && !data[4]) 594 { 595 data[1] = data[2] = data[3] = data[4] = data[5] = 596 data[6] = data[7] = data[8] = data[9] = data[10] = 597 data[11] = data[12] = data[13] = data[14] = data[15] = data[0]; 598 return; 599 } 600 /* first horizontal transform for rows 0 and 1 */ 601 tmp0 = data[0]; 602 tmp1 = data[1]; 603 data[0] = tmp0 + tmp1; 604 data[1] = tmp0 + (tmp1>>1); 605 data[2] = tmp0 - (tmp1>>1); 606 data[3] = tmp0 - tmp1; 607 608 tmp0 = data[4]; 609 data[5] = tmp0; 610 data[6] = tmp0; 611 data[7] = tmp0; 612 613 /* then vertical transform */ 614 for (col = 4; col--; data++) 615 { 616 tmp0 = data[0]; 617 tmp1 = data[4]; 618 data[0] = tmp0 + tmp1; 619 data[4] = tmp0 + (tmp1>>1); 620 data[8] = tmp0 - (tmp1>>1); 621 data[12] = tmp0 - tmp1; 622 } 623 624 } 625 /*lint +e702 */ 626 627