/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* CVS tag name for identification */ const char tagName[256] = "$Name: FIRST_ANDROID_COPYRIGHT $"; #include "H264SwDecApi.h" #include #include #include #define DEBUG(argv) printf argv /* _NO_OUT disables output file writing */ #ifdef __arm #define _NO_OUT #endif /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ void WriteOutput(FILE *fid, u8 *data, u32 picSize); u32 CropPicture(u8 *pOutImage, u8 *pInImage, u32 picWidth, u32 picHeight, CropParams *pCropParams); void CropWriteOutput(FILE *fid, u8 *imageData, u32 cropDisplay, H264SwDecInfo *decInfo); typedef struct { H264SwDecInst decInst; H264SwDecInput decInput; H264SwDecOutput decOutput; H264SwDecPicture decPicture; H264SwDecInfo decInfo; FILE *foutput; char outFileName[256]; u8 *byteStrmStart; u32 picNumber; } Decoder; /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ int main(int argc, char **argv) { i32 instCount, instRunning; i32 i; u32 maxNumPics; u32 strmLen; H264SwDecRet ret; u32 numErrors = 0; u32 cropDisplay = 0; u32 disableOutputReordering = 0; FILE *finput; Decoder **decoder; char outFileName[256] = "out.yuv"; if ( argc > 1 && strcmp(argv[1], "-T") == 0 ) { fprintf(stderr, "%s\n", tagName); return 0; } if (argc < 2) { DEBUG(( "Usage: %s [-Nn] [-Ooutfile] [-P] [-U] [-C] [-R] [-T] file1.264 [file2.264] .. [fileN.264]\n", argv[0])); DEBUG(("\t-Nn forces decoding to stop after n pictures\n")); #if defined(_NO_OUT) DEBUG(("\t-Ooutfile output writing disabled at compile time\n")); #else DEBUG(("\t-Ooutfile write output to \"outfile\" (default out.yuv)\n")); DEBUG(("\t-Onone does not write output\n")); #endif DEBUG(("\t-C display cropped image (default decoded image)\n")); DEBUG(("\t-R disable DPB output reordering\n")); DEBUG(("\t-T to print tag name and exit\n")); exit(100); } instCount = argc - 1; /* read command line arguments */ maxNumPics = 0; for (i = 1; i < (argc-1); i++) { if ( strncmp(argv[i], "-N", 2) == 0 ) { maxNumPics = (u32)atoi(argv[i]+2); instCount--; } else if ( strncmp(argv[i], "-O", 2) == 0 ) { strcpy(outFileName, argv[i]+2); instCount--; } else if ( strcmp(argv[i], "-C") == 0 ) { cropDisplay = 1; instCount--; } else if ( strcmp(argv[i], "-R") == 0 ) { disableOutputReordering = 1; instCount--; } } if (instCount < 1) { DEBUG(("No input files\n")); exit(100); } /* allocate memory for multiple decoder instances * one instance for every stream file */ decoder = (Decoder **)malloc(sizeof(Decoder*)*(u32)instCount); if (decoder == NULL) { DEBUG(("Unable to allocate memory\n")); exit(100); } /* prepare each decoder instance */ for (i = 0; i < instCount; i++) { decoder[i] = (Decoder *)calloc(1, sizeof(Decoder)); /* open input file */ finput = fopen(argv[argc-instCount+i],"rb"); if (finput == NULL) { DEBUG(("Unable to open input file <%s>\n", argv[argc-instCount+i])); exit(100); } DEBUG(("Reading input file[%d] %s\n", i, argv[argc-instCount+i])); /* read input stream to buffer */ fseek(finput,0L,SEEK_END); strmLen = (u32)ftell(finput); rewind(finput); decoder[i]->byteStrmStart = (u8 *)malloc(sizeof(u8)*strmLen); if (decoder[i]->byteStrmStart == NULL) { DEBUG(("Unable to allocate memory\n")); exit(100); } fread(decoder[i]->byteStrmStart, sizeof(u8), strmLen, finput); fclose(finput); /* open output file */ if (strcmp(outFileName, "none") != 0) { #if defined(_NO_OUT) decoder[i]->foutput = NULL; #else sprintf(decoder[i]->outFileName, "%s%i", outFileName, i); decoder[i]->foutput = fopen(decoder[i]->outFileName, "wb"); if (decoder[i]->foutput == NULL) { DEBUG(("Unable to open output file\n")); exit(100); } #endif } ret = H264SwDecInit(&(decoder[i]->decInst), disableOutputReordering); if (ret != H264SWDEC_OK) { DEBUG(("Init failed %d\n", ret)); exit(100); } decoder[i]->decInput.pStream = decoder[i]->byteStrmStart; decoder[i]->decInput.dataLen = strmLen; decoder[i]->decInput.intraConcealmentMethod = 0; } /* main decoding loop */ do { /* decode once using each instance */ for (i = 0; i < instCount; i++) { ret = H264SwDecDecode(decoder[i]->decInst, &(decoder[i]->decInput), &(decoder[i]->decOutput)); switch(ret) { case H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY: ret = H264SwDecGetInfo(decoder[i]->decInst, &(decoder[i]->decInfo)); if (ret != H264SWDEC_OK) exit(1); if (cropDisplay && decoder[i]->decInfo.croppingFlag) { DEBUG(("Decoder[%d] Cropping params: (%d, %d) %dx%d\n", i, decoder[i]->decInfo.cropParams.cropLeftOffset, decoder[i]->decInfo.cropParams.cropTopOffset, decoder[i]->decInfo.cropParams.cropOutWidth, decoder[i]->decInfo.cropParams.cropOutHeight)); } DEBUG(("Decoder[%d] Width %d Height %d\n", i, decoder[i]->decInfo.picWidth, decoder[i]->decInfo.picHeight)); DEBUG(("Decoder[%d] videoRange %d, matricCoefficients %d\n", i, decoder[i]->decInfo.videoRange, decoder[i]->decInfo.matrixCoefficients)); decoder[i]->decInput.dataLen -= (u32)(decoder[i]->decOutput.pStrmCurrPos - decoder[i]->decInput.pStream); decoder[i]->decInput.pStream = decoder[i]->decOutput.pStrmCurrPos; break; case H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY: decoder[i]->decInput.dataLen -= (u32)(decoder[i]->decOutput.pStrmCurrPos - decoder[i]->decInput.pStream); decoder[i]->decInput.pStream = decoder[i]->decOutput.pStrmCurrPos; /* fall through */ case H264SWDEC_PIC_RDY: if (ret == H264SWDEC_PIC_RDY) decoder[i]->decInput.dataLen = 0; ret = H264SwDecGetInfo(decoder[i]->decInst, &(decoder[i]->decInfo)); if (ret != H264SWDEC_OK) exit(1); while (H264SwDecNextPicture(decoder[i]->decInst, &(decoder[i]->decPicture), 0) == H264SWDEC_PIC_RDY) { decoder[i]->picNumber++; numErrors += decoder[i]->decPicture.nbrOfErrMBs; DEBUG(("Decoder[%d] PIC %d, type %s, concealed %d\n", i, decoder[i]->picNumber, decoder[i]->decPicture.isIdrPicture ? "IDR" : "NON-IDR", decoder[i]->decPicture.nbrOfErrMBs)); fflush(stdout); CropWriteOutput(decoder[i]->foutput, (u8*)decoder[i]->decPicture.pOutputPicture, cropDisplay, &(decoder[i]->decInfo)); } if (maxNumPics && decoder[i]->picNumber == maxNumPics) decoder[i]->decInput.dataLen = 0; break; case H264SWDEC_STRM_PROCESSED: case H264SWDEC_STRM_ERR: case H264SWDEC_PARAM_ERR: decoder[i]->decInput.dataLen = 0; break; default: DEBUG(("Decoder[%d] FATAL ERROR\n", i)); exit(10); break; } } /* check if any of the instances is still running (=has more data) */ instRunning = instCount; for (i = 0; i < instCount; i++) { if (decoder[i]->decInput.dataLen == 0) instRunning--; } } while (instRunning); /* get last frames and close each instance */ for (i = 0; i < instCount; i++) { while (H264SwDecNextPicture(decoder[i]->decInst, &(decoder[i]->decPicture), 1) == H264SWDEC_PIC_RDY) { decoder[i]->picNumber++; DEBUG(("Decoder[%d] PIC %d, type %s, concealed %d\n", i, decoder[i]->picNumber, decoder[i]->decPicture.isIdrPicture ? "IDR" : "NON-IDR", decoder[i]->decPicture.nbrOfErrMBs)); fflush(stdout); CropWriteOutput(decoder[i]->foutput, (u8*)decoder[i]->decPicture.pOutputPicture, cropDisplay, &(decoder[i]->decInfo)); } H264SwDecRelease(decoder[i]->decInst); if (decoder[i]->foutput) fclose(decoder[i]->foutput); free(decoder[i]->byteStrmStart); free(decoder[i]); } free(decoder); if (numErrors) return 1; else return 0; } /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ void CropWriteOutput(FILE *foutput, u8 *imageData, u32 cropDisplay, H264SwDecInfo *decInfo) { u8 *tmpImage = NULL; u32 tmp, picSize; if (cropDisplay && decInfo->croppingFlag) { picSize = decInfo->cropParams.cropOutWidth * decInfo->cropParams.cropOutHeight; picSize = (3 * picSize)/2; tmpImage = malloc(picSize); if (tmpImage == NULL) exit(1); tmp = CropPicture(tmpImage, imageData, decInfo->picWidth, decInfo->picHeight, &(decInfo->cropParams)); if (tmp) exit(1); WriteOutput(foutput, tmpImage, picSize); free(tmpImage); } else { picSize = decInfo->picWidth * decInfo->picHeight; picSize = (3 * picSize)/2; WriteOutput(foutput, imageData, picSize); } } /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ void WriteOutput(FILE *fid, u8 *data, u32 picSize) { if (fid) fwrite(data, 1, picSize, fid); } /*------------------------------------------------------------------------------ Function name: H264SwDecTrace ------------------------------------------------------------------------------*/ void H264SwDecTrace(char *string) { FILE *fp; fp = fopen("dec_api.trc", "at"); if (!fp) return; fwrite(string, 1, strlen(string), fp); fwrite("\n", 1,1, fp); fclose(fp); } /*------------------------------------------------------------------------------ Function name: H264SwDecmalloc ------------------------------------------------------------------------------*/ void* H264SwDecMalloc(u32 size, u32 num) { if (size > UINT32_MAX / num) { return NULL; } return malloc(size * num); } /*------------------------------------------------------------------------------ Function name: H264SwDecFree ------------------------------------------------------------------------------*/ void H264SwDecFree(void *ptr) { free(ptr); } /*------------------------------------------------------------------------------ Function name: H264SwDecMemcpy ------------------------------------------------------------------------------*/ void H264SwDecMemcpy(void *dest, void *src, u32 count) { memcpy(dest, src, count); } /*------------------------------------------------------------------------------ Function name: H264SwDecMemset ------------------------------------------------------------------------------*/ void H264SwDecMemset(void *ptr, i32 value, u32 count) { memset(ptr, value, count); } /*------------------------------------------------------------------------------ Function name: CropPicture ------------------------------------------------------------------------------*/ u32 CropPicture(u8 *pOutImage, u8 *pInImage, u32 picWidth, u32 picHeight, CropParams *pCropParams) { u32 i, j; u32 outWidth, outHeight; u8 *pOut, *pIn; if (pOutImage == NULL || pInImage == NULL || pCropParams == NULL || !picWidth || !picHeight) { /* due to lint warning */ free(pOutImage); return(1); } if ( ((pCropParams->cropLeftOffset + pCropParams->cropOutWidth) > picWidth ) || ((pCropParams->cropTopOffset + pCropParams->cropOutHeight) > picHeight ) ) { /* due to lint warning */ free(pOutImage); return(1); } outWidth = pCropParams->cropOutWidth; outHeight = pCropParams->cropOutHeight; pIn = pInImage + pCropParams->cropTopOffset*picWidth + pCropParams->cropLeftOffset; pOut = pOutImage; /* luma */ for (i = outHeight; i; i--) { for (j = outWidth; j; j--) { *pOut++ = *pIn++; } pIn += picWidth - outWidth; } outWidth >>= 1; outHeight >>= 1; pIn = pInImage + picWidth*picHeight + pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2; /* cb */ for (i = outHeight; i; i--) { for (j = outWidth; j; j--) { *pOut++ = *pIn++; } pIn += picWidth/2 - outWidth; } pIn = pInImage + 5*picWidth*picHeight/4 + pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2; /* cr */ for (i = outHeight; i; i--) { for (j = outWidth; j; j--) { *pOut++ = *pIn++; } pIn += picWidth/2 - outWidth; } return (0); }