ref: edba95536681d8c589ed6dccc1b88a8499a98d3b
dir: /codec/console/enc/src/welsenc.cpp/
/*! * \copy * Copyright (c) 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. * */ #include <stdio.h> #include <string.h> #include <assert.h> #include <signal.h> #ifdef ONLY_ENC_FRAMES_NUM #undef ONLY_ENC_FRAMES_NUM #endif//ONLY_ENC_FRAMES_NUM #define ONLY_ENC_FRAMES_NUM INT_MAX // 2, INT_MAX // type the num you try to encode here, 2, 10, etc //#define STICK_STREAM_SIZE #if defined(__GNUC__) #if !defined(MACOS) #if !defined(_MATH_H_MATHDEF) #define _MATH_H_MATHDEF //#else //#error "warning: have defined _MATH_H_MATHDEF!!" // to check #endif//_MATH_H_MATHDEF #endif//MACOS #endif//__GNUC__ #include "measure_time.h" #include "param_svc.h" //#include "layered_pic_buffer.h" #include "read_config.h" #if defined(MACOS) #include "bundlewelsenc.h" #else #include "typedefs.h" #endif//MACOS #ifdef _MSC_VER #include <io.h> /* _setmode() */ #include <fcntl.h> /* _O_BINARY */ #endif//_MSC_VER #include "codec_def.h" #include "codec_api.h" #include "extern.h" #include "macros.h" #include "wels_const.h" #ifdef MT_ENABLED #include "mt_defs.h" #include "WelsThreadLib.h" #endif//MT_ENABLED #include <iostream> using namespace std; using namespace WelsSVCEnc; /* * Layer Context */ typedef struct LayerpEncCtx_s { int32_t iDLayerQp; SMulSliceOption sMso; } SLayerPEncCtx; /* Ctrl-C handler */ static int g_iCtrlC = 0; static void SigIntHandler( int a ) { g_iCtrlC = 1; } int ParseConfig(CReadConfig& cRdCfg, SWelsSvcCodingParam& pSvcParam, SFilesSet& sFileSet) { string strTag[4]; int32_t iLeftTargetBitrate = 0; int32_t iLeftSpatialBitrate[MAX_DEPENDENCY_LAYER] = { 0 }; int32_t iRet = 0; int8_t iLayerCount = 0; string str_("SlicesAssign"); const int kiSize = str_.size(); // memset(&pSvcParam, 0, sizeof(WelsSVCParamConfig)); while ( !cRdCfg.EndOfFile() ){ long iRd = cRdCfg.ReadLine(&strTag[0]); if (iRd > 0){ if ( strTag[0].empty() ) continue; if (strTag[0].compare("OutputFile") == 0){ sFileSet.strBsFile = strTag[1]; continue; } else if (strTag[0].compare("MaxFrameRate") == 0){ pSvcParam.fMaxFrameRate = (float)atof(strTag[1].c_str()); continue; } else if (strTag[0].compare("FramesToBeEncoded") == 0){ pSvcParam.uiFrameToBeCoded = atoi(strTag[1].c_str()); continue; } else if ( strTag[0].compare("SourceSequenceInRGB24") == 0 ){ pSvcParam.iInputCsp = atoi(strTag[1].c_str()) == 0 ? videoFormatI420 : videoFormatRGB; continue; } else if (strTag[0].compare("GOPSize") == 0){ pSvcParam.uiGopSize = atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("IntraPeriod") == 0){ pSvcParam.uiIntraPeriod = atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("EnableSpsPpsIDAddition") == 0) { pSvcParam.bEnableSpsPpsIdAddition = atoi(strTag[1].c_str())?true:false; continue; } else if (strTag[0].compare("EnableScalableSEI") == 0) { pSvcParam.bEnableSSEI = atoi(strTag[1].c_str())?true:false; continue; } else if (strTag[0].compare("EnableFrameCropping") == 0) { pSvcParam.bEnableFrameCroppingFlag = (atoi(strTag[1].c_str()) != 0); continue; } else if (strTag[0].compare("LoopFilterDisableIDC") == 0){ pSvcParam.iLoopFilterDisableIdc = (int8_t)atoi(strTag[1].c_str()); if (pSvcParam.iLoopFilterDisableIdc > 6 || pSvcParam.iLoopFilterDisableIdc < 0){ fprintf(stderr, "Invalid parameter in iLoopFilterDisableIdc: %d.\n", pSvcParam.iLoopFilterDisableIdc); iRet = 1; break; } continue; } else if (strTag[0].compare("LoopFilterAlphaC0Offset") == 0){ pSvcParam.iLoopFilterAlphaC0Offset = (int8_t)atoi(strTag[1].c_str()); if ( pSvcParam.iLoopFilterAlphaC0Offset < -6 ) pSvcParam.iLoopFilterAlphaC0Offset = -6; else if ( pSvcParam.iLoopFilterAlphaC0Offset > 6 ) pSvcParam.iLoopFilterAlphaC0Offset = 6; continue; } else if (strTag[0].compare("LoopFilterBetaOffset") == 0){ pSvcParam.iLoopFilterBetaOffset = (int8_t)atoi(strTag[1].c_str()); if ( pSvcParam.iLoopFilterBetaOffset < -6 ) pSvcParam.iLoopFilterBetaOffset = -6; else if ( pSvcParam.iLoopFilterBetaOffset > 6 ) pSvcParam.iLoopFilterBetaOffset = 6; continue; } else if (strTag[0].compare("InterLayerLoopFilterDisableIDC") == 0){ pSvcParam.iInterLayerLoopFilterDisableIdc = (int8_t)atoi(strTag[1].c_str()); if (pSvcParam.iInterLayerLoopFilterDisableIdc > 6 || pSvcParam.iInterLayerLoopFilterDisableIdc < 0){ fprintf(stderr, "Invalid parameter in iInterLayerLoopFilterDisableIdc: %d.\n", pSvcParam.iInterLayerLoopFilterDisableIdc); iRet = 1; break; } continue; } else if (strTag[0].compare("InterLayerLoopFilterAlphaC0Offset") == 0){ pSvcParam.iInterLayerLoopFilterAlphaC0Offset = (int8_t)atoi(strTag[1].c_str()); if ( pSvcParam.iInterLayerLoopFilterAlphaC0Offset < -6 ) pSvcParam.iInterLayerLoopFilterAlphaC0Offset = -6; else if ( pSvcParam.iInterLayerLoopFilterAlphaC0Offset > 6 ) pSvcParam.iInterLayerLoopFilterAlphaC0Offset = 6; continue; } else if (strTag[0].compare("InterLayerLoopFilterBetaOffset") == 0){ pSvcParam.iInterLayerLoopFilterBetaOffset = (int8_t)atoi(strTag[1].c_str()); if ( pSvcParam.iInterLayerLoopFilterBetaOffset < -6 ) pSvcParam.iInterLayerLoopFilterBetaOffset = -6; else if ( pSvcParam.iInterLayerLoopFilterBetaOffset > 6 ) pSvcParam.iInterLayerLoopFilterBetaOffset = 6; continue; } else if ( strTag[0].compare("MultipleThreadIdc") == 0 ) { // # 0: auto(dynamic imp. internal encoder); 1: multiple threads imp. disabled; > 1: count number of threads; pSvcParam.iMultipleThreadIdc = atoi( strTag[1].c_str() ); if ( pSvcParam.iMultipleThreadIdc < 0 ) pSvcParam.iMultipleThreadIdc = 0; else if ( pSvcParam.iMultipleThreadIdc > MAX_THREADS_NUM ) pSvcParam.iMultipleThreadIdc = MAX_THREADS_NUM; continue; } else if (strTag[0].compare("EnableRC") == 0){ pSvcParam.bEnableRc = atoi(strTag[1].c_str())?true:false; continue; } else if (strTag[0].compare("RCMode") == 0){ pSvcParam.iRCMode = atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("TargetBitrate") == 0){ pSvcParam.iTargetBitrate = 1000 * atoi(strTag[1].c_str()); if ( pSvcParam.bEnableRc && pSvcParam.iTargetBitrate <= 0 ){ fprintf(stderr, "Invalid target bitrate setting due to RC enabled. Check TargetBitrate field please!\n"); return 1; } if ( pSvcParam.bEnableRc ){ iLeftTargetBitrate = pSvcParam.iTargetBitrate; } continue; } else if (strTag[0].compare("EnableDenoise") == 0){ pSvcParam.bEnableDenoise = atoi(strTag[1].c_str())?true:false; continue; } else if (strTag[0].compare("EnableSceneChangeDetection") == 0){ pSvcParam.bEnableSceneChangeDetect = atoi(strTag[1].c_str())?true:false; continue; } else if (strTag[0].compare("EnableBackgroundDetection") == 0) { pSvcParam.bEnableBackgroundDetection = atoi(strTag[1].c_str())?true:false; continue; } else if (strTag[0].compare("EnableAdaptiveQuantization") == 0){ pSvcParam.bEnableAdaptiveQuant = atoi(strTag[1].c_str())?true:false; continue; } else if (strTag[0].compare("EnableLongTermReference") == 0){ pSvcParam.bEnableLongTermReference = atoi(strTag[1].c_str())?true:false; continue; } else if (strTag[0].compare("LtrMarkPeriod") == 0){ pSvcParam.uiLtrMarkPeriod = (uint32_t)atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("NumLayers") == 0){ pSvcParam.iNumDependencyLayer = (int8_t)atoi(strTag[1].c_str()); if (pSvcParam.iNumDependencyLayer > MAX_DEPENDENCY_LAYER || pSvcParam.iNumDependencyLayer <= 0){ fprintf(stderr, "Invalid parameter in iNumDependencyLayer: %d.\n", pSvcParam.iNumDependencyLayer); iRet = 1; break; } continue; } else if (strTag[0].compare("LayerCfg") == 0){ if ( strTag[1].length() > 0 ) sFileSet.sSpatialLayers[iLayerCount].strLayerCfgFile = strTag[1]; // pSvcParam.sDependencyLayers[iLayerCount].uiDependencyId = iLayerCount; ++ iLayerCount; continue; } else if (strTag[0].compare("PrefixNALAddingCtrl") == 0){ int ctrl_flag = atoi(strTag[1].c_str()); if (ctrl_flag > 1) ctrl_flag = 1; else if (ctrl_flag < 0) ctrl_flag = 0; pSvcParam.bPrefixNalAddingCtrl = ctrl_flag?true:false; continue; } } } const int8_t kiActualLayerNum = WELS_MIN(pSvcParam.iNumDependencyLayer, iLayerCount); if (pSvcParam.iNumDependencyLayer > kiActualLayerNum){ // fixed number of dependency layer due to parameter error in settings pSvcParam.iNumDependencyLayer = kiActualLayerNum; } assert( kiActualLayerNum <= MAX_DEPENDENCY_LAYER ); for (int8_t iLayer = 0; iLayer < kiActualLayerNum; ++ iLayer){ SLayerPEncCtx sLayerCtx; int32_t iLayerArg = -2; int32_t iNumQualityBitrateLayerSet = 0; SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; CReadConfig cRdLayerCfg( sFileSet.sSpatialLayers[iLayer].strLayerCfgFile ); memset(&sLayerCtx, 0, sizeof(SLayerPEncCtx)); if ( !cRdLayerCfg.ExistFile() ){ fprintf(stderr, "Unabled to open layer #%d configuration file: %s.\n", iLayer, cRdLayerCfg.GetFileName().c_str()); continue; } while ( !cRdLayerCfg.EndOfFile() ){ long iLayerRd = cRdLayerCfg.ReadLine(&strTag[0]); bool_t bFound = false; if (iLayerRd > 0){ if ( strTag[0].empty() ) continue; if (strTag[0].compare("SourceWidth") == 0){ pDLayer->iFrameWidth = atoi(strTag[1].c_str()); pDLayer->iActualWidth= pDLayer->iFrameWidth; continue; } else if (strTag[0].compare("SourceHeight") == 0){ pDLayer->iFrameHeight = atoi(strTag[1].c_str()); pDLayer->iActualHeight = pDLayer->iFrameHeight; continue; } else if (strTag[0].compare("FrameRateIn") == 0){ pDLayer->fInputFrameRate = (float)atof(strTag[1].c_str()); continue; } else if (strTag[0].compare("FrameRateOut") == 0){ pDLayer->fOutputFrameRate = (float)atof(strTag[1].c_str()); continue; } else if (strTag[0].compare("InputFile") == 0){ if ( strTag[1].length() > 0 ) sFileSet.sSpatialLayers[iLayer].strSeqFile = strTag[1]; continue; } else if (strTag[0].compare("ReconFile") == 0){ const int kiLen = strTag[1].length(); if (kiLen >= MAX_FNAME_LEN) return 1; #ifdef ENABLE_FRAME_DUMP pDLayer->sRecFileName[kiLen] = '\0'; strncpy(pDLayer->sRecFileName, strTag[1].c_str(), kiLen); // confirmed_safe_unsafe_usage #endif//ENABLE_FRAME_DUMP continue; } else if (strTag[0].compare("ProfileIdc") == 0){ pDLayer->uiProfileIdc = atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("FRExt") == 0){ // pDLayer->frext_mode = (bool_t)atoi(strTag[1].c_str()); continue; } if (strTag[0].compare("SpatialBitrate") == 0){ pDLayer->iSpatialBitrate = 1000 * atoi(strTag[1].c_str()); if ( pSvcParam.bEnableRc && pDLayer->iSpatialBitrate <= 0 ){ fprintf(stderr, "Invalid spatial bitrate(%d) in dependency layer #%d.\n", pDLayer->iSpatialBitrate, iLayer); return 1; } if ( pSvcParam.bEnableRc &&pDLayer->iSpatialBitrate > iLeftTargetBitrate ){ fprintf(stderr, "Invalid spatial(#%d) bitrate(%d) setting due to unavailable left(%d)!\n", iLayer, pDLayer->iSpatialBitrate, iLeftTargetBitrate); return 1; } iLeftSpatialBitrate[iLayer] = pDLayer->iSpatialBitrate; continue; } if (strTag[0].compare("InitialQP") == 0){ sLayerCtx.iDLayerQp = atoi(strTag[1].c_str()); continue; } if (strTag[0].compare("SliceMode") == 0){ sLayerCtx.sMso.uiSliceMode = (SliceMode)atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("SliceSize") == 0){//SM_DYN_SLICE sLayerCtx.sMso.sSliceArgument.uiSliceSizeConstraint = (SliceMode)atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("SliceNum") == 0){ sLayerCtx.sMso.sSliceArgument.iSliceNum = atoi(strTag[1].c_str()); continue; } else if ( strTag[0].compare(0, kiSize, str_ ) == 0 ) { const char* kpString = strTag[0].c_str(); int uiSliceIdx = atoi(&kpString[kiSize]); assert( uiSliceIdx < MAX_SLICES_NUM ); sLayerCtx.sMso.sSliceArgument.uiSliceMbNum[uiSliceIdx] = atoi( strTag[1].c_str() ); continue; } } } pDLayer->iDLayerQp = sLayerCtx.iDLayerQp; pDLayer->sMso.uiSliceMode = sLayerCtx.sMso.uiSliceMode; memcpy( &pDLayer->sMso, &sLayerCtx.sMso, sizeof(SMulSliceOption) ); // confirmed_safe_unsafe_usage memcpy( &pDLayer->sMso.sSliceArgument.uiSliceMbNum[0], &sLayerCtx.sMso.sSliceArgument.uiSliceMbNum[0], sizeof(sLayerCtx.sMso.sSliceArgument.uiSliceMbNum) ); // confirmed_safe_unsafe_usage } return iRet; } int ParseCommandLine( int argc, char ** argv, SVCEncodingParam & sParam) { char * pCmd; int i = 0; if (argc <= 0) // no additional pCmd parameters return 0; while ( i < argc ) { pCmd = argv[i]; if( !strcmp(pCmd, "-numl") ) { // confirmed_safe_unsafe_usage int iNumSpatial = atoi(argv[i+1]); sParam.iSpatialLayerNum = iNumSpatial; i += 2; } else if( !strcmp(pCmd, "-numt") ) { // confirmed_safe_unsafe_usage int iNumTemporal = atoi(argv[i+1]); sParam.iTemporalLayerNum = iNumTemporal; i += 2; } else if( !strcmp(pCmd,"-iper") ) { // confirmed_safe_unsafe_usage int iPeriod = atoi(argv[i+1]); sParam.iIntraPeriod = iPeriod; i += 2; } else if( !strcmp(pCmd,"-spsid") ) { // confirmed_safe_unsafe_usage int iSpsPpsId = atoi(argv[i+1]); sParam.bEnableSpsPpsIdAddition = iSpsPpsId?true:false; i += 2; } else if( !strcmp(pCmd,"-denois") ) { // confirmed_safe_unsafe_usage int iDenois = atoi(argv[i+1]); sParam.bEnableDenoise = iDenois?true:false; i += 2; } else if( !strcmp(pCmd,"-bgd") ) { // confirmed_safe_unsafe_usage int iBgd = atoi(argv[i+1]); sParam.bEnableBackgroundDetection = iBgd?true:false; i += 2; } else if( !strcmp(pCmd,"-aq") ) { // confirmed_safe_unsafe_usage int iAq = atoi(argv[i+1]); sParam.bEnableAdaptiveQuant = iAq?true:false; i += 2; } else if( !strcmp(pCmd,"-ltr") ) { // confirmed_safe_unsafe_usage int iLtr = atoi(argv[i+1]); sParam.bEnableLongTermReference = iLtr?true:false; i += 2; } else if( !strcmp(pCmd,"-ltrper") ) { // confirmed_safe_unsafe_usage int iLtrPer = atoi(argv[i+1]); sParam.iLtrMarkPeriod = iLtrPer; i += 2; } else if( !strcmp(pCmd,"-rcm") ) { // confirmed_safe_unsafe_usage int iRcMode = atoi(argv[i+1]); sParam.iRCMode = iRcMode; i += 2; } else if( !strcmp(pCmd,"-tarb") ) { // confirmed_safe_unsafe_usage int iTarB = atoi(argv[i+1]); sParam.iTargetBitrate = iTarB; i += 2; } else if( !strcmp(pCmd,"-ltarb") ) // confirmed_safe_unsafe_usage { int iLayer = atoi( argv[i+1] ); int iSpatialBitrate = atoi( argv[i+2] ); sParam.sSpatialLayers[iLayer].iSpatialBitrate = iSpatialBitrate; i += 3; } else { i ++; } } return 0; } void PrintHelp() { printf("\n Wels SVC Encoder Usage:\n\n"); printf(" Syntax: welsenc.exe welsenc.cfg\n"); printf(" Syntax: welsenc.exe welsenc.cfg [options]\n"); printf("\n Supported Options:\n"); printf(" -h Print Help\n"); printf(" -bf Bit Stream File\n"); printf(" -frms Number of total frames to be encoded\n"); printf(" -gop GOPSize - GOP size (2,4,8,16,32,64, default: 1)\n"); printf(" -iper Intra period (default: -1) : must be a power of 2 of GOP size (or -1)\n"); printf(" -spsid Enable id adding in SPS/PPS per IDR \n"); printf(" -denois Control denoising (default: 0)\n"); printf(" -scene Control scene change detection (default: 0)\n"); printf(" -bgd Control background detection (default: 0)\n"); printf(" -aq Control adaptive quantization (default: 0)\n"); printf(" -ltr Control long term reference (default: 0)\n"); printf(" -rc Control rate control: 0-disable; 1-enable \n"); printf(" -tarb Overall target bitrate\n"); printf(" -numl Number Of Layers: Must exist with layer_cfg file and the number of input layer_cfg file must equal to the value set by this command\n"); printf(" The options below are layer-based: (need to be set with layer id)\n"); printf(" -org (Layer) (original file); example: -org 0 src.yuv\n"); printf(" -drec (Layer) (reconstruction file); Setting the reconstruction file, this will only functioning when dumping reconstruction is enabled\n"); printf(" -sw (Layer) (source width)\n"); printf(" -sh (Layer) (source height)\n"); printf(" -frin (Layer) (input frame rate)\n"); printf(" -frout (Layer) (output frame rate)\n"); printf(" -lqp (Layer) (base quality layer qp : must work with -ldeltaqp or -lqparr)\n"); printf(" -ltarb (Layer) (spatial layer target bitrate)\n"); printf(" -slcmd (Layer) (spatial layer slice mode): pls refer to layerX.cfg for details ( -slcnum: set target slice num; -slcsize: set target slice size constraint ) \n"); printf("\n"); } int ParseCommandLine(int argc, char** argv, SWelsSvcCodingParam & pSvcParam, SFilesSet& sFileSet) { char* pCommand = NULL; char* pTemp = NULL; unsigned int uiQpChangeFlag[4] = {0}; unsigned int uiQlPredModeChangeFlag[4] = {0}; SLayerPEncCtx sLayerCtx[3]; int n = 0; string str_("SlicesAssign"); const int kiSize = str_.size(); if (argc <= 0) // no additional pCmd parameters return 0; while(n < argc) { pCommand = argv[n++]; if (!(strcmp(pCommand,"-h"))) // confirmed_safe_unsafe_usage { PrintHelp(); continue; } if (!(strcmp(pCommand,"-bf"))) // confirmed_safe_unsafe_usage { sFileSet.strBsFile.assign(argv[n]); ++ n; continue; } if( !(strcmp(pCommand,"-frms")) ) // confirmed_safe_unsafe_usage { pSvcParam.uiFrameToBeCoded = atoi(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-gop")) ) // confirmed_safe_unsafe_usage { pSvcParam.uiGopSize = atoi(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-iper")) ) // confirmed_safe_unsafe_usage { pSvcParam.uiIntraPeriod = atoi(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-spsid")) ) // confirmed_safe_unsafe_usage { pSvcParam.bEnableSpsPpsIdAddition = atoi(argv[n ])?true:false; ++ n; continue; } if( !(strcmp(pCommand,"-denois")) ) // confirmed_safe_unsafe_usage { pSvcParam.bEnableDenoise = atoi(argv[n ])?true:false; ++ n; continue; } if( !(strcmp(pCommand,"-scene")) ) // confirmed_safe_unsafe_usage { pSvcParam.bEnableSceneChangeDetect = atoi(argv[n ])?true:false; ++ n; continue; } if ( !(strcmp(pCommand,"-bgd")) ) // confirmed_safe_unsafe_usage { pSvcParam.bEnableBackgroundDetection = atoi(argv[n ])?true:false; ++ n; continue; } if( !(strcmp(pCommand,"-aq")) ) // confirmed_safe_unsafe_usage { pSvcParam.bEnableAdaptiveQuant = atoi(argv[n ])?true:false; ++ n; continue; } if( !(strcmp(pCommand,"-ltr")) ) // confirmed_safe_unsafe_usage { pSvcParam.bEnableLongTermReference = atoi(argv[n ])?true:false; ++ n; continue; } if( !(strcmp(pCommand,"-ltrper")) ) // confirmed_safe_unsafe_usage { pSvcParam.uiLtrMarkPeriod = atoi(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-rc")) ) // confirmed_safe_unsafe_usage { pSvcParam.bEnableRc = atoi(argv[n ])?true:false; ++ n; continue; } if( !(strcmp(pCommand,"-tarb")) ) // confirmed_safe_unsafe_usage { pSvcParam.iTargetBitrate = atoi(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-numl")) ) // confirmed_safe_unsafe_usage { bool_t bFound = false; pSvcParam.iNumDependencyLayer = atoi(argv[n++]); for (int ln = 0 ; ln < pSvcParam.iNumDependencyLayer ; ln++) { // pSvcParam.sDependencyLayers[ln].uiDependencyId = ln; sFileSet.sSpatialLayers[ln].strLayerCfgFile.assign( argv[n] ); ++ n; } for (int8_t iLayer = 0; iLayer < pSvcParam.iNumDependencyLayer; ++ iLayer){ SLayerPEncCtx sLayerCtx; string strTag[4]; int32_t iLayerArg = -2; int32_t iNumQualityBitrateLayerSet = 0; SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; CReadConfig cRdLayerCfg( sFileSet.sSpatialLayers[iLayer].strLayerCfgFile ); memset(&sLayerCtx, 0, sizeof(SLayerPEncCtx)); // pDLayer->frext_mode = 0; if ( !cRdLayerCfg.ExistFile() ){ fprintf(stderr, "Unabled to open layer #%d configuration file: %s.\n", iLayer, cRdLayerCfg.GetFileName().c_str()); continue; } while ( !cRdLayerCfg.EndOfFile() ){ long iLayerRd = cRdLayerCfg.ReadLine(&strTag[0]); if (iLayerRd > 0){ if ( strTag[0].empty() ) continue; if (strTag[0].compare("SourceWidth") == 0){ pDLayer->iFrameWidth = atoi(strTag[1].c_str()); pDLayer->iActualWidth= pDLayer->iFrameWidth; continue; } else if (strTag[0].compare("SourceHeight") == 0){ pDLayer->iFrameHeight = atoi(strTag[1].c_str()); pDLayer->iActualHeight = pDLayer->iFrameHeight; continue; } else if (strTag[0].compare("FrameRateIn") == 0){ pDLayer->fInputFrameRate = (float)atof(strTag[1].c_str()); continue; } else if (strTag[0].compare("FrameRateOut") == 0){ pDLayer->fOutputFrameRate = (float)atof(strTag[1].c_str()); continue; } else if (strTag[0].compare("InputFile") == 0){ if ( strTag[1].length() > 0 ) sFileSet.sSpatialLayers[iLayer].strSeqFile = strTag[1]; continue; } else if (strTag[0].compare("ReconFile") == 0){ #ifdef ENABLE_FRAME_DUMP const int kiLen = strTag[1].length(); if (kiLen >= MAX_FNAME_LEN) return 1; pDLayer->sRecFileName[kiLen] = '\0'; strncpy(pDLayer->sRecFileName, strTag[1].c_str(), kiLen); // confirmed_safe_unsafe_usage #endif//ENABLE_FRAME_DUMP continue; } else if (strTag[0].compare("ProfileIdc") == 0){ pDLayer->uiProfileIdc = atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("FRExt") == 0){ // pDLayer->frext_mode = (bool_t)atoi(strTag[1].c_str()); continue; } if (strTag[0].compare("SpatialBitrate") == 0){ pDLayer->iSpatialBitrate = 1000 * atoi(strTag[1].c_str()); continue; } if (strTag[0].compare("InitialQP") == 0){ sLayerCtx.iDLayerQp = atoi(strTag[1].c_str()); continue; } if (strTag[0].compare("SliceMode") == 0){ sLayerCtx.sMso.uiSliceMode = (SliceMode)atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("SliceSize") == 0){//SM_DYN_SLICE sLayerCtx.sMso.sSliceArgument.uiSliceSizeConstraint = (SliceMode)atoi(strTag[1].c_str()); continue; } else if (strTag[0].compare("SliceNum") == 0){ sLayerCtx.sMso.sSliceArgument.iSliceNum = atoi(strTag[1].c_str()); continue; } else if ( strTag[0].compare(0, kiSize, str_ ) == 0 ) { const char* kpString = strTag[0].c_str(); int uiSliceIdx = atoi(&kpString[kiSize]); assert( uiSliceIdx < MAX_SLICES_NUM ); sLayerCtx.sMso.sSliceArgument.uiSliceMbNum[uiSliceIdx] = atoi( strTag[1].c_str() ); continue; } } } pDLayer->iDLayerQp = sLayerCtx.iDLayerQp; pDLayer->sMso.uiSliceMode = sLayerCtx.sMso.uiSliceMode; memcpy( &pDLayer->sMso, &sLayerCtx.sMso, sizeof(SMulSliceOption) ); // confirmed_safe_unsafe_usage memcpy( &pDLayer->sMso.sSliceArgument.uiSliceMbNum[0], &sLayerCtx.sMso.sSliceArgument.uiSliceMbNum[0], sizeof(sLayerCtx.sMso.sSliceArgument.uiSliceMbNum) ); // confirmed_safe_unsafe_usage } //n += 1; continue; } if( !(strcmp(pCommand,"-org")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); sFileSet.sSpatialLayers[iLayer].strSeqFile.assign( argv[n] ); ++ n; continue; } if( !(strcmp(pCommand,"-drec")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); const int iLen = strlen(argv[n]); // confirmed_safe_unsafe_usage #ifdef ENABLE_FRAME_DUMP SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; pDLayer->sRecFileName[iLen] = '\0'; strncpy(pDLayer->sRecFileName, argv[n], iLen); // confirmed_safe_unsafe_usage #endif//ENABLE_FRAME_DUMP ++ n; continue; } if( !(strcmp(pCommand,"-sw")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; pDLayer->iFrameWidth = atoi(argv[n ]); pDLayer->iActualWidth= pDLayer->iFrameWidth; ++ n; continue; } if( !(strcmp(pCommand,"-sh")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; pDLayer->iFrameHeight = atoi(argv[n ]); pDLayer->iActualHeight= pDLayer->iFrameHeight; ++ n; continue; } if( !(strcmp(pCommand,"-frin")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; pDLayer->fInputFrameRate = (float)atof(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-frout")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; pDLayer->fOutputFrameRate = (float)atof(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-lqp")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; uiQpChangeFlag[iLayer] = 1; pDLayer->iDLayerQp = sLayerCtx[iLayer].iDLayerQp= atoi(argv[n ]); n += 1; continue; } //sLayerCtx[iLayer].num_quality_layers = pDLayer->num_quality_layers = 1; if( !(strcmp(pCommand,"-ltarb")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; pDLayer->iSpatialBitrate = 1000 * atoi(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-slcmd")) ) // confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; switch ( atoi(argv[n] ) ) { case 0: pDLayer->sMso.uiSliceMode = SM_SINGLE_SLICE; break; case 1: pDLayer->sMso.uiSliceMode = SM_FIXEDSLCNUM_SLICE; break; case 2: pDLayer->sMso.uiSliceMode = SM_RASTER_SLICE; break; case 3: pDLayer->sMso.uiSliceMode = SM_ROWMB_SLICE; break; case 4: pDLayer->sMso.uiSliceMode = SM_DYN_SLICE; break; default: pDLayer->sMso.uiSliceMode = SM_RESERVED; break; } ++ n; continue; } if( !(strcmp(pCommand,"-slcsize")) )//confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; pDLayer->sMso.sSliceArgument.uiSliceSizeConstraint = atoi(argv[n ]); ++ n; continue; } if( !(strcmp(pCommand,"-slcnum")) )// confirmed_safe_unsafe_usage { unsigned int iLayer = atoi( argv[n++] ); SDLayerParam *pDLayer = &pSvcParam.sDependencyLayers[iLayer]; pDLayer->sMso.sSliceArgument.iSliceNum = atoi(argv[n ]); ++ n; continue; } } return 0; } int FillSpecificParameters( SVCEncodingParam &sParam ) { /* Test for temporal, spatial, SNR scalability */ sParam.fFrameRate = 30.0f; // input frame rate sParam.iPicWidth = 1280; // width of picture in samples sParam.iPicHeight = 720; // height of picture in samples sParam.iTargetBitrate= 2500000; // target bitrate desired sParam.iRCMode = 0; // rc mode control sParam.iTemporalLayerNum= 3; // layer number at temporal level sParam.iSpatialLayerNum = 4; // layer number at spatial level sParam.bEnableDenoise = 0; // denoise control sParam.bEnableBackgroundDetection = 1; // background detection control sParam.bEnableAdaptiveQuant = 1; // adaptive quantization control sParam.bEnableLongTermReference = 0; // long term reference control sParam.iLtrMarkPeriod = 30; sParam.iInputCsp = videoFormatI420; // color space of input sequence sParam.iKeyPicCodingMode= 1;// mode of key picture coding sParam.iIntraPeriod = 320; // period of Intra frame sParam.bEnableSpsPpsIdAddition = 1; sParam.bPrefixNalAddingCtrl = 1; int iIndexLayer = 0; sParam.sSpatialLayers[iIndexLayer].iVideoWidth = 160; sParam.sSpatialLayers[iIndexLayer].iVideoHeight = 90; sParam.sSpatialLayers[iIndexLayer].fFrameRate = 7.5f; sParam.sSpatialLayers[iIndexLayer].iQualityLayerNum = 1; sParam.sSpatialLayers[iIndexLayer].iSpatialBitrate = 64000; sParam.sSpatialLayers[iIndexLayer].iCgsSnrRefined = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[0] = 0; // memset(sParam.iTemporalBitrate, 0, sizeof(sParam.iTemporalBitrate)); sParam.sSpatialLayers[iIndexLayer].iInterSpatialLayerPredFlag = 0; #ifdef MT_ENABLED sParam.sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = 0; #endif ++ iIndexLayer; sParam.sSpatialLayers[iIndexLayer].iVideoWidth = 320; sParam.sSpatialLayers[iIndexLayer].iVideoHeight = 180; sParam.sSpatialLayers[iIndexLayer].fFrameRate = 15.0f; sParam.sSpatialLayers[iIndexLayer].iQualityLayerNum = 1; sParam.sSpatialLayers[iIndexLayer].iSpatialBitrate = 160000; sParam.sSpatialLayers[iIndexLayer].iCgsSnrRefined = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[0] = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[1] = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[2] = 0; sParam.sSpatialLayers[iIndexLayer].iInterSpatialLayerPredFlag = 0; #ifdef MT_ENABLED sParam.sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = 0; #endif ++ iIndexLayer; sParam.sSpatialLayers[iIndexLayer].iVideoWidth = 640; sParam.sSpatialLayers[iIndexLayer].iVideoHeight = 360; sParam.sSpatialLayers[iIndexLayer].fFrameRate = 30.0f; sParam.sSpatialLayers[iIndexLayer].iQualityLayerNum = 1; sParam.sSpatialLayers[iIndexLayer].iSpatialBitrate = 512000; sParam.sSpatialLayers[iIndexLayer].iCgsSnrRefined = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[0] = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[1] = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[2] = 0; sParam.sSpatialLayers[iIndexLayer].iInterSpatialLayerPredFlag = 0; #ifdef MT_ENABLED sParam.sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = 0; sParam.sSpatialLayers[iIndexLayer].sSliceCfg.sSliceArgument.uiSliceNum = 1; #endif ++ iIndexLayer; sParam.sSpatialLayers[iIndexLayer].iVideoWidth = 1280; sParam.sSpatialLayers[iIndexLayer].iVideoHeight = 720; sParam.sSpatialLayers[iIndexLayer].fFrameRate = 30.0f; sParam.sSpatialLayers[iIndexLayer].iQualityLayerNum = 1; sParam.sSpatialLayers[iIndexLayer].iSpatialBitrate = 1500000; sParam.sSpatialLayers[iIndexLayer].iCgsSnrRefined = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[0] = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[1] = 0; // sParam.sSpatialLayers[iIndexLayer].iQualityBitrate[2] = 0; sParam.sSpatialLayers[iIndexLayer].iInterSpatialLayerPredFlag = 0; #ifdef MT_ENABLED sParam.sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = 0; sParam.sSpatialLayers[iIndexLayer].sSliceCfg.sSliceArgument.uiSliceNum = 1; #endif float fMaxFr = sParam.sSpatialLayers[sParam.iSpatialLayerNum-1].fFrameRate; for (int32_t i = sParam.iSpatialLayerNum-2; i >= 0; -- i) { if (sParam.sSpatialLayers[i].fFrameRate > fMaxFr+EPSN) fMaxFr = sParam.sSpatialLayers[i].fFrameRate; } sParam.fFrameRate = fMaxFr; return 0; } /* For SVC Demo test */ int ProcessEncodingSvcWithParam ( ISVCEncoder *pPtrEnc, int argc, char ** argv ) { const char * kpSrcFile = argv[1]; const char * kpStrBsFile = argv[2]; if ( pPtrEnc == NULL || kpSrcFile == NULL || kpStrBsFile == NULL ) return 1; FILE *pFpBs = NULL; FILE *pFpSrc= NULL; SFrameBSInfo sFbi; SVCEncodingParam sSvcParam; int64_t iStart = 0, iTotal = 0; #if defined ( STICK_STREAM_SIZE ) FILE *fTrackStream = fopen("coding_size.stream", "wb");; #endif pFpSrc = fopen(kpSrcFile, "rb"); if ( NULL == pFpSrc ) return 1; pFpBs = fopen(kpStrBsFile, "wb"); if ( NULL == pFpBs){ fclose( pFpSrc ); pFpSrc = NULL; return 1; } memset( &sFbi, 0, sizeof(SFrameBSInfo) ); memset( &sSvcParam, 0, sizeof(SVCEncodingParam) ); FillSpecificParameters(sSvcParam); int iParsedNum = 3; if( ParseCommandLine(argc-iParsedNum, argv+iParsedNum, sSvcParam) != 0 ) { printf("parse pCommand line failed\n"); return 1; } if ( cmResultSuccess != pPtrEnc->Initialize( &sSvcParam, INIT_TYPE_PARAMETER_BASED ) ) { fprintf(stderr, "Encoder Initialization failed!\n"); return 1; } const int32_t iPicLumaSize = sSvcParam.iPicWidth * sSvcParam.iPicHeight; int32_t iFrameSize = 0; uint8_t *pPlanes[3] = { 0 }; switch( sSvcParam.iInputCsp ) { int iStride; case videoFormatI420: case videoFormatYV12: iFrameSize = (3 * iPicLumaSize)>>1; pPlanes[0] = new uint8_t[iFrameSize]; pPlanes[1] = pPlanes[0] + iPicLumaSize; pPlanes[2] = pPlanes[1] + (iPicLumaSize>>2); break; case videoFormatYUY2: case videoFormatYVYU: case videoFormatUYVY: iStride = CALC_BI_STRIDE(sSvcParam.iPicWidth, 16); iFrameSize = iStride * sSvcParam.iPicHeight; pPlanes[0] = new uint8_t[iFrameSize]; break; case videoFormatRGB: case videoFormatBGR: iStride = CALC_BI_STRIDE(sSvcParam.iPicWidth, 24); iFrameSize = iStride * sSvcParam.iPicHeight; pPlanes[0] = new uint8_t[iFrameSize]; break; case videoFormatBGRA: case videoFormatRGBA: case videoFormatARGB: case videoFormatABGR: iStride = 4 * sSvcParam.iPicWidth; iFrameSize = iStride * sSvcParam.iPicHeight; pPlanes[0] = new uint8_t[iFrameSize]; break; default: return 1; } int32_t iFrame = 0; while (true) { if ( feof(pFpSrc) ) break; #ifdef ONLY_ENC_FRAMES_NUM if ( iFrame >= ONLY_ENC_FRAMES_NUM ) break; #endif//ONLY_ENC_FRAMES_NUM if ( fread(pPlanes[0], sizeof(uint8_t), iFrameSize, pFpSrc) <= 0 ) break; iStart = WelsTime(); long iEncode = pPtrEnc->EncodeFrame( pPlanes[0], &sFbi); iTotal += WelsTime() - iStart; if ( videoFrameTypeInvalid == iEncode ){ fprintf(stderr, "EncodeFrame() failed: %d.\n", iEncode); break; } /* Write bit-stream */ if ( pFpBs != NULL && videoFrameTypeSkip != iEncode ){ // file handler to write bit stream int iLayer = 0; while ( iLayer < sFbi.iLayerNum ){ SLayerBSInfo *pLayerBsInfo = &sFbi.sLayerInfo[iLayer]; if ( pLayerBsInfo != NULL ){ int iLayerSize = 0; int iNalIdx = pLayerBsInfo->iNalCount -1; do { iLayerSize += pLayerBsInfo->iNalLengthInByte[iNalIdx]; -- iNalIdx; } while(iNalIdx >= 0); fwrite(pLayerBsInfo->pBsBuf, 1, iLayerSize, pFpBs); // write pure bit stream into file } ++ iLayer; } ++ iFrame; } } if (iFrame > 0){ double dElapsed = iTotal / 1e6; printf( "Frames: %d\nencode time: %f sec\nFPS: %f fps\n", iFrame, dElapsed, (iFrame * 1.0)/dElapsed ); } if ( NULL != pPlanes[0] ) { delete [] pPlanes[0]; pPlanes[0] = NULL; } if ( pFpBs ){ fclose( pFpBs ); pFpBs = NULL; } if ( pFpSrc ){ fclose( pFpSrc ); pFpSrc= NULL; } return 0; } int ProcessEncodingSvcWithConfig ( ISVCEncoder *pPtrEnc, int argc, char **argv ) { int iRet = 0; if ( pPtrEnc == NULL ) return 1; SFrameBSInfo sFbi; SWelsSvcCodingParam sSvcParam; int64_t iStart = 0, iTotal = 0; // Preparing encoding process FILE* pFileYUV[MAX_DEPENDENCY_LAYER] = {0}; int32_t iActualFrameEncodedCount = 0; int32_t iFrameIdx = 0; int32_t iTotalFrameMax = -1; int8_t iDlayerIdx = 0; uint8_t * pYUV[MAX_DEPENDENCY_LAYER] = { 0 }; SSourcePicture ** pSrcPicList = NULL; #if (defined(RUN_SIMULATOR) || defined(WIN32)||defined(_MACH_PLATFORM) || (defined(__GNUC__))) // Inactive with sink with output file handler FILE *pFpBs = NULL; #endif #if defined(COMPARE_DATA) //For getting the golden file handle FILE *fpGolden = NULL; #endif #if defined ( STICK_STREAM_SIZE ) FILE *fTrackStream = fopen("coding_size.stream", "wb");; #endif SFilesSet fs; // for configuration file CReadConfig cRdCfg; int iParsedNum = 2; memset(&sFbi, 0, sizeof(SFrameBSInfo)); memset(&sSvcParam, 0, sizeof(SWelsSvcCodingParam)); sSvcParam.iInputCsp = videoFormatI420; // I420 in default sSvcParam.sDependencyLayers[0].uiProfileIdc = PRO_BASELINE; // svc_cfg->sDependencyLayers[0].frext_mode = 0; // for configuration file cRdCfg.Openf(argv[1]); if ( !cRdCfg.ExistFile() ){ fprintf(stderr, "Specified file: %s not exist, maybe invalid path or parameter settting.\n", cRdCfg.GetFileName().c_str()); iRet = 1; goto INSIDE_MEM_FREE; } iRet = ParseConfig(cRdCfg, sSvcParam, fs); if ( iRet ){ fprintf(stderr, "parse svc parameter config file failed.\n"); iRet = 1; goto INSIDE_MEM_FREE; } if ( ParseCommandLine(argc-iParsedNum, argv+iParsedNum, sSvcParam, fs) != 0 ) { printf("parse pCommand line failed\n"); iRet = 1; goto INSIDE_MEM_FREE; } iTotalFrameMax = (int32_t)sSvcParam.uiFrameToBeCoded; sSvcParam.SUsedPicRect.iLeft = 0; sSvcParam.SUsedPicRect.iTop = 0; // sSvcParam.max_pic_width = sSvcParam.iActualPicWidth = sSvcParam.SUsedPicRect.iWidth = sSvcParam.sDependencyLayers[sSvcParam.iNumDependencyLayer-1].iFrameWidth; // pSvcParam.max_pic_height = sSvcParam.iActualPicHeight = sSvcParam.SUsedPicRect.iHeight = sSvcParam.sDependencyLayers[sSvcParam.iNumDependencyLayer-1].iFrameHeight; if ( cmResultSuccess != pPtrEnc->Initialize((void *)&sSvcParam, INIT_TYPE_CONFIG_BASED) ) // SVC encoder initialization { fprintf( stderr, "SVC encoder Initialize failed\n"); iRet = 1; goto INSIDE_MEM_FREE; } #if (defined(RUN_SIMULATOR) || defined(WIN32)||defined(_MACH_PLATFORM) || (defined(__GNUC__))) // Inactive with sink with output file handler if ( fs.strBsFile.length() > 0 ){ pFpBs = fopen (fs.strBsFile.c_str(), "wb"); if (pFpBs == NULL){ fprintf( stderr, "Can not open file (%s) to write bitstream!\n", fs.strBsFile.c_str() ); iRet = 1; goto INSIDE_MEM_FREE; } } #endif #if defined(COMPARE_DATA) //For getting the golden file handle if((fpGolden = fopen(argv[3], "rb")) == NULL) { fprintf(stderr, "Unable to open golden sequence file, check corresponding path!\n"); iRet = 1; goto INSIDE_MEM_FREE; } #endif pSrcPicList = new SSourcePicture * [sSvcParam.iNumDependencyLayer]; while (iDlayerIdx < sSvcParam.iNumDependencyLayer) { SDLayerParam *pDLayer = &sSvcParam.sDependencyLayers[iDlayerIdx]; const int kiPicResSize = pDLayer->iFrameWidth * pDLayer->iFrameHeight; SSourcePicture * pSrcPic = new SSourcePicture; if( pSrcPic == NULL ){ iRet = 1; goto INSIDE_MEM_FREE; } memset(pSrcPic, 0, sizeof(SSourcePicture)); pYUV[iDlayerIdx] = new uint8_t [(3*kiPicResSize)>>1]; if (pYUV[iDlayerIdx] == NULL) { iRet = 1; goto INSIDE_MEM_FREE; } pSrcPic->iColorFormat = videoFormatI420; pSrcPic->iPicWidth = pDLayer->iFrameWidth; pSrcPic->iPicHeight = pDLayer->iFrameHeight; pSrcPic->iStride[0] = pDLayer->iFrameWidth; pSrcPic->iStride[1] = pSrcPic->iStride[2] = pDLayer->iFrameWidth >> 1; pSrcPicList[iDlayerIdx] = pSrcPic; pFileYUV[iDlayerIdx] = fopen( fs.sSpatialLayers[iDlayerIdx].strSeqFile.c_str(), "rb"); if (pFileYUV[iDlayerIdx] != NULL){ if( !fseek( pFileYUV[iDlayerIdx], 0, SEEK_END ) ) { int64_t i_size = ftell( pFileYUV[iDlayerIdx] ); fseek( pFileYUV[iDlayerIdx], 0, SEEK_SET ); iTotalFrameMax = WELS_MAX( (int32_t)(i_size / ((3*kiPicResSize)>>1) ), iTotalFrameMax ); } } else{ fprintf(stderr, "Unable to open source sequence file (%s), check corresponding path!\n", fs.sSpatialLayers[iDlayerIdx].strSeqFile.c_str()); iRet = 1; goto INSIDE_MEM_FREE; } ++ iDlayerIdx; } iFrameIdx = 0; while (iFrameIdx < iTotalFrameMax && (((int32_t)sSvcParam.uiFrameToBeCoded <= 0) || (iFrameIdx < (int32_t)sSvcParam.uiFrameToBeCoded)) ) { bool_t bOnePicAvailableAtLeast = false; bool_t bSomeSpatialUnavailable = false; #ifdef ONLY_ENC_FRAMES_NUM // Only encoded some limited frames here if ( iActualFrameEncodedCount >= ONLY_ENC_FRAMES_NUM ) { break; } #endif//ONLY_ENC_FRAMES_NUM iDlayerIdx = 0; int nSpatialLayerNum = 0; while (iDlayerIdx < sSvcParam.iNumDependencyLayer) { SDLayerParam * pDLayer = &sSvcParam.sDependencyLayers[iDlayerIdx]; const int kiPicResSize = ((pDLayer->iFrameWidth * pDLayer->iFrameHeight)*3)>>1; uint32_t uiSkipIdx = (1 << pDLayer->iTemporalResolution); bool_t bCanBeRead= false; if ( iFrameIdx % uiSkipIdx == 0 ) // such layer is enabled to encode indeed { bCanBeRead = (fread(pYUV[iDlayerIdx], 1, kiPicResSize, pFileYUV[iDlayerIdx]) == kiPicResSize); if ( bCanBeRead ) { bOnePicAvailableAtLeast = true; pSrcPicList[nSpatialLayerNum]->pData[0] = pYUV[iDlayerIdx]; pSrcPicList[nSpatialLayerNum]->pData[1] = pSrcPicList[nSpatialLayerNum]->pData[0] + (pDLayer->iFrameWidth * pDLayer->iFrameHeight); pSrcPicList[nSpatialLayerNum]->pData[2] = pSrcPicList[nSpatialLayerNum]->pData[1] + ((pDLayer->iFrameWidth * pDLayer->iFrameHeight)>>2); pSrcPicList[nSpatialLayerNum]->iPicWidth = pDLayer->iFrameWidth; pSrcPicList[nSpatialLayerNum]->iPicHeight = pDLayer->iFrameHeight; pSrcPicList[nSpatialLayerNum]->iStride[0] = pDLayer->iFrameWidth; pSrcPicList[nSpatialLayerNum]->iStride[1] = pSrcPicList[nSpatialLayerNum]->iStride[2] = pDLayer->iFrameWidth >> 1; ++ nSpatialLayerNum; } else // file end while reading { bSomeSpatialUnavailable = true; break; } } else { } ++ iDlayerIdx; } if ( bSomeSpatialUnavailable ) break; if ( !bOnePicAvailableAtLeast ){ ++ iFrameIdx; continue; } // To encoder this frame iStart = WelsTime(); int iEncFrames = pPtrEnc->EncodeFrame(const_cast<const SSourcePicture**>(pSrcPicList), nSpatialLayerNum, &sFbi); iTotal += WelsTime() - iStart; // fixed issue in case dismatch source picture introduced by frame skipped, 1/12/2010 if ( videoFrameTypeSkip == iEncFrames ) { continue; } if ( iEncFrames != videoFrameTypeInvalid && iEncFrames != videoFrameTypeSkip ) { int iLayer = 0; int iFrameSize = 0; while ( iLayer < sFbi.iLayerNum ){ SLayerBSInfo *pLayerBsInfo = &sFbi.sLayerInfo[iLayer]; if ( pLayerBsInfo != NULL ){ int iLayerSize = 0; int iNalIdx = pLayerBsInfo->iNalCount -1; do { iLayerSize += pLayerBsInfo->iNalLengthInByte[iNalIdx]; -- iNalIdx; } while(iNalIdx >= 0); #if defined(COMPARE_DATA) //Comparing the result of encoder with golden pData { unsigned char *pUCArry = new unsigned char [iLayerSize]; fread(pUCArry, 1, iLayerSize, fpGolden); for (int w=0; w<iLayerSize; w++) { if (pUCArry[w] != pLayerBsInfo->pBsBuf[w]) { fprintf(stderr, "error @frame%d/layer%d/byte%d!!!!!!!!!!!!!!!!!!!!!!!!\n", iFrameIdx, iLayer, w); //fprintf(stderr, "%x - %x\n", pUCArry[w], pLayerBsInfo->pBsBuf[w]); break; } } fprintf( stderr, "frame%d/layer%d comparation completed!\n", iFrameIdx, iLayer); delete [] pUCArry; } #endif #if (defined(RUN_SIMULATOR) || defined(WIN32)||defined(_MACH_PLATFORM) || (defined(__GNUC__))) fwrite(pLayerBsInfo->pBsBuf, 1, iLayerSize, pFpBs); // write pure bit stream into file #endif iFrameSize += iLayerSize; } ++ iLayer; } #if defined (STICK_STREAM_SIZE) if ( fTrackStream ){ fwrite( &iFrameSize, 1, sizeof(int), fTrackStream ); } #endif//STICK_STREAM_SIZE ++ iActualFrameEncodedCount; // excluding skipped frame time } else{ fprintf(stderr, "EncodeFrame(), ret: %d, frame index: %d.\n", iEncFrames, iFrameIdx); } ++ iFrameIdx; } if (iActualFrameEncodedCount > 0){ double dElapsed = iTotal / 1e6; printf( "Width: %d\nHeight: %d\nFrames: %d\nencode time: %f sec\nFPS: %f fps\n", sSvcParam.iActualPicWidth, sSvcParam.iActualPicHeight, iActualFrameEncodedCount, dElapsed, (iActualFrameEncodedCount * 1.0)/dElapsed ); } INSIDE_MEM_FREE: { #if (defined(RUN_SIMULATOR) || defined(WIN32)||defined(_MACH_PLATFORM) || (defined(__GNUC__))) if (pFpBs) { fclose(pFpBs); pFpBs = NULL; } #endif #if defined (STICK_STREAM_SIZE) if ( fTrackStream ){ fclose( fTrackStream ); fTrackStream = NULL; } #endif #if defined (COMPARE_DATA) if ( fpGolden ){ fclose(fpGolden); fpGolden = NULL; } #endif // Destruction memory introduced in this routine iDlayerIdx = 0; while (iDlayerIdx < sSvcParam.iNumDependencyLayer) { if (pFileYUV[iDlayerIdx] != NULL){ fclose(pFileYUV[iDlayerIdx]); pFileYUV[iDlayerIdx] = NULL; } ++ iDlayerIdx; } if( pSrcPicList ){ for( int32_t i=0;i<sSvcParam.iNumDependencyLayer;i++ ) { if( pSrcPicList[i] ){ delete pSrcPicList[i]; pSrcPicList[i] = NULL; } } delete pSrcPicList; pSrcPicList = NULL; } for( int32_t i=0;i<MAX_DEPENDENCY_LAYER;i++ ){ if( pYUV[i] ){ delete [] pYUV[i]; pYUV[i] = NULL; } } } return iRet; } // Merge from Heifei's Wonder. Lock process to a single core void LockToSingleCore() { #ifdef _MSC_VER //for 2005 compiler, change "DWORD" to "DWORD_PTR" DWORD ProcessAffMask = 0, SystemAffMask = 0; HANDLE hProcess = GetCurrentProcess(); GetProcessAffinityMask(hProcess, &ProcessAffMask, &SystemAffMask); if (ProcessAffMask > 1) { // more than one CPU core available. Fix to only one: if (ProcessAffMask & 2) { ProcessAffMask = 2; } else { ProcessAffMask = 1; } // Lock process to a single CPU core SetProcessAffinityMask(hProcess, ProcessAffMask); } // set high priority to avoid interrupts during test SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); #endif return ; } long CreateSVCEncHandle(ISVCEncoder** ppEncoder) { long ret = 0; #if defined(MACOS) ret = WelsEncBundleLoad(); WelsEncBundleCreateEncoder(ppEncoder); #else ret = CreateSVCEncoder( ppEncoder ); #endif//MACOS return ret; } void DestroySVCEncHanlde(ISVCEncoder* pEncoder) { if (pEncoder) { #if defined(MACOS) WelsEncBundleDestroyEncoder(pEncoder); #else DestroySVCEncoder( pEncoder ); #endif//MACOS } } /**************************************************************************** * main: ****************************************************************************/ #if (defined(MACOS)) int main_demo( int argc, char **argv ) #else int main( int argc, char **argv ) #endif { ISVCEncoder* pSVCEncoder = NULL; FILE *pFileOut = NULL; FILE *pFileIn = NULL; int iRet = 0; #ifdef _MSC_VER _setmode(_fileno(stdin), _O_BINARY); /* thanks to Marcoss Morais <morais at dee.ufcg.edu.br> */ _setmode(_fileno(stdout), _O_BINARY); // remove the LOCK_TO_SINGLE_CORE micro, user need to enable it with manual // LockToSingleCore(); #endif /* Control-C handler */ signal( SIGINT, SigIntHandler ); iRet = CreateSVCEncHandle( &pSVCEncoder ); if ( iRet ) { cout << "CreateSVCEncoder() failed!!" << endl; goto exit; } if (argc < 2) { goto exit; } else { string strCfgFileName = argv[1]; basic_string <char>::size_type index; static const basic_string <char>::size_type npos = size_t(-1); index = strCfgFileName.rfind(".cfg"); // check configuration type (like .cfg?) if ( index == npos ) { if (argc > 2) { iRet = ProcessEncodingSvcWithParam( pSVCEncoder, argc, argv ); if ( iRet != 0 ) goto exit; } else { cout << "You specified pCommand is invalid!!" << endl; goto exit; } } else { iRet = ProcessEncodingSvcWithConfig( pSVCEncoder, argc, argv); if (iRet > 0) goto exit; } } DestroySVCEncHanlde( pSVCEncoder ); return 0; exit: DestroySVCEncHanlde( pSVCEncoder ); PrintHelp(); return 1; }