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 #include "H264SwDecApi.h" 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 22 /*------------------------------------------------------------------------------ 23 Module defines 24 ------------------------------------------------------------------------------*/ 25 26 /* CHECK_MEMORY_USAGE prints and sums the memory allocated in calls to 27 * H264SwDecMalloc() */ 28 /* #define CHECK_MEMORY_USAGE */ 29 30 /* _NO_OUT disables output file writing */ 31 /* #define _NO_OUT */ 32 33 /* Debug prints */ 34 #define DEBUG(argv) printf argv 35 36 /* CVS tag name for identification */ 37 const char tagName[256] = "$Name: FIRST_ANDROID_COPYRIGHT $"; 38 39 void WriteOutput(char *filename, u8 *data, u32 picSize); 40 u32 NextPacket(u8 **pStrm); 41 u32 CropPicture(u8 *pOutImage, u8 *pInImage, 42 u32 picWidth, u32 picHeight, CropParams *pCropParams); 43 44 /* Global variables for stream handling */ 45 u8 *streamStop = NULL; 46 u32 packetize = 0; 47 u32 nalUnitStream = 0; 48 FILE *foutput = NULL; 49 50 #ifdef SOC_DESIGNER 51 52 // Initialisation function defined in InitCache.s 53 extern void cache_init(void); 54 55 /*------------------------------------------------------------------------------ 56 57 Function name: $Sub$$main 58 59 Purpose: 60 This function is called at the end of the C library initialisation and 61 before main. Its purpose is to do any further initialisation before the 62 application start. 63 64 ------------------------------------------------------------------------------*/ 65 int $Sub$$main(char argc, char * argv[]) 66 { 67 cache_init(); // does some extra setup work setting up caches 68 return $Super$$main(argc, argv); // calls the original function 69 } 70 #endif 71 72 /*------------------------------------------------------------------------------ 73 74 Function name: main 75 76 Purpose: 77 main function of decoder testbench. Provides command line interface 78 with file I/O for H.264 decoder. Prints out the usage information 79 when executed without arguments. 80 81 ------------------------------------------------------------------------------*/ 82 83 int main(int argc, char **argv) 84 { 85 86 u32 i, tmp; 87 u32 maxNumPics = 0; 88 u8 *byteStrmStart; 89 u8 *imageData; 90 u8 *tmpImage = NULL; 91 u32 strmLen; 92 u32 picSize; 93 H264SwDecInst decInst; 94 H264SwDecRet ret; 95 H264SwDecInput decInput; 96 H264SwDecOutput decOutput; 97 H264SwDecPicture decPicture; 98 H264SwDecInfo decInfo; 99 H264SwDecApiVersion decVer; 100 u32 picDecodeNumber; 101 u32 picDisplayNumber; 102 u32 numErrors = 0; 103 u32 cropDisplay = 0; 104 u32 disableOutputReordering = 0; 105 106 FILE *finput; 107 108 char outFileName[256] = ""; 109 110 /* Print API version number */ 111 decVer = H264SwDecGetAPIVersion(); 112 DEBUG(("H.264 Decoder API v%d.%d\n", decVer.major, decVer.minor)); 113 114 /* Print tag name if '-T' argument present */ 115 if ( argc > 1 && strcmp(argv[1], "-T") == 0 ) 116 { 117 DEBUG(("%s\n", tagName)); 118 return 0; 119 } 120 121 /* Check that enough command line arguments given, if not -> print usage 122 * information out */ 123 if (argc < 2) 124 { 125 DEBUG(( 126 "Usage: %s [-Nn] [-Ooutfile] [-P] [-U] [-C] [-R] [-T] file.h264\n", 127 argv[0])); 128 DEBUG(("\t-Nn forces decoding to stop after n pictures\n")); 129 #if defined(_NO_OUT) 130 DEBUG(("\t-Ooutfile output writing disabled at compile time\n")); 131 #else 132 DEBUG(("\t-Ooutfile write output to \"outfile\" (default out_wxxxhyyy.yuv)\n")); 133 DEBUG(("\t-Onone does not write output\n")); 134 #endif 135 DEBUG(("\t-P packet-by-packet mode\n")); 136 DEBUG(("\t-U NAL unit stream mode\n")); 137 DEBUG(("\t-C display cropped image (default decoded image)\n")); 138 DEBUG(("\t-R disable DPB output reordering\n")); 139 DEBUG(("\t-T to print tag name and exit\n")); 140 return 0; 141 } 142 143 /* read command line arguments */ 144 for (i = 1; i < (u32)(argc-1); i++) 145 { 146 if ( strncmp(argv[i], "-N", 2) == 0 ) 147 { 148 maxNumPics = (u32)atoi(argv[i]+2); 149 } 150 else if ( strncmp(argv[i], "-O", 2) == 0 ) 151 { 152 strcpy(outFileName, argv[i]+2); 153 } 154 else if ( strcmp(argv[i], "-P") == 0 ) 155 { 156 packetize = 1; 157 } 158 else if ( strcmp(argv[i], "-U") == 0 ) 159 { 160 nalUnitStream = 1; 161 } 162 else if ( strcmp(argv[i], "-C") == 0 ) 163 { 164 cropDisplay = 1; 165 } 166 else if ( strcmp(argv[i], "-R") == 0 ) 167 { 168 disableOutputReordering = 1; 169 } 170 } 171 172 /* open input file for reading, file name given by user. If file open 173 * fails -> exit */ 174 finput = fopen(argv[argc-1],"rb"); 175 if (finput == NULL) 176 { 177 DEBUG(("UNABLE TO OPEN INPUT FILE\n")); 178 return -1; 179 } 180 181 /* check size of the input file -> length of the stream in bytes */ 182 fseek(finput,0L,SEEK_END); 183 strmLen = (u32)ftell(finput); 184 rewind(finput); 185 186 /* allocate memory for stream buffer. if unsuccessful -> exit */ 187 byteStrmStart = (u8 *)malloc(sizeof(u8)*strmLen); 188 if (byteStrmStart == NULL) 189 { 190 DEBUG(("UNABLE TO ALLOCATE MEMORY\n")); 191 return -1; 192 } 193 194 /* read input stream from file to buffer and close input file */ 195 fread(byteStrmStart, sizeof(u8), strmLen, finput); 196 fclose(finput); 197 198 /* initialize decoder. If unsuccessful -> exit */ 199 ret = H264SwDecInit(&decInst, disableOutputReordering); 200 if (ret != H264SWDEC_OK) 201 { 202 DEBUG(("DECODER INITIALIZATION FAILED\n")); 203 free(byteStrmStart); 204 return -1; 205 } 206 207 /* initialize H264SwDecDecode() input structure */ 208 streamStop = byteStrmStart + strmLen; 209 decInput.pStream = byteStrmStart; 210 decInput.dataLen = strmLen; 211 decInput.intraConcealmentMethod = 0; 212 213 /* get pointer to next packet and the size of packet 214 * (for packetize or nalUnitStream modes) */ 215 if ( (tmp = NextPacket(&decInput.pStream)) != 0 ) 216 decInput.dataLen = tmp; 217 218 picDecodeNumber = picDisplayNumber = 1; 219 /* main decoding loop */ 220 do 221 { 222 /* Picture ID is the picture number in decoding order */ 223 decInput.picId = picDecodeNumber; 224 225 /* call API function to perform decoding */ 226 ret = H264SwDecDecode(decInst, &decInput, &decOutput); 227 228 switch(ret) 229 { 230 231 case H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY: 232 /* Stream headers were successfully decoded 233 * -> stream information is available for query now */ 234 235 ret = H264SwDecGetInfo(decInst, &decInfo); 236 if (ret != H264SWDEC_OK) 237 return -1; 238 239 DEBUG(("Profile %d\n", decInfo.profile)); 240 241 DEBUG(("Width %d Height %d\n", 242 decInfo.picWidth, decInfo.picHeight)); 243 244 if (cropDisplay && decInfo.croppingFlag) 245 { 246 DEBUG(("Cropping params: (%d, %d) %dx%d\n", 247 decInfo.cropParams.cropLeftOffset, 248 decInfo.cropParams.cropTopOffset, 249 decInfo.cropParams.cropOutWidth, 250 decInfo.cropParams.cropOutHeight)); 251 252 /* Cropped frame size in planar YUV 4:2:0 */ 253 picSize = decInfo.cropParams.cropOutWidth * 254 decInfo.cropParams.cropOutHeight; 255 picSize = (3 * picSize)/2; 256 tmpImage = malloc(picSize); 257 if (tmpImage == NULL) 258 return -1; 259 } 260 else 261 { 262 /* Decoder output frame size in planar YUV 4:2:0 */ 263 picSize = decInfo.picWidth * decInfo.picHeight; 264 picSize = (3 * picSize)/2; 265 } 266 267 DEBUG(("videoRange %d, matrixCoefficients %d\n", 268 decInfo.videoRange, decInfo.matrixCoefficients)); 269 270 /* update H264SwDecDecode() input structure, number of bytes 271 * "consumed" is computed as difference between the new stream 272 * pointer and old stream pointer */ 273 decInput.dataLen -= 274 (u32)(decOutput.pStrmCurrPos - decInput.pStream); 275 decInput.pStream = decOutput.pStrmCurrPos; 276 277 /* If -O option not used, generate default file name */ 278 if (outFileName[0] == 0) 279 sprintf(outFileName, "out_w%dh%d.yuv", 280 decInfo.picWidth, decInfo.picHeight); 281 break; 282 283 case H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY: 284 /* Picture is ready and more data remains in input buffer 285 * -> update H264SwDecDecode() input structure, number of bytes 286 * "consumed" is computed as difference between the new stream 287 * pointer and old stream pointer */ 288 decInput.dataLen -= 289 (u32)(decOutput.pStrmCurrPos - decInput.pStream); 290 decInput.pStream = decOutput.pStrmCurrPos; 291 /* fall through */ 292 293 case H264SWDEC_PIC_RDY: 294 295 /*lint -esym(644,tmpImage,picSize) variable initialized at 296 * H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY case */ 297 298 if (ret == H264SWDEC_PIC_RDY) 299 decInput.dataLen = NextPacket(&decInput.pStream); 300 301 /* If enough pictures decoded -> force decoding to end 302 * by setting that no more stream is available */ 303 if (maxNumPics && picDecodeNumber == maxNumPics) 304 decInput.dataLen = 0; 305 306 /* Increment decoding number for every decoded picture */ 307 picDecodeNumber++; 308 309 /* use function H264SwDecNextPicture() to obtain next picture 310 * in display order. Function is called until no more images 311 * are ready for display */ 312 while ( H264SwDecNextPicture(decInst, &decPicture, 0) == 313 H264SWDEC_PIC_RDY ) 314 { 315 DEBUG(("PIC %d, type %s", picDisplayNumber, 316 decPicture.isIdrPicture ? "IDR" : "NON-IDR")); 317 if (picDisplayNumber != decPicture.picId) 318 DEBUG((", decoded pic %d", decPicture.picId)); 319 if (decPicture.nbrOfErrMBs) 320 { 321 DEBUG((", concealed %d\n", decPicture.nbrOfErrMBs)); 322 } 323 else 324 DEBUG(("\n")); 325 fflush(stdout); 326 327 numErrors += decPicture.nbrOfErrMBs; 328 329 /* Increment display number for every displayed picture */ 330 picDisplayNumber++; 331 332 /*lint -esym(644,decInfo) always initialized if pictures 333 * available for display */ 334 335 /* Write output picture to file */ 336 imageData = (u8*)decPicture.pOutputPicture; 337 if (cropDisplay && decInfo.croppingFlag) 338 { 339 tmp = CropPicture(tmpImage, imageData, 340 decInfo.picWidth, decInfo.picHeight, 341 &decInfo.cropParams); 342 if (tmp) 343 return -1; 344 WriteOutput(outFileName, tmpImage, picSize); 345 } 346 else 347 { 348 WriteOutput(outFileName, imageData, picSize); 349 } 350 } 351 352 break; 353 354 case H264SWDEC_STRM_PROCESSED: 355 case H264SWDEC_STRM_ERR: 356 /* Input stream was decoded but no picture is ready 357 * -> Get more data */ 358 decInput.dataLen = NextPacket(&decInput.pStream); 359 break; 360 361 default: 362 DEBUG(("FATAL ERROR\n")); 363 return -1; 364 365 } 366 /* keep decoding until all data from input stream buffer consumed */ 367 } while (decInput.dataLen > 0); 368 369 /* if output in display order is preferred, the decoder shall be forced 370 * to output pictures remaining in decoded picture buffer. Use function 371 * H264SwDecNextPicture() to obtain next picture in display order. Function 372 * is called until no more images are ready for display. Second parameter 373 * for the function is set to '1' to indicate that this is end of the 374 * stream and all pictures shall be output */ 375 while (H264SwDecNextPicture(decInst, &decPicture, 1) == H264SWDEC_PIC_RDY) 376 { 377 DEBUG(("PIC %d, type %s", picDisplayNumber, 378 decPicture.isIdrPicture ? "IDR" : "NON-IDR")); 379 if (picDisplayNumber != decPicture.picId) 380 DEBUG((", decoded pic %d", decPicture.picId)); 381 if (decPicture.nbrOfErrMBs) 382 { 383 DEBUG((", concealed %d\n", decPicture.nbrOfErrMBs)); 384 } 385 else 386 DEBUG(("\n")); 387 fflush(stdout); 388 389 numErrors += decPicture.nbrOfErrMBs; 390 391 /* Increment display number for every displayed picture */ 392 picDisplayNumber++; 393 394 /* Write output picture to file */ 395 imageData = (u8*)decPicture.pOutputPicture; 396 if (cropDisplay && decInfo.croppingFlag) 397 { 398 tmp = CropPicture(tmpImage, imageData, 399 decInfo.picWidth, decInfo.picHeight, 400 &decInfo.cropParams); 401 if (tmp) 402 return -1; 403 WriteOutput(outFileName, tmpImage, picSize); 404 } 405 else 406 { 407 WriteOutput(outFileName, imageData, picSize); 408 } 409 } 410 411 /* release decoder instance */ 412 H264SwDecRelease(decInst); 413 414 if (foutput) 415 fclose(foutput); 416 417 /* free allocated buffers */ 418 free(byteStrmStart); 419 free(tmpImage); 420 421 DEBUG(("Output file: %s\n", outFileName)); 422 423 DEBUG(("DECODING DONE\n")); 424 if (numErrors || picDecodeNumber == 1) 425 { 426 DEBUG(("ERRORS FOUND\n")); 427 return 1; 428 } 429 430 return 0; 431 } 432 433 /*------------------------------------------------------------------------------ 434 435 Function name: WriteOutput 436 437 Purpose: 438 Write picture pointed by data to file. Size of the 439 picture in pixels is indicated by picSize. 440 441 ------------------------------------------------------------------------------*/ 442 void WriteOutput(char *filename, u8 *data, u32 picSize) 443 { 444 445 /* foutput is global file pointer */ 446 if (foutput == NULL) 447 { 448 /* open output file for writing, can be disabled with define. 449 * If file open fails -> exit */ 450 if (strcmp(filename, "none") != 0) 451 { 452 #if !defined(_NO_OUT) 453 foutput = fopen(filename, "wb"); 454 if (foutput == NULL) 455 { 456 DEBUG(("UNABLE TO OPEN OUTPUT FILE\n")); 457 exit(100); 458 } 459 #endif 460 } 461 } 462 463 if (foutput && data) 464 fwrite(data, 1, picSize, foutput); 465 } 466 467 /*------------------------------------------------------------------------------ 468 469 Function name: NextPacket 470 471 Purpose: 472 Get the pointer to start of next packet in input stream. Uses 473 global variables 'packetize' and 'nalUnitStream' to determine the 474 decoder input stream mode and 'streamStop' to determine the end 475 of stream. There are three possible stream modes: 476 default - the whole stream at once 477 packetize - a single NAL-unit with start code prefix 478 nalUnitStream - a single NAL-unit without start code prefix 479 480 pStrm stores pointer to the start of previous decoder input and is 481 replaced with pointer to the start of the next decoder input. 482 483 Returns the packet size in bytes 484 485 ------------------------------------------------------------------------------*/ 486 u32 NextPacket(u8 **pStrm) 487 { 488 489 u32 index; 490 u32 maxIndex; 491 u32 zeroCount; 492 u8 *stream; 493 u8 byte; 494 static u32 prevIndex=0; 495 496 /* For default stream mode all the stream is in first packet */ 497 if (!packetize && !nalUnitStream) 498 return 0; 499 500 index = 0; 501 stream = *pStrm + prevIndex; 502 maxIndex = (u32)(streamStop - stream); 503 504 if (maxIndex == 0) 505 return(0); 506 507 /* leading zeros of first NAL unit */ 508 do 509 { 510 byte = stream[index++]; 511 } while (byte != 1 && index < maxIndex); 512 513 /* invalid start code prefix */ 514 if (index == maxIndex || index < 3) 515 { 516 DEBUG(("INVALID BYTE STREAM\n")); 517 exit(100); 518 } 519 520 /* nalUnitStream is without start code prefix */ 521 if (nalUnitStream) 522 { 523 stream += index; 524 maxIndex -= index; 525 index = 0; 526 } 527 528 zeroCount = 0; 529 530 /* Search stream for next start code prefix */ 531 /*lint -e(716) while(1) used consciously */ 532 while (1) 533 { 534 byte = stream[index++]; 535 if (!byte) 536 zeroCount++; 537 538 if ( (byte == 0x01) && (zeroCount >= 2) ) 539 { 540 /* Start code prefix has two zeros 541 * Third zero is assumed to be leading zero of next packet 542 * Fourth and more zeros are assumed to be trailing zeros of this 543 * packet */ 544 if (zeroCount > 3) 545 { 546 index -= 4; 547 zeroCount -= 3; 548 } 549 else 550 { 551 index -= zeroCount+1; 552 zeroCount = 0; 553 } 554 break; 555 } 556 else if (byte) 557 zeroCount = 0; 558 559 if (index == maxIndex) 560 { 561 break; 562 } 563 564 } 565 566 /* Store pointer to the beginning of the packet */ 567 *pStrm = stream; 568 prevIndex = index; 569 570 /* nalUnitStream is without trailing zeros */ 571 if (nalUnitStream) 572 index -= zeroCount; 573 574 return(index); 575 576 } 577 578 /*------------------------------------------------------------------------------ 579 580 Function name: CropPicture 581 582 Purpose: 583 Perform cropping for picture. Input picture pInImage with dimensions 584 picWidth x picHeight is cropped with pCropParams and the resulting 585 picture is stored in pOutImage. 586 587 ------------------------------------------------------------------------------*/ 588 u32 CropPicture(u8 *pOutImage, u8 *pInImage, 589 u32 picWidth, u32 picHeight, CropParams *pCropParams) 590 { 591 592 u32 i, j; 593 u32 outWidth, outHeight; 594 u8 *pOut, *pIn; 595 596 if (pOutImage == NULL || pInImage == NULL || pCropParams == NULL || 597 !picWidth || !picHeight) 598 { 599 /* just to prevent lint warning, returning non-zero will result in 600 * return without freeing the memory */ 601 free(pOutImage); 602 return(1); 603 } 604 605 if ( ((pCropParams->cropLeftOffset + pCropParams->cropOutWidth) > 606 picWidth ) || 607 ((pCropParams->cropTopOffset + pCropParams->cropOutHeight) > 608 picHeight ) ) 609 { 610 /* just to prevent lint warning, returning non-zero will result in 611 * return without freeing the memory */ 612 free(pOutImage); 613 return(1); 614 } 615 616 outWidth = pCropParams->cropOutWidth; 617 outHeight = pCropParams->cropOutHeight; 618 619 /* Calculate starting pointer for luma */ 620 pIn = pInImage + pCropParams->cropTopOffset*picWidth + 621 pCropParams->cropLeftOffset; 622 pOut = pOutImage; 623 624 /* Copy luma pixel values */ 625 for (i = outHeight; i; i--) 626 { 627 for (j = outWidth; j; j--) 628 { 629 *pOut++ = *pIn++; 630 } 631 pIn += picWidth - outWidth; 632 } 633 634 outWidth >>= 1; 635 outHeight >>= 1; 636 637 /* Calculate starting pointer for cb */ 638 pIn = pInImage + picWidth*picHeight + 639 pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2; 640 641 /* Copy cb pixel values */ 642 for (i = outHeight; i; i--) 643 { 644 for (j = outWidth; j; j--) 645 { 646 *pOut++ = *pIn++; 647 } 648 pIn += picWidth/2 - outWidth; 649 } 650 651 /* Calculate starting pointer for cr */ 652 pIn = pInImage + 5*picWidth*picHeight/4 + 653 pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2; 654 655 /* Copy cr pixel values */ 656 for (i = outHeight; i; i--) 657 { 658 for (j = outWidth; j; j--) 659 { 660 *pOut++ = *pIn++; 661 } 662 pIn += picWidth/2 - outWidth; 663 } 664 665 return (0); 666 } 667 668 /*------------------------------------------------------------------------------ 669 670 Function name: H264SwDecTrace 671 672 Purpose: 673 Example implementation of H264SwDecTrace function. Prototype of this 674 function is given in H264SwDecApi.h. This implementation appends 675 trace messages to file named 'dec_api.trc'. 676 677 ------------------------------------------------------------------------------*/ 678 void H264SwDecTrace(char *string) 679 { 680 FILE *fp; 681 682 fp = fopen("dec_api.trc", "at"); 683 684 if (!fp) 685 return; 686 687 fwrite(string, 1, strlen(string), fp); 688 fwrite("\n", 1,1, fp); 689 690 fclose(fp); 691 } 692 693 /*------------------------------------------------------------------------------ 694 695 Function name: H264SwDecMalloc 696 697 Purpose: 698 Example implementation of H264SwDecMalloc function. Prototype of this 699 function is given in H264SwDecApi.h. This implementation uses 700 library function malloc for allocation of memory. 701 702 ------------------------------------------------------------------------------*/ 703 void* H264SwDecMalloc(u32 size) 704 { 705 706 #if defined(CHECK_MEMORY_USAGE) 707 /* Note that if the decoder has to free and reallocate some of the buffers 708 * the total value will be invalid */ 709 static u32 numBytes = 0; 710 numBytes += size; 711 DEBUG(("Allocated %d bytes, total %d\n", size, numBytes)); 712 #endif 713 714 return malloc(size); 715 } 716 717 /*------------------------------------------------------------------------------ 718 719 Function name: H264SwDecFree 720 721 Purpose: 722 Example implementation of H264SwDecFree function. Prototype of this 723 function is given in H264SwDecApi.h. This implementation uses 724 library function free for freeing of memory. 725 726 ------------------------------------------------------------------------------*/ 727 void H264SwDecFree(void *ptr) 728 { 729 free(ptr); 730 } 731 732 /*------------------------------------------------------------------------------ 733 734 Function name: H264SwDecMemcpy 735 736 Purpose: 737 Example implementation of H264SwDecMemcpy function. Prototype of this 738 function is given in H264SwDecApi.h. This implementation uses 739 library function memcpy to copy src to dest. 740 741 ------------------------------------------------------------------------------*/ 742 void H264SwDecMemcpy(void *dest, void *src, u32 count) 743 { 744 memcpy(dest, src, count); 745 } 746 747 /*------------------------------------------------------------------------------ 748 749 Function name: H264SwDecMemset 750 751 Purpose: 752 Example implementation of H264SwDecMemset function. Prototype of this 753 function is given in H264SwDecApi.h. This implementation uses 754 library function memset to set content of memory area pointed by ptr. 755 756 ------------------------------------------------------------------------------*/ 757 void H264SwDecMemset(void *ptr, i32 value, u32 count) 758 { 759 memset(ptr, value, count); 760 } 761 762