shithub: openh264

ref: 99faf1ec4a47c5362a6bde552d6097166e2fda16
dir: /codec/console/dec/src/h264dec.cpp/

View raw version
/*!
 * \copy
 *     Copyright (c)  2004-2013, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * Redistributions in binary form must reproduce the above copyright
 *          notice, this list of conditions and the following disclaimer in
 *          the documentation and/or other materials provided with the
 *          distribution.
 *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *     POSSIBILITY OF SUCH DAMAGE.
 *
 * h264dec.cpp:		Wels Decoder Console Implementation file
 */

#if defined (WIN32)
#include <windows.h>
#include <tchar.h>
#else
#include <string.h>
#endif
#include <stdio.h>
#include <stdlib.h>

#include "codec_def.h"
#include "codec_app_def.h"
#include "codec_api.h"
#include "read_config.h"
#include "../../decoder/core/inc/typedefs.h"
#include "../../decoder/core/inc/measure_time.h"
#include "d3d9_utils.h"

typedef long   (*PCreateDecoderFunc) (ISVCDecoder** ppDecoder);
typedef void_t (*PDestroyDecoderFunc)(ISVCDecoder* pDecoder);


using namespace std;

//using namespace WelsDec;

//#define STICK_STREAM_SIZE	// For Demo interfaces test with track file of integrated frames

