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/* CVS tag name for identification */ 18const char tagName[256] = "$Name: FIRST_ANDROID_COPYRIGHT $"; 19 20#include "H264SwDecApi.h" 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24 25#define DEBUG(argv) printf argv 26 27/* _NO_OUT disables output file writing */ 28#ifdef __arm 29#define _NO_OUT 30#endif 31 32/*------------------------------------------------------------------------------ 33 34------------------------------------------------------------------------------*/ 35void WriteOutput(FILE *fid, u8 *data, u32 picSize); 36 37u32 CropPicture(u8 *pOutImage, u8 *pInImage, 38 u32 picWidth, u32 picHeight, CropParams *pCropParams); 39 40void CropWriteOutput(FILE *fid, u8 *imageData, u32 cropDisplay, 41 H264SwDecInfo *decInfo); 42 43typedef struct 44{ 45 H264SwDecInst decInst; 46 H264SwDecInput decInput; 47 H264SwDecOutput decOutput; 48 H264SwDecPicture decPicture; 49 H264SwDecInfo decInfo; 50 FILE *foutput; 51 char outFileName[256]; 52 u8 *byteStrmStart; 53 u32 picNumber; 54} Decoder; 55 56 57/*------------------------------------------------------------------------------ 58 59------------------------------------------------------------------------------*/ 60int main(int argc, char **argv) 61{ 62 63 i32 instCount, instRunning; 64 i32 i; 65 u32 maxNumPics; 66 u32 strmLen; 67 H264SwDecRet ret; 68 u32 numErrors = 0; 69 u32 cropDisplay = 0; 70 u32 disableOutputReordering = 0; 71 FILE *finput; 72 Decoder **decoder; 73 char outFileName[256] = "out.yuv"; 74 75 76 if ( argc > 1 && strcmp(argv[1], "-T") == 0 ) 77 { 78 fprintf(stderr, "%s\n", tagName); 79 return 0; 80 } 81 82 if (argc < 2) 83 { 84 DEBUG(( 85 "Usage: %s [-Nn] [-Ooutfile] [-P] [-U] [-C] [-R] [-T] file1.264 [file2.264] .. [fileN.264]\n", 86 argv[0])); 87 DEBUG(("\t-Nn forces decoding to stop after n pictures\n")); 88#if defined(_NO_OUT) 89 DEBUG(("\t-Ooutfile output writing disabled at compile time\n")); 90#else 91 DEBUG(("\t-Ooutfile write output to \"outfile\" (default out.yuv)\n")); 92 DEBUG(("\t-Onone does not write output\n")); 93#endif 94 DEBUG(("\t-C display cropped image (default decoded image)\n")); 95 DEBUG(("\t-R disable DPB output reordering\n")); 96 DEBUG(("\t-T to print tag name and exit\n")); 97 exit(100); 98 } 99 100 instCount = argc - 1; 101 102 /* read command line arguments */ 103 maxNumPics = 0; 104 for (i = 1; i < (argc-1); i++) 105 { 106 if ( strncmp(argv[i], "-N", 2) == 0 ) 107 { 108 maxNumPics = (u32)atoi(argv[i]+2); 109 instCount--; 110 } 111 else if ( strncmp(argv[i], "-O", 2) == 0 ) 112 { 113 strcpy(outFileName, argv[i]+2); 114 instCount--; 115 } 116 else if ( strcmp(argv[i], "-C") == 0 ) 117 { 118 cropDisplay = 1; 119 instCount--; 120 } 121 else if ( strcmp(argv[i], "-R") == 0 ) 122 { 123 disableOutputReordering = 1; 124 instCount--; 125 } 126 } 127 128 if (instCount < 1) 129 { 130 DEBUG(("No input files\n")); 131 exit(100); 132 } 133 134 /* allocate memory for multiple decoder instances 135 * one instance for every stream file */ 136 decoder = (Decoder **)malloc(sizeof(Decoder*)*(u32)instCount); 137 if (decoder == NULL) 138 { 139 DEBUG(("Unable to allocate memory\n")); 140 exit(100); 141 } 142 143 /* prepare each decoder instance */ 144 for (i = 0; i < instCount; i++) 145 { 146 decoder[i] = (Decoder *)calloc(1, sizeof(Decoder)); 147 148 /* open input file */ 149 finput = fopen(argv[argc-instCount+i],"rb"); 150 if (finput == NULL) 151 { 152 DEBUG(("Unable to open input file <%s>\n", argv[argc-instCount+i])); 153 exit(100); 154 } 155 156 DEBUG(("Reading input file[%d] %s\n", i, argv[argc-instCount+i])); 157 158 /* read input stream to buffer */ 159 fseek(finput,0L,SEEK_END); 160 strmLen = (u32)ftell(finput); 161 rewind(finput); 162 decoder[i]->byteStrmStart = (u8 *)malloc(sizeof(u8)*strmLen); 163 if (decoder[i]->byteStrmStart == NULL) 164 { 165 DEBUG(("Unable to allocate memory\n")); 166 exit(100); 167 } 168 fread(decoder[i]->byteStrmStart, sizeof(u8), strmLen, finput); 169 fclose(finput); 170 171 /* open output file */ 172 if (strcmp(outFileName, "none") != 0) 173 { 174#if defined(_NO_OUT) 175 decoder[i]->foutput = NULL; 176#else 177 sprintf(decoder[i]->outFileName, "%s%i", outFileName, i); 178 decoder[i]->foutput = fopen(decoder[i]->outFileName, "wb"); 179 if (decoder[i]->foutput == NULL) 180 { 181 DEBUG(("Unable to open output file\n")); 182 exit(100); 183 } 184#endif 185 } 186 187 ret = H264SwDecInit(&(decoder[i]->decInst), disableOutputReordering); 188 189 if (ret != H264SWDEC_OK) 190 { 191 DEBUG(("Init failed %d\n", ret)); 192 exit(100); 193 } 194 195 decoder[i]->decInput.pStream = decoder[i]->byteStrmStart; 196 decoder[i]->decInput.dataLen = strmLen; 197 decoder[i]->decInput.intraConcealmentMethod = 0; 198 199 } 200 201 /* main decoding loop */ 202 do 203 { 204 /* decode once using each instance */ 205 for (i = 0; i < instCount; i++) 206 { 207 ret = H264SwDecDecode(decoder[i]->decInst, 208 &(decoder[i]->decInput), 209 &(decoder[i]->decOutput)); 210 211 switch(ret) 212 { 213 214 case H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY: 215 216 ret = H264SwDecGetInfo(decoder[i]->decInst, 217 &(decoder[i]->decInfo)); 218 if (ret != H264SWDEC_OK) 219 exit(1); 220 221 if (cropDisplay && decoder[i]->decInfo.croppingFlag) 222 { 223 DEBUG(("Decoder[%d] Cropping params: (%d, %d) %dx%d\n", 224 i, 225 decoder[i]->decInfo.cropParams.cropLeftOffset, 226 decoder[i]->decInfo.cropParams.cropTopOffset, 227 decoder[i]->decInfo.cropParams.cropOutWidth, 228 decoder[i]->decInfo.cropParams.cropOutHeight)); 229 } 230 231 DEBUG(("Decoder[%d] Width %d Height %d\n", i, 232 decoder[i]->decInfo.picWidth, 233 decoder[i]->decInfo.picHeight)); 234 235 DEBUG(("Decoder[%d] videoRange %d, matricCoefficients %d\n", 236 i, decoder[i]->decInfo.videoRange, 237 decoder[i]->decInfo.matrixCoefficients)); 238 decoder[i]->decInput.dataLen -= 239 (u32)(decoder[i]->decOutput.pStrmCurrPos - 240 decoder[i]->decInput.pStream); 241 decoder[i]->decInput.pStream = 242 decoder[i]->decOutput.pStrmCurrPos; 243 break; 244 245 case H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY: 246 decoder[i]->decInput.dataLen -= 247 (u32)(decoder[i]->decOutput.pStrmCurrPos - 248 decoder[i]->decInput.pStream); 249 decoder[i]->decInput.pStream = 250 decoder[i]->decOutput.pStrmCurrPos; 251 /* fall through */ 252 case H264SWDEC_PIC_RDY: 253 if (ret == H264SWDEC_PIC_RDY) 254 decoder[i]->decInput.dataLen = 0; 255 256 ret = H264SwDecGetInfo(decoder[i]->decInst, 257 &(decoder[i]->decInfo)); 258 if (ret != H264SWDEC_OK) 259 exit(1); 260 261 while (H264SwDecNextPicture(decoder[i]->decInst, 262 &(decoder[i]->decPicture), 0) == H264SWDEC_PIC_RDY) 263 { 264 decoder[i]->picNumber++; 265 266 numErrors += decoder[i]->decPicture.nbrOfErrMBs; 267 268 DEBUG(("Decoder[%d] PIC %d, type %s, concealed %d\n", 269 i, decoder[i]->picNumber, 270 decoder[i]->decPicture.isIdrPicture 271 ? "IDR" : "NON-IDR", 272 decoder[i]->decPicture.nbrOfErrMBs)); 273 fflush(stdout); 274 275 CropWriteOutput(decoder[i]->foutput, 276 (u8*)decoder[i]->decPicture.pOutputPicture, 277 cropDisplay, &(decoder[i]->decInfo)); 278 } 279 280 if (maxNumPics && decoder[i]->picNumber == maxNumPics) 281 decoder[i]->decInput.dataLen = 0; 282 break; 283 284 case H264SWDEC_STRM_PROCESSED: 285 case H264SWDEC_STRM_ERR: 286 case H264SWDEC_PARAM_ERR: 287 decoder[i]->decInput.dataLen = 0; 288 break; 289 290 default: 291 DEBUG(("Decoder[%d] FATAL ERROR\n", i)); 292 exit(10); 293 break; 294 295 } 296 } 297 298 /* check if any of the instances is still running (=has more data) */ 299 instRunning = instCount; 300 for (i = 0; i < instCount; i++) 301 { 302 if (decoder[i]->decInput.dataLen == 0) 303 instRunning--; 304 } 305 306 } while (instRunning); 307 308 309 /* get last frames and close each instance */ 310 for (i = 0; i < instCount; i++) 311 { 312 while (H264SwDecNextPicture(decoder[i]->decInst, 313 &(decoder[i]->decPicture), 1) == H264SWDEC_PIC_RDY) 314 { 315 decoder[i]->picNumber++; 316 317 DEBUG(("Decoder[%d] PIC %d, type %s, concealed %d\n", 318 i, decoder[i]->picNumber, 319 decoder[i]->decPicture.isIdrPicture 320 ? "IDR" : "NON-IDR", 321 decoder[i]->decPicture.nbrOfErrMBs)); 322 fflush(stdout); 323 324 CropWriteOutput(decoder[i]->foutput, 325 (u8*)decoder[i]->decPicture.pOutputPicture, 326 cropDisplay, &(decoder[i]->decInfo)); 327 } 328 329 H264SwDecRelease(decoder[i]->decInst); 330 331 if (decoder[i]->foutput) 332 fclose(decoder[i]->foutput); 333 334 free(decoder[i]->byteStrmStart); 335 336 free(decoder[i]); 337 } 338 339 free(decoder); 340 341 if (numErrors) 342 return 1; 343 else 344 return 0; 345 346} 347 348/*------------------------------------------------------------------------------ 349 350------------------------------------------------------------------------------*/ 351void CropWriteOutput(FILE *foutput, u8 *imageData, u32 cropDisplay, 352 H264SwDecInfo *decInfo) 353{ 354 u8 *tmpImage = NULL; 355 u32 tmp, picSize; 356 357 if (cropDisplay && decInfo->croppingFlag) 358 { 359 picSize = decInfo->cropParams.cropOutWidth * 360 decInfo->cropParams.cropOutHeight; 361 picSize = (3 * picSize)/2; 362 tmpImage = malloc(picSize); 363 if (tmpImage == NULL) 364 exit(1); 365 tmp = CropPicture(tmpImage, imageData, 366 decInfo->picWidth, decInfo->picHeight, 367 &(decInfo->cropParams)); 368 if (tmp) 369 exit(1); 370 WriteOutput(foutput, tmpImage, picSize); 371 free(tmpImage); 372 } 373 else 374 { 375 picSize = decInfo->picWidth * decInfo->picHeight; 376 picSize = (3 * picSize)/2; 377 WriteOutput(foutput, imageData, picSize); 378 } 379 380} 381 382/*------------------------------------------------------------------------------ 383 384------------------------------------------------------------------------------*/ 385void WriteOutput(FILE *fid, u8 *data, u32 picSize) 386{ 387 if (fid) 388 fwrite(data, 1, picSize, fid); 389} 390 391/*------------------------------------------------------------------------------ 392 393 Function name: H264SwDecTrace 394 395------------------------------------------------------------------------------*/ 396void H264SwDecTrace(char *string) 397{ 398 FILE *fp; 399 400 fp = fopen("dec_api.trc", "at"); 401 402 if (!fp) 403 return; 404 405 fwrite(string, 1, strlen(string), fp); 406 fwrite("\n", 1,1, fp); 407 408 fclose(fp); 409} 410 411/*------------------------------------------------------------------------------ 412 413 Function name: H264SwDecmalloc 414 415------------------------------------------------------------------------------*/ 416void* H264SwDecMalloc(u32 size) 417{ 418 return malloc(size); 419} 420 421/*------------------------------------------------------------------------------ 422 423 Function name: H264SwDecFree 424 425------------------------------------------------------------------------------*/ 426void H264SwDecFree(void *ptr) 427{ 428 free(ptr); 429} 430 431/*------------------------------------------------------------------------------ 432 433 Function name: H264SwDecMemcpy 434 435------------------------------------------------------------------------------*/ 436void H264SwDecMemcpy(void *dest, void *src, u32 count) 437{ 438 memcpy(dest, src, count); 439} 440 441/*------------------------------------------------------------------------------ 442 443 Function name: H264SwDecMemset 444 445------------------------------------------------------------------------------*/ 446void H264SwDecMemset(void *ptr, i32 value, u32 count) 447{ 448 memset(ptr, value, count); 449} 450 451/*------------------------------------------------------------------------------ 452 453 Function name: CropPicture 454 455------------------------------------------------------------------------------*/ 456u32 CropPicture(u8 *pOutImage, u8 *pInImage, 457 u32 picWidth, u32 picHeight, CropParams *pCropParams) 458{ 459 460 u32 i, j; 461 u32 outWidth, outHeight; 462 u8 *pOut, *pIn; 463 464 if (pOutImage == NULL || pInImage == NULL || pCropParams == NULL || 465 !picWidth || !picHeight) 466 { 467 /* due to lint warning */ 468 free(pOutImage); 469 return(1); 470 } 471 472 if ( ((pCropParams->cropLeftOffset + pCropParams->cropOutWidth) > 473 picWidth ) || 474 ((pCropParams->cropTopOffset + pCropParams->cropOutHeight) > 475 picHeight ) ) 476 { 477 /* due to lint warning */ 478 free(pOutImage); 479 return(1); 480 } 481 482 outWidth = pCropParams->cropOutWidth; 483 outHeight = pCropParams->cropOutHeight; 484 485 pIn = pInImage + pCropParams->cropTopOffset*picWidth + 486 pCropParams->cropLeftOffset; 487 pOut = pOutImage; 488 489 /* luma */ 490 for (i = outHeight; i; i--) 491 { 492 for (j = outWidth; j; j--) 493 { 494 *pOut++ = *pIn++; 495 } 496 pIn += picWidth - outWidth; 497 } 498 499 outWidth >>= 1; 500 outHeight >>= 1; 501 502 pIn = pInImage + picWidth*picHeight + 503 pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2; 504 505 /* cb */ 506 for (i = outHeight; i; i--) 507 { 508 for (j = outWidth; j; j--) 509 { 510 *pOut++ = *pIn++; 511 } 512 pIn += picWidth/2 - outWidth; 513 } 514 515 pIn = pInImage + 5*picWidth*picHeight/4 + 516 pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2; 517 518 /* cr */ 519 for (i = outHeight; i; i--) 520 { 521 for (j = outWidth; j; j--) 522 { 523 *pOut++ = *pIn++; 524 } 525 pIn += picWidth/2 - outWidth; 526 } 527 528 return (0); 529 530} 531 532