void_t H264DecodeInstance( ISVCDecoder* pDecoder, const char* kpH264FileName, const char* kpOuputFileName, int32_t& iWidth, int32_t& iHeight, void_t* pOptionFileName )
{
	FILE *pH264File	  = NULL;
	FILE *pYuvFile	  = NULL;
	FILE *pOptionFile = NULL;
	int64_t iStart = 0, iEnd = 0, iTotal = 0;
	int32_t iSliceSize;
	int32_t iSliceIndex = 0;
	uint8_t* pBuf = NULL;
	uint8_t uiStartCode[4] = {0, 0, 0, 1};

	void_t *pData[3] = {NULL};
	uint8_t *pDst[3] = {NULL};
	SBufferInfo sDstBufInfo;

	int32_t iBufPos = 0;
	int32_t iFileSize;
	int32_t i = 0;
	int32_t iLastWidth = 0, iLastHeight = 0;
	int32_t iFrameCount = 0;
	int32_t iEndOfStreamFlag = 0;
	int32_t iColorFormat = videoFormatInternal;
	static int32_t iFrameNum = 0;

	EDecodeMode     eDecoderMode    = AUTO_MODE;
	EBufferProperty	eOutputProperty = BUFFER_DEVICE;
	
	CUtils cOutputModule;
	double dElapsed = 0;

	if (pDecoder == NULL) return;	
	if (kpH264FileName)
	{
		pH264File = fopen(kpH264FileName,"rb");
		if (pH264File == NULL){
			fprintf(stderr, "Can not open h264 source file, check its legal path related please..\n");
			return;
		}
		fprintf(stderr, "H264 source file name: %s..\n",kpH264FileName);
	}
	else
	{
		fprintf(stderr, "Can not find any h264 bitstream file to read..\n");
		fprintf(stderr, "----------------decoder return------------------------\n" );
		return;
	}

	if (kpOuputFileName){
		pYuvFile = fopen(kpOuputFileName, "wb");
		if (pYuvFile == NULL){
			fprintf(stderr, "Can not open yuv file to output result of decoding..\n");
			// any options
			//return;	// can let decoder work in quiet mode, no writing any output
		}
		else
			fprintf(stderr, "Sequence output file name: %s..\n", kpOuputFileName);
	}
	else{
		fprintf(stderr, "Can not find any output file to write..\n");
		// any options
	}
	
	if (pOptionFileName){
		pOptionFile = fopen((char*)pOptionFileName, "wb");
		if ( pOptionFile == NULL ){
			fprintf(stderr, "Can not open optional file for write..\n");
		}
		else
			fprintf(stderr, "Extra optional file: %s..\n", (char*)pOptionFileName);
	}

	printf( "------------------------------------------------------\n" );

	fseek(pH264File, 0L, SEEK_END);
	iFileSize = ftell(pH264File);
	if (iFileSize<=0) {
		fprintf(stderr, "Current Bit Stream File is too small, read error!!!!\n");
		goto label_exit;
	}
	fseek(pH264File, 0L, SEEK_SET);

	pBuf = new uint8_t[iFileSize+4];
	if (pBuf == NULL){
		fprintf(stderr, "new buffer failed!\n");
		goto label_exit;
	}

	fread(pBuf, 1, iFileSize, pH264File);
	memcpy(pBuf+iFileSize, &uiStartCode[0], 4);//confirmed_safe_unsafe_usage

	if( pDecoder->SetOption( DECODER_OPTION_DATAFORMAT,  &iColorFormat ) ){
		fprintf(stderr, "SetOption() failed, opt_id : %d  ..\n", DECODER_OPTION_DATAFORMAT);
		goto label_exit;
	}

	if( pDecoder->SetOption( DECODER_OPTION_MODE,  &eDecoderMode ) ){
		fprintf(stderr, "SetOption() failed, opt_id : %d  ..\n", DECODER_OPTION_MODE);
		goto label_exit;
	}

	// set the output buffer property
	if(pYuvFile)
	{
		pDecoder->SetOption( DECODER_OPTION_OUTPUT_PROPERTY,  &eOutputProperty );
	}

#if defined ( STICK_STREAM_SIZE )
	FILE *fpTrack = fopen("3.len", "rb");	

#endif// STICK_STREAM_SIZE
	

	while ( true ) {

		if ( iBufPos >= iFileSize ){
			iEndOfStreamFlag = true;
			if ( iEndOfStreamFlag )
				pDecoder->SetOption( DECODER_OPTION_END_OF_STREAM, (void_t*)&iEndOfStreamFlag );
			break;
		}

#if defined ( STICK_STREAM_SIZE )
		if ( fpTrack )
			fread(&iSliceSize, 1, sizeof(int32_t), fpTrack);		
#else
		for (i=0; i<iFileSize; i++) {
			if (pBuf[iBufPos+i]==0 && pBuf[iBufPos+i+1]==0 && pBuf[iBufPos+i+2]==0 && 
				pBuf[iBufPos+i+3]==1 && i>0) {
				break;
			}
		}
		iSliceSize = i;
#endif

//for coverage test purpose
        int32_t iOutputColorFormat;
        pDecoder->GetOption(DECODER_OPTION_DATAFORMAT, &iOutputColorFormat);
        int32_t iEndOfStreamFlag;
        pDecoder->GetOption(DECODER_OPTION_END_OF_STREAM, &iEndOfStreamFlag);
        int32_t iCurIdrPicId;
        pDecoder->GetOption(DECODER_OPTION_IDR_PIC_ID, &iCurIdrPicId);
        int32_t iFrameNum;
        pDecoder->GetOption(DECODER_OPTION_FRAME_NUM, &iFrameNum);
        int32_t bCurAuContainLtrMarkSeFlag;
        pDecoder->GetOption(DECODER_OPTION_LTR_MARKING_FLAG, &bCurAuContainLtrMarkSeFlag);
        int32_t iFrameNumOfAuMarkedLtr;
        pDecoder->GetOption(DECODER_OPTION_LTR_MARKED_FRAME_NUM, &iFrameNumOfAuMarkedLtr);
        int32_t iFeedbackVclNalInAu;
        pDecoder->GetOption(DECODER_OPTION_VCL_NAL, &iFeedbackVclNalInAu);        
        int32_t iFeedbackTidInAu;
        pDecoder->GetOption(DECODER_OPTION_TEMPORAL_ID, &iFeedbackTidInAu);
        int32_t iSetMode;
        pDecoder->GetOption(DECODER_OPTION_MODE, &iSetMode);
        int32_t iDeviceInfo;
        pDecoder->GetOption(DECODER_OPTION_DEVICE_INFO, &iDeviceInfo);
//~end for

		iStart = WelsTime();
		pData[0] = NULL;
		pData[1] = NULL;
		pData[2] = NULL;
		memset(&sDstBufInfo, 0, sizeof(SBufferInfo));

		pDecoder->DecodeFrame( pBuf + iBufPos, iSliceSize, pData, &sDstBufInfo );
		
		if(sDstBufInfo.iBufferStatus == 1)
		{
			pDst[0] = (uint8_t *)pData[0];
			pDst[1] = (uint8_t *)pData[1];
			pDst[2] = (uint8_t *)pData[2];
		}
		iEnd	= WelsTime();
		iTotal	+= iEnd - iStart;
		if ( (sDstBufInfo.iBufferStatus==1) )
		{
				iFrameNum++;
			cOutputModule.Process((void_t **)pDst, &sDstBufInfo, pYuvFile);
			if (sDstBufInfo.eBufferProperty == BUFFER_HOST)
			{
				iWidth  = sDstBufInfo.UsrData.sSystemBuffer.iWidth;
				iHeight = sDstBufInfo.UsrData.sSystemBuffer.iHeight;
			}
			else
			{
				iWidth  = sDstBufInfo.UsrData.sVideoBuffer.iSurfaceWidth;
				iHeight = sDstBufInfo.UsrData.sVideoBuffer.iSurfaceHeight;
			}
					
			if ( pOptionFile != NULL )
			{
				if ( iWidth != iLastWidth && iHeight != iLastHeight )
				{
					fwrite(&iFrameCount, sizeof(iFrameCount), 1, pOptionFile);
					fwrite(&iWidth , sizeof(iWidth) , 1, pOptionFile);
					fwrite(&iHeight, sizeof(iHeight), 1, pOptionFile);
					iLastWidth  = iWidth;
					iLastHeight = iHeight;
				}
			}
			++ iFrameCount;
		}

		iBufPos += iSliceSize;
		++ iSliceIndex;
	}

	// Get pending last frame
	pData[0] = NULL;
	pData[1] = NULL;
	pData[2] = NULL;
	memset(&sDstBufInfo, 0, sizeof(SBufferInfo));

	pDecoder->DecodeFrame( NULL, 0, pData, &sDstBufInfo );
	if(sDstBufInfo.iBufferStatus == 1)
	{
		pDst[0] = (uint8_t *)pData[0];
		pDst[1] = (uint8_t *)pData[1];
		pDst[2] = (uint8_t *)pData[2];
	}

	if ((sDstBufInfo.iBufferStatus==1))
	{
		cOutputModule.Process((void_t **)pDst, &sDstBufInfo, pYuvFile);
		if (sDstBufInfo.eBufferProperty == BUFFER_HOST)
		{
			iWidth  = sDstBufInfo.UsrData.sSystemBuffer.iWidth;
			iHeight = sDstBufInfo.UsrData.sSystemBuffer.iHeight;
		}
		else
		{
			iWidth  = sDstBufInfo.UsrData.sVideoBuffer.iSurfaceWidth;
			iHeight = sDstBufInfo.UsrData.sVideoBuffer.iSurfaceHeight;
		}
		
		if ( pOptionFile != NULL )
		{
			/* Anyway, we need write in case of final frame decoding */
			fwrite(&iFrameCount, sizeof(iFrameCount), 1, pOptionFile);
			fwrite(&iWidth , sizeof(iWidth) , 1, pOptionFile);
			fwrite(&iHeight, sizeof(iHeight), 1, pOptionFile);
			iLastWidth	= iWidth;
			iLastHeight	= iHeight;
		}
		++ iFrameCount;
	}


#if defined ( STICK_STREAM_SIZE )
	if ( fpTrack ){
		fclose( fpTrack );
		fpTrack = NULL;
	}
#endif// STICK_STREAM_SIZE
	
	dElapsed = iTotal / 1e6;
	fprintf( stderr, "-------------------------------------------------------\n" );
	fprintf( stderr, "iWidth:		%d\nheight:		%d\nFrames:		%d\ndecode time:	%f sec\nFPS:		%f fps\n",
			 iWidth, iHeight, iFrameCount, dElapsed, (iFrameCount * 1.0)/dElapsed );
	fprintf( stderr, "-------------------------------------------------------\n" );

	// coverity scan uninitial
label_exit:
	if (pBuf) 
	{
		delete[] pBuf;
		pBuf = NULL;
	}	
	if ( pH264File )
	{
		fclose(pH264File);
		pH264File = NULL;
	}
	if ( pYuvFile )
	{
		fclose(pYuvFile);
		pYuvFile = NULL;
	}
	if ( pOptionFile )
	{
		fclose(pOptionFile);
		pOptionFile = NULL;
	}
}


int32_t main(int32_t iArgC, char* pArgV[])
{
	ISVCDecoder *pDecoder = NULL;

	SDecodingParam sDecParam = {0};
	string strInputFile(""), strOutputFile(""), strOptionFile("");

	sDecParam.sVideoProperty.size = sizeof( sDecParam.sVideoProperty );

	if (iArgC < 2)
	{
		printf( "usage 1: h264dec.exe welsdec.cfg\n" );
		printf( "usage 2: h264dec.exe welsdec.264 out.yuv\n" );
		printf( "usage 3: h264dec.exe welsdec.264\n" );
		return 1;
	}
	else if (iArgC == 2)
	{
		if (strstr(pArgV[1], ".cfg")) // read config file //confirmed_safe_unsafe_usage
		{
			CReadConfig cReadCfg(pArgV[1]);
			string strTag[4];
			string strReconFile("");

			if ( !cReadCfg.ExistFile() ){
				printf("Specified file: %s not exist, maybe invalid path or parameter settting.\n", cReadCfg.GetFileName().c_str());
				return 1;
			}
			memset(&sDecParam, 0, sizeof(sDecParam));

			while ( !cReadCfg.EndOfFile() ){
				long nRd = cReadCfg.ReadLine(&strTag[0]);
				if (nRd > 0){
					if (strTag[0].compare("InputFile") == 0){
						strInputFile	= strTag[1];
					}
					else if (strTag[0].compare("OutputFile") == 0){
						strOutputFile	= strTag[1];
					}
					else if (strTag[0].compare("RestructionFile") == 0){
						strReconFile	= strTag[1];
						int32_t iLen = strReconFile.length();
						sDecParam.pFileNameRestructed	= new char[iLen + 1];
						if (sDecParam.pFileNameRestructed != NULL){
							sDecParam.pFileNameRestructed[iLen] = 0;
						}
					
						strncpy(sDecParam.pFileNameRestructed, strReconFile.c_str(), iLen);//confirmed_safe_unsafe_usage
					}
					else if (strTag[0].compare("TargetDQID") == 0){
						sDecParam.uiTargetDqLayer	= (uint8_t)atol(strTag[1].c_str());
					}
					else if (strTag[0].compare("OutColorFormat") == 0){
						sDecParam.iOutputColorFormat = atol(strTag[1].c_str());
					}
					else if (strTag[0].compare("ErrorConcealmentFlag") == 0){
						sDecParam.uiEcActiveFlag	= (uint8_t)atol(strTag[1].c_str());
					}
					else if (strTag[0].compare("CPULoad") == 0){
						sDecParam.uiCpuLoad	= (uint32_t)atol(strTag[1].c_str());
					}
					else if (strTag[0].compare("VideoBitstreamType") == 0){
						sDecParam.sVideoProperty.eVideoBsType = (VIDEO_BITSTREAM_TYPE)atol(strTag[1].c_str());
					}
				}
			}
			if (strOutputFile.empty())
			{
				printf( "No output file specified in configuration file.\n" );
				return 1;
			}
		}
		else if (strstr(pArgV[1], ".264")) // no output dump yuv file, just try to render the decoded pictures //confirmed_safe_unsafe_usage
		{
			strInputFile	= pArgV[1];
			memset(&sDecParam, 0, sizeof(sDecParam));
			sDecParam.iOutputColorFormat          = videoFormatI420;
			sDecParam.uiTargetDqLayer	          = (uint8_t)-1;
			sDecParam.uiEcActiveFlag	          = 1;
			sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
		}
	}
	else //iArgC > 2
	{
		strInputFile	= pArgV[1];
		strOutputFile	= pArgV[2];
		memset(&sDecParam, 0, sizeof(sDecParam));
		sDecParam.iOutputColorFormat	= videoFormatI420;
		sDecParam.uiTargetDqLayer	= (uint8_t)-1;
		sDecParam.uiEcActiveFlag	= 1;
		sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
		if (iArgC > 3)
			strOptionFile	= pArgV[3];

		if (strOutputFile.empty())
		{
			printf( "No output file specified in configuration file.\n" );
			return 1;
		}
	}
	
	if (strInputFile.empty())
	{
		printf( "No input file specified in configuration file.\n" );
		return 1;
	}
	



#if defined(_MSC_VER)

	HMODULE hModule = LoadLibraryA(".\\welsdec.dll");

	PCreateDecoderFunc  pCreateDecoderFunc				= NULL;
	PDestroyDecoderFunc pDestroyDecoderFunc				= NULL;


	pCreateDecoderFunc  = (PCreateDecoderFunc)::GetProcAddress(hModule, "CreateDecoder");
	pDestroyDecoderFunc = (PDestroyDecoderFunc)::GetProcAddress(hModule, "DestroyDecoder");

	if ((hModule != NULL) && (pCreateDecoderFunc != NULL) && (pDestroyDecoderFunc != NULL))
	{
		printf("load library sw function successfully\n");

		if ( pCreateDecoderFunc( &pDecoder )  || (NULL == pDecoder) )
		{
			printf( "Create Decoder failed.\n" );
			return 1;
		}
	}
	else 
	{
		printf("load library sw function failed\n");
		return 1;
	}


#else


	if ( CreateDecoder( &pDecoder )  || (NULL == pDecoder) )
	{
		printf( "Create Decoder failed.\n" );
		return 1;
	}
	
#endif


	if ( pDecoder->Initialize( &sDecParam, INIT_TYPE_PARAMETER_BASED ) )
	{
		printf( "Decoder initialization failed.\n" );
		return 1;
	}
	
	
	int32_t iWidth = 0;
	int32_t iHeight= 0;

	
	H264DecodeInstance( pDecoder, strInputFile.c_str(), strOutputFile.c_str(), iWidth, iHeight, (!strOptionFile.empty() ? (void_t*)(const_cast<char*>(strOptionFile.c_str())) : NULL) );
	
	if (sDecParam.pFileNameRestructed != NULL){
		delete []sDecParam.pFileNameRestructed;
		sDecParam.pFileNameRestructed = NULL;
	}
		
	if ( pDecoder ){
		pDecoder->Unintialize();
		
#if defined(_MSC_VER)
		pDestroyDecoderFunc( pDecoder );
#else
		DestroyDecoder(pDecoder);
#endif
	}

	return 0;
}