• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2  * \copy
3  *     Copyright (c)  2013, Cisco Systems
4  *     All rights reserved.
5  *
6  *     Redistribution and use in source and binary forms, with or without
7  *     modification, are permitted provided that the following conditions
8  *     are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *
13  *        * Redistributions in binary form must reproduce the above copyright
14  *          notice, this list of conditions and the following disclaimer in
15  *          the documentation and/or other materials provided with the
16  *          distribution.
17  *
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  *     POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 #define _CRT_SECURE_NO_WARNINGS
34 #include <stdio.h>
35 #include <string.h>
36 #include <assert.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #if defined (ANDROID_NDK)
40 #include <android/log.h>
41 #endif
42 #ifdef ONLY_ENC_FRAMES_NUM
43 #undef ONLY_ENC_FRAMES_NUM
44 #endif//ONLY_ENC_FRAMES_NUM
45 #define ONLY_ENC_FRAMES_NUM INT_MAX // 2, INT_MAX // type the num you try to encode here, 2, 10, etc
46 
47 #if defined (WINDOWS_PHONE)
48 float   g_fFPS           = 0.0;
49 double  g_dEncoderTime   = 0.0;
50 int     g_iEncodedFrame  = 0;
51 #endif
52 
53 #if defined (ANDROID_NDK)
54 #define LOG_TAG "welsenc"
55 #define LOGI(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
56 #define printf(...) LOGI(__VA_ARGS__)
57 #define fprintf(a, ...) LOGI(__VA_ARGS__)
58 #endif
59 //#define STICK_STREAM_SIZE
60 
61 #include "measure_time.h"
62 #include "read_config.h"
63 
64 #include "typedefs.h"
65 
66 #ifdef _MSC_VER
67 #include <io.h>     /* _setmode() */
68 #include <fcntl.h>  /* _O_BINARY */
69 #endif//_MSC_VER
70 
71 #include "codec_def.h"
72 #include "codec_api.h"
73 #include "extern.h"
74 #include "macros.h"
75 #include "wels_const.h"
76 
77 #include "mt_defs.h"
78 #include "WelsThreadLib.h"
79 
80 #ifdef _WIN32
81 #ifdef WINAPI_FAMILY
82 #include <winapifamily.h>
83 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
84 #define HAVE_PROCESS_AFFINITY
85 #endif
86 #else /* defined(WINAPI_FAMILY) */
87 #define HAVE_PROCESS_AFFINITY
88 #endif
89 #endif /* _WIN32 */
90 
91 #if defined(__linux__) || defined(__unix__)
92 #define _FILE_OFFSET_BITS 64
93 #endif
94 
95 #include <iostream>
96 using namespace std;
97 using namespace WelsEnc;
98 
99 /*
100  *  Layer Context
101  */
102 typedef struct LayerpEncCtx_s {
103   int32_t       iDLayerQp;
104   SSliceArgument  sSliceArgument;
105 } SLayerPEncCtx;
106 
107 typedef struct tagFilesSet {
108   string strBsFile;
109   string strSeqFile;    // for cmd lines
110   string strLayerCfgFile[MAX_DEPENDENCY_LAYER];
111   char   sRecFileName[MAX_DEPENDENCY_LAYER][MAX_FNAME_LEN];
112   uint32_t uiFrameToBeCoded;
113   bool     bEnableMultiBsFile;
114 
tagFilesSettagFilesSet115   tagFilesSet() {
116     uiFrameToBeCoded = 0;
117     bEnableMultiBsFile = false;
118     for (int i = 0; i < MAX_DEPENDENCY_LAYER; i++)
119       sRecFileName[i][0] = '\0';
120   }
121 } SFilesSet;
122 
123 
124 
125 /* Ctrl-C handler */
126 static int     g_iCtrlC = 0;
SigIntHandler(int a)127 static void    SigIntHandler (int a) {
128   g_iCtrlC = 1;
129 }
130 static int     g_LevelSetting = WELS_LOG_ERROR;
131 
ParseLayerConfig(CReadConfig & cRdLayerCfg,const int iLayer,SEncParamExt & pSvcParam,SFilesSet & sFileSet)132 int ParseLayerConfig (CReadConfig& cRdLayerCfg, const int iLayer, SEncParamExt& pSvcParam, SFilesSet& sFileSet) {
133   if (!cRdLayerCfg.ExistFile()) {
134     fprintf (stderr, "Unabled to open layer #%d configuration file: %s.\n", iLayer, cRdLayerCfg.GetFileName().c_str());
135     return 1;
136   }
137 
138   SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
139   int iLeftTargetBitrate = (pSvcParam.iRCMode != RC_OFF_MODE) ? pSvcParam.iTargetBitrate : 0;
140   SLayerPEncCtx sLayerCtx;
141   memset (&sLayerCtx, 0, sizeof (SLayerPEncCtx));
142 
143   string strTag[4];
144   string str_ ("SlicesAssign");
145   const int kiSize = (int)str_.size();
146 
147   while (!cRdLayerCfg.EndOfFile()) {
148     long iLayerRd = cRdLayerCfg.ReadLine (&strTag[0]);
149     if (iLayerRd > 0) {
150       if (strTag[0].empty())
151         continue;
152       if (strTag[0].compare ("FrameWidth") == 0) {
153         pDLayer->iVideoWidth = atoi (strTag[1].c_str());
154       } else if (strTag[0].compare ("FrameHeight") == 0) {
155         pDLayer->iVideoHeight = atoi (strTag[1].c_str());
156       } else if (strTag[0].compare ("FrameRateOut") == 0) {
157         pDLayer->fFrameRate = (float)atof (strTag[1].c_str());
158       } else if (strTag[0].compare ("ReconFile") == 0) {
159         const unsigned int kiLen = (unsigned int)strTag[1].length();
160         if (kiLen >= sizeof (sFileSet.sRecFileName[iLayer]))
161           return -1;
162         sFileSet.sRecFileName[iLayer][kiLen] = '\0';
163         strncpy (sFileSet.sRecFileName[iLayer], strTag[1].c_str(), kiLen); // confirmed_safe_unsafe_usage
164       } else if (strTag[0].compare ("ProfileIdc") == 0) {
165         pDLayer->uiProfileIdc = (EProfileIdc)atoi (strTag[1].c_str());
166       } else if (strTag[0].compare ("FRExt") == 0) {
167 //        pDLayer->frext_mode = (bool)atoi(strTag[1].c_str());
168       } else if (strTag[0].compare ("SpatialBitrate") == 0) {
169         pDLayer->iSpatialBitrate = 1000 * atoi (strTag[1].c_str());
170         if (pSvcParam.iRCMode != RC_OFF_MODE) {
171           if (pDLayer->iSpatialBitrate <= 0) {
172             fprintf (stderr, "Invalid spatial bitrate(%d) in dependency layer #%d.\n", pDLayer->iSpatialBitrate, iLayer);
173             return -1;
174           }
175           if (pDLayer->iSpatialBitrate > iLeftTargetBitrate) {
176             fprintf (stderr, "Invalid spatial(#%d) bitrate(%d) setting due to unavailable left(%d)!\n", iLayer,
177                      pDLayer->iSpatialBitrate, iLeftTargetBitrate);
178             return -1;
179           }
180           iLeftTargetBitrate -= pDLayer->iSpatialBitrate;
181         }
182       } else if (strTag[0].compare ("MaxSpatialBitrate") == 0) {
183         pDLayer->iMaxSpatialBitrate = 1000 * atoi (strTag[1].c_str());
184         if (pSvcParam.iRCMode != RC_OFF_MODE) {
185           if (pDLayer->iMaxSpatialBitrate < 0) {
186             fprintf (stderr, "Invalid max spatial bitrate(%d) in dependency layer #%d.\n", pDLayer->iMaxSpatialBitrate, iLayer);
187             return -1;
188           }
189           if (pDLayer->iMaxSpatialBitrate > 0 && pDLayer->iMaxSpatialBitrate < pDLayer->iSpatialBitrate) {
190             fprintf (stderr, "Invalid max spatial(#%d) bitrate(%d) setting::: < layerBitrate(%d)!\n", iLayer,
191                      pDLayer->iMaxSpatialBitrate, pDLayer->iSpatialBitrate);
192             return -1;
193           }
194         }
195       } else if (strTag[0].compare ("InitialQP") == 0) {
196         sLayerCtx.iDLayerQp = atoi (strTag[1].c_str());
197       } else if (strTag[0].compare ("SliceMode") == 0) {
198         sLayerCtx.sSliceArgument.uiSliceMode = (SliceModeEnum)atoi (strTag[1].c_str());
199       } else if (strTag[0].compare ("SliceSize") == 0) { //SM_SIZELIMITED_SLICE
200         sLayerCtx.sSliceArgument.uiSliceSizeConstraint = atoi (strTag[1].c_str());
201         continue;
202       } else if (strTag[0].compare ("SliceNum") == 0) {
203         sLayerCtx.sSliceArgument.uiSliceNum = atoi (strTag[1].c_str());
204       } else if (strTag[0].compare (0, kiSize, str_) == 0) {
205         const char* kpString = strTag[0].c_str();
206         int uiSliceIdx = atoi (&kpString[kiSize]);
207         assert (uiSliceIdx < MAX_SLICES_NUM);
208         sLayerCtx.sSliceArgument.uiSliceMbNum[uiSliceIdx] = atoi (strTag[1].c_str());
209       }
210     }
211   }
212   pDLayer->iDLayerQp             = sLayerCtx.iDLayerQp;
213   pDLayer->sSliceArgument.uiSliceMode = sLayerCtx.sSliceArgument.uiSliceMode;
214 
215   memcpy (&pDLayer->sSliceArgument, &sLayerCtx.sSliceArgument, sizeof (SSliceArgument)); // confirmed_safe_unsafe_usage
216   memcpy (&pDLayer->sSliceArgument.uiSliceMbNum[0], &sLayerCtx.sSliceArgument.uiSliceMbNum[0],
217           sizeof (sLayerCtx.sSliceArgument.uiSliceMbNum)); // confirmed_safe_unsafe_usage
218 
219   return 0;
220 }
ParseConfig(CReadConfig & cRdCfg,SSourcePicture * pSrcPic,SEncParamExt & pSvcParam,SFilesSet & sFileSet)221 int ParseConfig (CReadConfig& cRdCfg, SSourcePicture* pSrcPic, SEncParamExt& pSvcParam, SFilesSet& sFileSet) {
222   string strTag[4];
223   int32_t iRet = 0;
224   int8_t iLayerCount = 0;
225 
226   while (!cRdCfg.EndOfFile()) {
227     long iRd = cRdCfg.ReadLine (&strTag[0]);
228     if (iRd > 0) {
229       if (strTag[0].empty())
230         continue;
231 
232       if (strTag[0].compare ("UsageType") == 0) {
233         pSvcParam.iUsageType = (EUsageType)atoi (strTag[1].c_str());
234       } else if (strTag[0].compare ("SimulcastAVC") == 0) {
235         pSvcParam.bSimulcastAVC = atoi (strTag[1].c_str()) ? true : false;
236       } else if (strTag[0].compare ("SourceWidth") == 0) {
237         pSrcPic->iPicWidth = atoi (strTag[1].c_str());
238       } else if (strTag[0].compare ("SourceHeight") == 0) {
239         pSrcPic->iPicHeight = atoi (strTag[1].c_str());
240       } else if (strTag[0].compare ("InputFile") == 0) {
241         if (strTag[1].length() > 0)
242           sFileSet.strSeqFile = strTag[1];
243       } else if (strTag[0].compare ("OutputFile") == 0) {
244         sFileSet.strBsFile = strTag[1];
245       } else if (strTag[0].compare ("MaxFrameRate") == 0) {
246         pSvcParam.fMaxFrameRate = (float)atof (strTag[1].c_str());
247       } else if (strTag[0].compare ("FramesToBeEncoded") == 0) {
248         sFileSet.uiFrameToBeCoded = atoi (strTag[1].c_str());
249       } else if (strTag[0].compare ("TemporalLayerNum") == 0) {
250         pSvcParam.iTemporalLayerNum = atoi (strTag[1].c_str());
251       } else if (strTag[0].compare ("IntraPeriod") == 0) {
252         pSvcParam.uiIntraPeriod = atoi (strTag[1].c_str());
253       } else if (strTag[0].compare ("MaxNalSize") == 0) {
254         pSvcParam.uiMaxNalSize = atoi (strTag[1].c_str());
255       } else if (strTag[0].compare ("SpsPpsIDStrategy") == 0) {
256         int32_t iValue = atoi (strTag[1].c_str());
257         switch (iValue) {
258         case 0:
259           pSvcParam.eSpsPpsIdStrategy  = CONSTANT_ID;
260           break;
261         case 0x01:
262           pSvcParam.eSpsPpsIdStrategy  = INCREASING_ID;
263           break;
264         case 0x02:
265           pSvcParam.eSpsPpsIdStrategy  = SPS_LISTING;
266           break;
267         case 0x03:
268           pSvcParam.eSpsPpsIdStrategy  = SPS_LISTING_AND_PPS_INCREASING;
269           break;
270         case 0x06:
271           pSvcParam.eSpsPpsIdStrategy  = SPS_PPS_LISTING;
272           break;
273         default:
274           pSvcParam.eSpsPpsIdStrategy  = CONSTANT_ID;
275           break;
276         }
277       } else if (strTag[0].compare ("EnableMultiBsFile") == 0) {
278         sFileSet.bEnableMultiBsFile = atoi (strTag[1].c_str()) ? true : false;
279       } else if (strTag[0].compare ("EnableScalableSEI") == 0) {
280         pSvcParam.bEnableSSEI = atoi (strTag[1].c_str()) ? true : false;
281       } else if (strTag[0].compare ("EnableFrameCropping") == 0) {
282         pSvcParam.bEnableFrameCroppingFlag = (atoi (strTag[1].c_str()) != 0);
283       } else if (strTag[0].compare ("EntropyCodingModeFlag") == 0) {
284         pSvcParam.iEntropyCodingModeFlag = (atoi (strTag[1].c_str()) != 0);
285       } else if (strTag[0].compare ("ComplexityMode") == 0) {
286         pSvcParam.iComplexityMode = (ECOMPLEXITY_MODE) (atoi (strTag[1].c_str()));
287       } else if (strTag[0].compare ("LoopFilterDisableIDC") == 0) {
288         pSvcParam.iLoopFilterDisableIdc = (int8_t)atoi (strTag[1].c_str());
289         if (pSvcParam.iLoopFilterDisableIdc > 6 || pSvcParam.iLoopFilterDisableIdc < 0) {
290           fprintf (stderr, "Invalid parameter in iLoopFilterDisableIdc: %d.\n", pSvcParam.iLoopFilterDisableIdc);
291           iRet = 1;
292           break;
293         }
294       } else if (strTag[0].compare ("LoopFilterAlphaC0Offset") == 0) {
295         pSvcParam.iLoopFilterAlphaC0Offset = (int8_t)atoi (strTag[1].c_str());
296         if (pSvcParam.iLoopFilterAlphaC0Offset < -6)
297           pSvcParam.iLoopFilterAlphaC0Offset = -6;
298         else if (pSvcParam.iLoopFilterAlphaC0Offset > 6)
299           pSvcParam.iLoopFilterAlphaC0Offset = 6;
300       } else if (strTag[0].compare ("LoopFilterBetaOffset") == 0) {
301         pSvcParam.iLoopFilterBetaOffset = (int8_t)atoi (strTag[1].c_str());
302         if (pSvcParam.iLoopFilterBetaOffset < -6)
303           pSvcParam.iLoopFilterBetaOffset = -6;
304         else if (pSvcParam.iLoopFilterBetaOffset > 6)
305           pSvcParam.iLoopFilterBetaOffset = 6;
306       } else if (strTag[0].compare ("MultipleThreadIdc") == 0) {
307         // # 0: auto(dynamic imp. internal encoder); 1: multiple threads imp. disabled; > 1: count number of threads;
308         pSvcParam.iMultipleThreadIdc = atoi (strTag[1].c_str());
309         if (pSvcParam.iMultipleThreadIdc < 0)
310           pSvcParam.iMultipleThreadIdc = 0;
311         else if (pSvcParam.iMultipleThreadIdc > MAX_THREADS_NUM)
312           pSvcParam.iMultipleThreadIdc = MAX_THREADS_NUM;
313       } else if (strTag[0].compare ("UseLoadBalancing") == 0) {
314         pSvcParam.bUseLoadBalancing = (atoi (strTag[1].c_str())) ? true : false;
315       } else if (strTag[0].compare ("RCMode") == 0) {
316         pSvcParam.iRCMode = (RC_MODES) atoi (strTag[1].c_str());
317       } else if (strTag[0].compare ("TargetBitrate") == 0) {
318         pSvcParam.iTargetBitrate = 1000 * atoi (strTag[1].c_str());
319         if ((pSvcParam.iRCMode != RC_OFF_MODE) && pSvcParam.iTargetBitrate <= 0) {
320           fprintf (stderr, "Invalid target bitrate setting due to RC enabled. Check TargetBitrate field please!\n");
321           return 1;
322         }
323       } else if (strTag[0].compare ("MaxOverallBitrate") == 0) {
324         pSvcParam.iMaxBitrate = 1000 * atoi (strTag[1].c_str());
325         if ((pSvcParam.iRCMode != RC_OFF_MODE) && pSvcParam.iMaxBitrate < 0) {
326           fprintf (stderr, "Invalid max overall bitrate setting due to RC enabled. Check MaxOverallBitrate field please!\n");
327           return 1;
328         }
329       } else if (strTag[0].compare ("MaxQp") == 0) {
330         pSvcParam.iMaxQp = atoi (strTag[1].c_str());
331       } else if (strTag[0].compare ("MinQp") == 0) {
332         pSvcParam.iMinQp = atoi (strTag[1].c_str());
333       } else if (strTag[0].compare ("EnableDenoise") == 0) {
334         pSvcParam.bEnableDenoise = atoi (strTag[1].c_str()) ? true : false;
335       } else if (strTag[0].compare ("EnableSceneChangeDetection") == 0) {
336         pSvcParam.bEnableSceneChangeDetect = atoi (strTag[1].c_str()) ? true : false;
337       } else if (strTag[0].compare ("EnableBackgroundDetection") == 0) {
338         pSvcParam.bEnableBackgroundDetection = atoi (strTag[1].c_str()) ? true : false;
339       } else if (strTag[0].compare ("EnableAdaptiveQuantization") == 0) {
340         pSvcParam.bEnableAdaptiveQuant = atoi (strTag[1].c_str()) ? true : false;
341       } else if (strTag[0].compare ("EnableFrameSkip") == 0) {
342         pSvcParam.bEnableFrameSkip = atoi (strTag[1].c_str()) ? true : false;
343       } else if (strTag[0].compare ("EnableLongTermReference") == 0) {
344         pSvcParam.bEnableLongTermReference = atoi (strTag[1].c_str()) ? true : false;
345       } else if (strTag[0].compare ("LongTermReferenceNumber") == 0) {
346         pSvcParam.iLTRRefNum = atoi (strTag[1].c_str());
347       } else if (strTag[0].compare ("LtrMarkPeriod") == 0) {
348         pSvcParam.iLtrMarkPeriod = (uint32_t)atoi (strTag[1].c_str());
349       } else if (strTag[0].compare ("LosslessLink") == 0) {
350         pSvcParam.bIsLosslessLink = atoi (strTag[1].c_str()) ? true : false;
351       } else if (strTag[0].compare ("NumLayers") == 0) {
352         pSvcParam.iSpatialLayerNum = (int8_t)atoi (strTag[1].c_str());
353         if (pSvcParam.iSpatialLayerNum > MAX_DEPENDENCY_LAYER || pSvcParam.iSpatialLayerNum <= 0) {
354           fprintf (stderr, "Invalid parameter in iSpatialLayerNum: %d.\n", pSvcParam.iSpatialLayerNum);
355           iRet = 1;
356           break;
357         }
358       } else if (strTag[0].compare ("LayerCfg") == 0) {
359         if (strTag[1].length() > 0)
360           sFileSet.strLayerCfgFile[iLayerCount] = strTag[1];
361 //          pSvcParam.sDependencyLayers[iLayerCount].uiDependencyId = iLayerCount;
362         ++ iLayerCount;
363       } else if (strTag[0].compare ("PrefixNALAddingCtrl") == 0) {
364         int ctrl_flag = atoi (strTag[1].c_str());
365         if (ctrl_flag > 1)
366           ctrl_flag = 1;
367         else if (ctrl_flag < 0)
368           ctrl_flag = 0;
369         pSvcParam.bPrefixNalAddingCtrl = ctrl_flag ? true : false;
370       }
371     }
372   }
373 
374   const int8_t kiActualLayerNum = WELS_MIN (pSvcParam.iSpatialLayerNum, iLayerCount);
375   if (pSvcParam.iSpatialLayerNum >
376       kiActualLayerNum) { // fixed number of dependency layer due to parameter error in settings
377     pSvcParam.iSpatialLayerNum = kiActualLayerNum;
378   }
379 
380   assert (kiActualLayerNum <= MAX_DEPENDENCY_LAYER);
381 
382   for (int8_t iLayer = 0; iLayer < kiActualLayerNum; ++ iLayer) {
383     CReadConfig cRdLayerCfg (sFileSet.strLayerCfgFile[iLayer]);
384     if (-1 == ParseLayerConfig (cRdLayerCfg, iLayer, pSvcParam, sFileSet)) {
385       iRet = 1;
386       break;
387     }
388   }
389 
390   return iRet;
391 }
392 
PrintHelp()393 void PrintHelp() {
394   printf ("\n Wels SVC Encoder Usage:\n\n");
395   printf (" Syntax: welsenc.exe -h\n");
396   printf (" Syntax: welsenc.exe welsenc.cfg\n");
397   printf (" Syntax: welsenc.exe welsenc.cfg [options]\n");
398 
399   printf ("\n Supported Options:\n");
400   printf ("  -bf          Bit Stream File\n");
401   printf ("  -org         Original file, example: -org src.yuv\n");
402   printf ("  -sw          the source width\n");
403   printf ("  -sh          the source height\n");
404   printf ("  -utype       usage type\n");
405   printf ("  -savc        simulcast avc\n");
406   printf ("  -frms        Number of total frames to be encoded\n");
407   printf ("  -frin        input frame rate\n");
408   printf ("  -numtl       Temporal layer number (default: 1)\n");
409   printf ("  -iper        Intra period (default: -1) : must be a power of 2 of GOP size (or -1)\n");
410   printf ("  -nalsize     the Maximum NAL size. which should be larger than the each layer slicesize when slice mode equals to SM_SIZELIMITED_SLICE\n");
411   printf ("  -spsid       SPS/PPS id strategy: 0:const, 1: increase, 2: sps list, 3: sps list and pps increase, 4: sps/pps list\n");
412   printf ("  -cabac       Entropy coding mode(0:cavlc 1:cabac \n");
413   printf ("  -complexity  Complexity mode (default: 0),0: low complexity, 1: medium complexity, 2: high complexity\n");
414   printf ("  -denois      Control denoising  (default: 0)\n");
415   printf ("  -scene       Control scene change detection (default: 0)\n");
416   printf ("  -bgd         Control background detection (default: 0)\n");
417   printf ("  -aq          Control adaptive quantization (default: 0)\n");
418   printf ("  -ltr         Control long term reference (default: 0)\n");
419   printf ("  -ltrnum      Control the number of long term reference((1-4):screen LTR,(1-2):video LTR \n");
420   printf ("  -ltrper      Control the long term reference marking period \n");
421   printf ("  -threadIdc   0: auto(dynamic imp. internal encoder); 1: multiple threads imp. disabled; > 1: count number of threads \n");
422   printf ("  -loadbalancing   0: turn off loadbalancing between slices when multi-threading available; 1: (default value) turn on loadbalancing between slices when multi-threading available\n");
423   printf ("  -deblockIdc  Loop filter idc (0: on, 1: off, \n");
424   printf ("  -alphaOffset AlphaOffset(-6..+6): valid range \n");
425   printf ("  -betaOffset  BetaOffset (-6..+6): valid range\n");
426   printf ("  -rc          rate control mode: -1-rc off; 0-quality mode; 1-bitrate mode; 2: buffer based mode,can't control bitrate; 3: bitrate mode based on timestamp input;\n");
427   printf ("  -tarb        Overall target bitrate\n");
428   printf ("  -maxbrTotal  Overall max bitrate\n");
429   printf ("  -maxqp       Maximum Qp (default: %d, or for screen content usage: %d)\n", QP_MAX_VALUE, MAX_SCREEN_QP);
430   printf ("  -minqp       Minimum Qp (default: %d, or for screen content usage: %d)\n", QP_MIN_VALUE, MIN_SCREEN_QP);
431   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");
432   printf ("  The options below are layer-based: (need to be set with layer id)\n");
433   printf ("  -lconfig     (Layer) (spatial layer configure file)\n");
434   printf ("  -drec        (Layer) (reconstruction file);example: -drec 0 rec.yuv.  Setting the reconstruction file, this will only functioning when dumping reconstruction is enabled\n");
435   printf ("  -dprofile    (Layer) (layer profile);example: -dprofile 0 66.  Setting the layer profile, this should be the same for all layers\n");
436   printf ("  -dw          (Layer) (output width)\n");
437   printf ("  -dh          (Layer) (output height)\n");
438   printf ("  -frout       (Layer) (output frame rate)\n");
439   printf ("  -lqp         (Layer) (base quality layer qp : must work with -ldeltaqp or -lqparr)\n");
440   printf ("  -ltarb       (Layer) (spatial layer target bitrate)\n");
441   printf ("  -lmaxb       (Layer) (spatial layer max bitrate)\n");
442   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 ; -slcmbnum: set the first slice mb num under some slice modes) \n");
443   printf ("  -trace       (Level)\n");
444   printf ("  -fixrc       Enable fix RC overshoot(default: 1)\n");
445   printf ("\n");
446 }
447 
ParseCommandLine(int argc,char ** argv,SSourcePicture * pSrcPic,SEncParamExt & pSvcParam,SFilesSet & sFileSet)448 int ParseCommandLine (int argc, char** argv, SSourcePicture* pSrcPic, SEncParamExt& pSvcParam, SFilesSet& sFileSet) {
449   char* pCommand = NULL;
450   SLayerPEncCtx sLayerCtx[MAX_SPATIAL_LAYER_NUM];
451   int n = 0;
452   string str_ ("SlicesAssign");
453 
454   while (n < argc) {
455     pCommand = argv[n++];
456 
457     if (!strcmp (pCommand, "-bf") && (n < argc))
458       sFileSet.strBsFile.assign (argv[n++]);
459     else if (!strcmp (pCommand, "-utype") && (n < argc))
460       pSvcParam.iUsageType = (EUsageType)atoi (argv[n++]);
461 
462     else if (!strcmp (pCommand, "-savc") && (n < argc))
463       pSvcParam.bSimulcastAVC =  atoi (argv[n++]) ? true : false;
464 
465     else if (!strcmp (pCommand, "-org") && (n < argc))
466       sFileSet.strSeqFile.assign (argv[n++]);
467 
468     else if (!strcmp (pCommand, "-sw") && (n < argc))//source width
469       pSrcPic->iPicWidth = atoi (argv[n++]);
470 
471     else if (!strcmp (pCommand, "-sh") && (n < argc))//source height
472       pSrcPic->iPicHeight = atoi (argv[n++]);
473 
474     else if (!strcmp (pCommand, "-frms") && (n < argc))
475       sFileSet.uiFrameToBeCoded = atoi (argv[n++]);
476 
477     else if (!strcmp (pCommand, "-frin") && (n < argc))
478       pSvcParam.fMaxFrameRate = (float) atof (argv[n++]);
479 
480     else if (!strcmp (pCommand, "-numtl") && (n < argc))
481       pSvcParam.iTemporalLayerNum = atoi (argv[n++]);
482 
483     else if (!strcmp (pCommand, "-mfile") && (n < argc))
484       sFileSet.bEnableMultiBsFile = atoi (argv[n++]) ? true : false;
485 
486     else if (!strcmp (pCommand, "-iper") && (n < argc))
487       pSvcParam.uiIntraPeriod = atoi (argv[n++]);
488 
489     else if (!strcmp (pCommand, "-nalsize") && (n < argc))
490       pSvcParam.uiMaxNalSize = atoi (argv[n++]);
491 
492     else if (!strcmp (pCommand, "-spsid") && (n < argc)) {
493       int32_t iValue = atoi (argv[n++]);
494       switch (iValue) {
495       case 0:
496         pSvcParam.eSpsPpsIdStrategy  = CONSTANT_ID;
497         break;
498       case 0x01:
499         pSvcParam.eSpsPpsIdStrategy  = INCREASING_ID;
500         break;
501       case 0x02:
502         pSvcParam.eSpsPpsIdStrategy  = SPS_LISTING;
503         break;
504       case 0x03:
505         pSvcParam.eSpsPpsIdStrategy  = SPS_LISTING_AND_PPS_INCREASING;
506         break;
507       case 0x06:
508         pSvcParam.eSpsPpsIdStrategy  = SPS_PPS_LISTING;
509         break;
510       default:
511         pSvcParam.eSpsPpsIdStrategy  = CONSTANT_ID;
512         break;
513       }
514     } else if (!strcmp (pCommand, "-cabac") && (n < argc))
515       pSvcParam.iEntropyCodingModeFlag = atoi (argv[n++]);
516 
517     else if (!strcmp (pCommand, "-complexity") && (n < argc))
518       pSvcParam.iComplexityMode = (ECOMPLEXITY_MODE)atoi (argv[n++]);
519 
520     else if (!strcmp (pCommand, "-denois") && (n < argc))
521       pSvcParam.bEnableDenoise = atoi (argv[n++]) ? true : false;
522 
523     else if (!strcmp (pCommand, "-scene") && (n < argc))
524       pSvcParam.bEnableSceneChangeDetect = atoi (argv[n++]) ? true : false;
525 
526     else if (!strcmp (pCommand, "-bgd") && (n < argc))
527       pSvcParam.bEnableBackgroundDetection = atoi (argv[n++]) ? true : false;
528 
529     else if (!strcmp (pCommand, "-aq") && (n < argc))
530       pSvcParam.bEnableAdaptiveQuant = atoi (argv[n++]) ? true : false;
531 
532     else if (!strcmp (pCommand, "-fs") && (n < argc))
533       pSvcParam.bEnableFrameSkip = atoi (argv[n++]) ? true : false;
534 
535     else if (!strcmp (pCommand, "-fixrc") && (n < argc))
536       pSvcParam.bFixRCOverShoot = atoi (argv[n++]) ? true : false;
537 
538     else if (!strcmp (pCommand, "-idrBitrateRatio") && (n < argc))
539       pSvcParam.iIdrBitrateRatio = atoi (argv[n++]);
540 
541     else if (!strcmp (pCommand, "-ltr") && (n < argc))
542       pSvcParam.bEnableLongTermReference = atoi (argv[n++]) ? true : false;
543 
544     else if (!strcmp (pCommand, "-ltrnum") && (n < argc))
545       pSvcParam.iLTRRefNum = atoi (argv[n++]);
546 
547     else if (!strcmp (pCommand, "-ltrper") && (n < argc))
548       pSvcParam.iLtrMarkPeriod = atoi (argv[n++]);
549 
550     else if (!strcmp (pCommand, "-threadIdc") && (n < argc))
551       pSvcParam.iMultipleThreadIdc = atoi (argv[n++]);
552     else if (!strcmp (pCommand, "-loadbalancing") && (n + 1 < argc)) {
553       pSvcParam.bUseLoadBalancing = (atoi (argv[n++])) ? true : false;
554     } else if (!strcmp (pCommand, "-deblockIdc") && (n < argc))
555       pSvcParam.iLoopFilterDisableIdc = atoi (argv[n++]);
556 
557     else if (!strcmp (pCommand, "-alphaOffset") && (n < argc))
558       pSvcParam.iLoopFilterAlphaC0Offset = atoi (argv[n++]);
559 
560     else if (!strcmp (pCommand, "-betaOffset") && (n < argc))
561       pSvcParam.iLoopFilterBetaOffset = atoi (argv[n++]);
562 
563     else if (!strcmp (pCommand, "-rc") && (n < argc))
564       pSvcParam.iRCMode = static_cast<RC_MODES> (atoi (argv[n++]));
565 
566     else if (!strcmp (pCommand, "-trace") && (n < argc))
567       g_LevelSetting = atoi (argv[n++]);
568 
569     else if (!strcmp (pCommand, "-tarb") && (n < argc))
570       pSvcParam.iTargetBitrate = 1000 * atoi (argv[n++]);
571 
572     else if (!strcmp (pCommand, "-maxbrTotal") && (n < argc))
573       pSvcParam.iMaxBitrate = 1000 * atoi (argv[n++]);
574 
575     else if (!strcmp (pCommand, "-maxqp") && (n < argc))
576       pSvcParam.iMaxQp = atoi (argv[n++]);
577 
578     else if (!strcmp (pCommand, "-minqp") && (n < argc))
579       pSvcParam.iMinQp = atoi (argv[n++]);
580 
581     else if (!strcmp (pCommand, "-numl") && (n < argc)) {
582       pSvcParam.iSpatialLayerNum = atoi (argv[n++]);
583     } else if (!strcmp (pCommand, "-lconfig") && (n < argc)) {
584       unsigned int iLayer = atoi (argv[n++]);
585       sFileSet.strLayerCfgFile[iLayer].assign (argv[n++]);
586       CReadConfig cRdLayerCfg (sFileSet.strLayerCfgFile[iLayer]);
587       if (-1 == ParseLayerConfig (cRdLayerCfg, iLayer, pSvcParam, sFileSet)) {
588         return 1;
589       }
590     } else if (!strcmp (pCommand, "-dprofile") && (n + 1 < argc)) {
591       unsigned int iLayer = atoi (argv[n++]);
592       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
593       pDLayer->uiProfileIdc = (EProfileIdc) atoi (argv[n++]);
594     } else if (!strcmp (pCommand, "-drec") && (n + 1 < argc)) {
595       unsigned int iLayer = atoi (argv[n++]);
596       const unsigned int iLen = (int) strlen (argv[n]);
597       if (iLen >= sizeof (sFileSet.sRecFileName[iLayer]))
598         return 1;
599       sFileSet.sRecFileName[iLayer][iLen] = '\0';
600       strncpy (sFileSet.sRecFileName[iLayer], argv[n++], iLen); // confirmed_safe_unsafe_usage
601     } else if (!strcmp (pCommand, "-dw") && (n + 1 < argc)) {
602       unsigned int iLayer = atoi (argv[n++]);
603       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
604       pDLayer->iVideoWidth = atoi (argv[n++]);
605     }
606 
607     else if (!strcmp (pCommand, "-dh") && (n + 1 < argc)) {
608       unsigned int iLayer = atoi (argv[n++]);
609       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
610       pDLayer->iVideoHeight = atoi (argv[n++]);
611     }
612 
613     else if (!strcmp (pCommand, "-frout") && (n + 1 < argc)) {
614       unsigned int iLayer = atoi (argv[n++]);
615       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
616       pDLayer->fFrameRate = (float)atof (argv[n++]);
617     }
618 
619     else if (!strcmp (pCommand, "-lqp") && (n + 1 < argc)) {
620       unsigned int iLayer = atoi (argv[n++]);
621       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
622       pDLayer->iDLayerQp = sLayerCtx[iLayer].iDLayerQp =  atoi (argv[n++]);
623     }
624     //sLayerCtx[iLayer].num_quality_layers = pDLayer->num_quality_layers = 1;
625 
626     else if (!strcmp (pCommand, "-ltarb") && (n + 1 < argc)) {
627       unsigned int iLayer = atoi (argv[n++]);
628       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
629       pDLayer->iSpatialBitrate = 1000 * atoi (argv[n++]);
630     }
631 
632     else if (!strcmp (pCommand, "-lmaxb") && (n + 1 < argc)) {
633       unsigned int iLayer = atoi (argv[n++]);
634       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
635       pDLayer->iMaxSpatialBitrate = 1000 * atoi (argv[n++]);
636     }
637 
638     else if (!strcmp (pCommand, "-slcmd") && (n + 1 < argc)) {
639       unsigned int iLayer = atoi (argv[n++]);
640       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
641 
642       switch (atoi (argv[n++])) {
643       case 0:
644         pDLayer->sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
645         break;
646       case 1:
647         pDLayer->sSliceArgument.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
648         break;
649       case 2:
650         pDLayer->sSliceArgument.uiSliceMode = SM_RASTER_SLICE;
651         break;
652       case 3:
653         pDLayer->sSliceArgument.uiSliceMode = SM_SIZELIMITED_SLICE;
654         break;
655       default:
656         pDLayer->sSliceArgument.uiSliceMode = SM_RESERVED;
657         break;
658       }
659     }
660 
661     else if (!strcmp (pCommand, "-slcsize") && (n + 1 < argc)) {
662       unsigned int iLayer = atoi (argv[n++]);
663       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
664       pDLayer->sSliceArgument.uiSliceSizeConstraint = atoi (argv[n++]);
665     }
666 
667     else if (!strcmp (pCommand, "-slcnum") && (n + 1 < argc)) {
668       unsigned int iLayer = atoi (argv[n++]);
669       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
670       pDLayer->sSliceArgument.uiSliceNum = atoi (argv[n++]);
671     } else if (!strcmp (pCommand, "-slcmbnum") && (n + 1 < argc)) {
672       unsigned int iLayer = atoi (argv[n++]);
673       SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer];
674       pDLayer->sSliceArgument.uiSliceMbNum[0] = atoi (argv[n++]);
675     }
676   }
677   return 0;
678 }
679 
680 
681 
FillSpecificParameters(SEncParamExt & sParam)682 int FillSpecificParameters (SEncParamExt& sParam) {
683   /* Test for temporal, spatial, SNR scalability */
684   sParam.iUsageType = CAMERA_VIDEO_REAL_TIME;
685   sParam.fMaxFrameRate  = 60.0f;                // input frame rate
686   sParam.iPicWidth      = 1280;                 // width of picture in samples
687   sParam.iPicHeight     = 720;                  // height of picture in samples
688   sParam.iTargetBitrate = 2500000;              // target bitrate desired
689   sParam.iMaxBitrate    = UNSPECIFIED_BIT_RATE;
690   sParam.iRCMode        = RC_QUALITY_MODE;      //  rc mode control
691   sParam.iTemporalLayerNum = 3;    // layer number at temporal level
692   sParam.iSpatialLayerNum  = 4;    // layer number at spatial level
693   sParam.bEnableDenoise    = 0;    // denoise control
694   sParam.bEnableBackgroundDetection = 1; // background detection control
695   sParam.bEnableAdaptiveQuant       = 1; // adaptive quantization control
696   sParam.bEnableFrameSkip           = 1; // frame skipping
697   sParam.bEnableLongTermReference   = 0; // long term reference control
698   sParam.iLtrMarkPeriod = 30;
699   sParam.uiIntraPeriod  = 320;           // period of Intra frame
700   sParam.eSpsPpsIdStrategy = INCREASING_ID;
701   sParam.bPrefixNalAddingCtrl = 0;
702   sParam.iComplexityMode = LOW_COMPLEXITY;
703   sParam.bSimulcastAVC         = false;
704   sParam.bFixRCOverShoot = true;
705   sParam.iIdrBitrateRatio = IDR_BITRATE_RATIO * 100;
706   int iIndexLayer = 0;
707   sParam.sSpatialLayers[iIndexLayer].uiProfileIdc       = PRO_BASELINE;
708   sParam.sSpatialLayers[iIndexLayer].iVideoWidth        = 160;
709   sParam.sSpatialLayers[iIndexLayer].iVideoHeight       = 90;
710   sParam.sSpatialLayers[iIndexLayer].fFrameRate         = 7.5f;
711   sParam.sSpatialLayers[iIndexLayer].iSpatialBitrate    = 64000;
712   sParam.sSpatialLayers[iIndexLayer].iMaxSpatialBitrate    = UNSPECIFIED_BIT_RATE;
713   sParam.sSpatialLayers[iIndexLayer].sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
714 
715   ++ iIndexLayer;
716   sParam.sSpatialLayers[iIndexLayer].uiProfileIdc       = PRO_SCALABLE_BASELINE;
717   sParam.sSpatialLayers[iIndexLayer].iVideoWidth        = 320;
718   sParam.sSpatialLayers[iIndexLayer].iVideoHeight       = 180;
719   sParam.sSpatialLayers[iIndexLayer].fFrameRate         = 15.0f;
720   sParam.sSpatialLayers[iIndexLayer].iSpatialBitrate    = 160000;
721   sParam.sSpatialLayers[iIndexLayer].iMaxSpatialBitrate    = UNSPECIFIED_BIT_RATE;
722   sParam.sSpatialLayers[iIndexLayer].sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
723 
724   ++ iIndexLayer;
725   sParam.sSpatialLayers[iIndexLayer].uiProfileIdc       = PRO_SCALABLE_BASELINE;
726   sParam.sSpatialLayers[iIndexLayer].iVideoWidth        = 640;
727   sParam.sSpatialLayers[iIndexLayer].iVideoHeight       = 360;
728   sParam.sSpatialLayers[iIndexLayer].fFrameRate         = 30.0f;
729   sParam.sSpatialLayers[iIndexLayer].iSpatialBitrate    = 512000;
730   sParam.sSpatialLayers[iIndexLayer].iMaxSpatialBitrate    = UNSPECIFIED_BIT_RATE;
731   sParam.sSpatialLayers[iIndexLayer].sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
732   sParam.sSpatialLayers[iIndexLayer].sSliceArgument.uiSliceNum = 1;
733 
734   ++ iIndexLayer;
735   sParam.sSpatialLayers[iIndexLayer].uiProfileIdc       = PRO_SCALABLE_BASELINE;
736   sParam.sSpatialLayers[iIndexLayer].iVideoWidth        = 1280;
737   sParam.sSpatialLayers[iIndexLayer].iVideoHeight       = 720;
738   sParam.sSpatialLayers[iIndexLayer].fFrameRate         = 30.0f;
739   sParam.sSpatialLayers[iIndexLayer].iSpatialBitrate    = 1500000;
740   sParam.sSpatialLayers[iIndexLayer].iMaxSpatialBitrate    = UNSPECIFIED_BIT_RATE;
741   sParam.sSpatialLayers[iIndexLayer].sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
742   sParam.sSpatialLayers[iIndexLayer].sSliceArgument.uiSliceNum = 1;
743 
744   float fMaxFr = sParam.sSpatialLayers[sParam.iSpatialLayerNum - 1].fFrameRate;
745   for (int32_t i = sParam.iSpatialLayerNum - 2; i >= 0; -- i) {
746     if (sParam.sSpatialLayers[i].fFrameRate > fMaxFr + EPSN)
747       fMaxFr = sParam.sSpatialLayers[i].fFrameRate;
748   }
749   sParam.fMaxFrameRate = fMaxFr;
750 
751   return 0;
752 }
753 
ProcessEncoding(ISVCEncoder * pPtrEnc,int argc,char ** argv,bool bConfigFile)754 int ProcessEncoding (ISVCEncoder* pPtrEnc, int argc, char** argv, bool bConfigFile) {
755   int iRet = 0;
756 
757   if (pPtrEnc == NULL)
758     return 1;
759 
760   SFrameBSInfo sFbi;
761   SEncParamExt sSvcParam;
762   int64_t iStart = 0, iTotal = 0;
763 
764   // Preparing encoding process
765   FILE* pFileYUV = NULL;
766   int32_t iActualFrameEncodedCount = 0;
767   int32_t iFrameIdx = 0;
768   int32_t iTotalFrameMax = -1;
769   uint8_t* pYUV = NULL;
770   SSourcePicture* pSrcPic = NULL;
771   uint32_t iSourceWidth, iSourceHeight, kiPicResSize;
772   // Inactive with sink with output file handler
773   FILE* pFpBs[4];
774   pFpBs[0] = pFpBs[1] = pFpBs[2] = pFpBs[3] = NULL;
775 #if defined(COMPARE_DATA)
776   //For getting the golden file handle
777   FILE* fpGolden = NULL;
778 #endif
779 #if defined ( STICK_STREAM_SIZE )
780   FILE* fTrackStream = fopen ("coding_size.stream", "wb");
781 #endif
782   SFilesSet fs;
783   // for configuration file
784   CReadConfig cRdCfg;
785   int iParsedNum = 1;
786 
787   memset (&sFbi, 0, sizeof (SFrameBSInfo));
788   pPtrEnc->GetDefaultParams (&sSvcParam);
789   fs.bEnableMultiBsFile = false;
790 
791   FillSpecificParameters (sSvcParam);
792   pSrcPic = new SSourcePicture;
793   if (pSrcPic == NULL) {
794     iRet = 1;
795     goto INSIDE_MEM_FREE;
796   }
797   //fill default pSrcPic
798   pSrcPic->iColorFormat = videoFormatI420;
799   pSrcPic->uiTimeStamp = 0;
800 
801   // if configure file exit, reading configure file firstly
802   if (bConfigFile) {
803     iParsedNum = 2;
804     cRdCfg.Openf (argv[1]);
805     if (!cRdCfg.ExistFile()) {
806       fprintf (stderr, "Specified file: %s not exist, maybe invalid path or parameter settting.\n",
807                cRdCfg.GetFileName().c_str());
808       iRet = 1;
809       goto INSIDE_MEM_FREE;
810     }
811     iRet = ParseConfig (cRdCfg, pSrcPic, sSvcParam, fs);
812     if (iRet) {
813       fprintf (stderr, "parse svc parameter config file failed.\n");
814       iRet = 1;
815       goto INSIDE_MEM_FREE;
816     }
817   }
818   if (ParseCommandLine (argc - iParsedNum, argv + iParsedNum, pSrcPic, sSvcParam, fs) != 0) {
819     printf ("parse pCommand line failed\n");
820     iRet = 1;
821     goto INSIDE_MEM_FREE;
822   }
823   pPtrEnc->SetOption (ENCODER_OPTION_TRACE_LEVEL, &g_LevelSetting);
824   //finish reading the configurations
825   iSourceWidth = pSrcPic->iPicWidth;
826   iSourceHeight = pSrcPic->iPicHeight;
827   kiPicResSize = iSourceWidth * iSourceHeight * 3 >> 1;
828 
829   pYUV = new uint8_t [kiPicResSize];
830   if (pYUV == NULL) {
831     iRet = 1;
832     goto INSIDE_MEM_FREE;
833   }
834 
835   //update pSrcPic
836   pSrcPic->iStride[0] = iSourceWidth;
837   pSrcPic->iStride[1] = pSrcPic->iStride[2] = pSrcPic->iStride[0] >> 1;
838 
839   pSrcPic->pData[0] = pYUV;
840   pSrcPic->pData[1] = pSrcPic->pData[0] + (iSourceWidth * iSourceHeight);
841   pSrcPic->pData[2] = pSrcPic->pData[1] + (iSourceWidth * iSourceHeight >> 2);
842 
843   //update sSvcParam
844   sSvcParam.iPicWidth = 0;
845   sSvcParam.iPicHeight = 0;
846   for (int iLayer = 0; iLayer < sSvcParam.iSpatialLayerNum; iLayer++) {
847     SSpatialLayerConfig* pDLayer = &sSvcParam.sSpatialLayers[iLayer];
848     sSvcParam.iPicWidth = WELS_MAX (sSvcParam.iPicWidth, pDLayer->iVideoWidth);
849     sSvcParam.iPicHeight = WELS_MAX (sSvcParam.iPicHeight, pDLayer->iVideoHeight);
850   }
851   //if target output resolution is not set, use the source size
852   sSvcParam.iPicWidth = (!sSvcParam.iPicWidth) ? iSourceWidth : sSvcParam.iPicWidth;
853   sSvcParam.iPicHeight = (!sSvcParam.iPicHeight) ? iSourceHeight : sSvcParam.iPicHeight;
854 
855   iTotalFrameMax = (int32_t)fs.uiFrameToBeCoded;
856   //  sSvcParam.bSimulcastAVC = true;
857   if (cmResultSuccess != pPtrEnc->InitializeExt (&sSvcParam)) { // SVC encoder initialization
858     fprintf (stderr, "SVC encoder Initialize failed\n");
859     iRet = 1;
860     goto INSIDE_MEM_FREE;
861   }
862   for (int iLayer = 0; iLayer < MAX_DEPENDENCY_LAYER; iLayer++) {
863     if (fs.sRecFileName[iLayer][0] != 0) {
864       SDumpLayer sDumpLayer;
865       sDumpLayer.iLayer = iLayer;
866       sDumpLayer.pFileName = fs.sRecFileName[iLayer];
867       if (cmResultSuccess != pPtrEnc->SetOption (ENCODER_OPTION_DUMP_FILE, &sDumpLayer)) {
868         fprintf (stderr, "SetOption ENCODER_OPTION_DUMP_FILE failed!\n");
869         iRet = 1;
870         goto INSIDE_MEM_FREE;
871       }
872     }
873   }
874   // Inactive with sink with output file handler
875   if (fs.strBsFile.length() > 0) {
876     bool bFileOpenErr = false;
877     if (sSvcParam.iSpatialLayerNum == 1 || fs.bEnableMultiBsFile == false) {
878       pFpBs[0] = fopen (fs.strBsFile.c_str(), "wb");
879       bFileOpenErr = (pFpBs[0] == NULL);
880     } else { //enable multi bs file writing
881       string filename_layer;
882       string add_info[4] = {"_layer0", "_layer1", "_layer2", "_layer3"};
883       string::size_type found = fs.strBsFile.find_last_of ('.');
884       for (int i = 0; i < sSvcParam.iSpatialLayerNum; ++i) {
885         filename_layer = fs.strBsFile.insert (found, add_info[i]);
886         pFpBs[i] = fopen (filename_layer.c_str(), "wb");
887         fs.strBsFile = filename_layer.erase (found, 7);
888         bFileOpenErr |= (pFpBs[i] == NULL);
889       }
890     }
891     if (bFileOpenErr) {
892       fprintf (stderr, "Can not open file (%s) to write bitstream!\n", fs.strBsFile.c_str());
893       iRet = 1;
894       goto INSIDE_MEM_FREE;
895     }
896   } else {
897     fprintf (stderr, "Don't set the proper bitstream filename!\n");
898     iRet = 1;
899     goto INSIDE_MEM_FREE;
900   }
901 
902 #if defined(COMPARE_DATA)
903   //For getting the golden file handle
904   if ((fpGolden = fopen (argv[3], "rb")) == NULL) {
905     fprintf (stderr, "Unable to open golden sequence file, check corresponding path!\n");
906     iRet = 1;
907     goto INSIDE_MEM_FREE;
908   }
909 #endif
910 
911   pFileYUV = fopen (fs.strSeqFile.c_str(), "rb");
912   if (pFileYUV != NULL) {
913 #if defined(_WIN32) || defined(_WIN64)
914 #if _MSC_VER >= 1400
915     if (!_fseeki64 (pFileYUV, 0, SEEK_END)) {
916       int64_t i_size = _ftelli64 (pFileYUV);
917       _fseeki64 (pFileYUV, 0, SEEK_SET);
918       iTotalFrameMax = WELS_MAX ((int32_t) (i_size / kiPicResSize), iTotalFrameMax);
919     }
920 #else
921     if (!fseek (pFileYUV, 0, SEEK_END)) {
922       int64_t i_size = ftell (pFileYUV);
923       fseek (pFileYUV, 0, SEEK_SET);
924       iTotalFrameMax = WELS_MAX ((int32_t) (i_size / kiPicResSize), iTotalFrameMax);
925     }
926 #endif
927 #else
928     if (!fseeko (pFileYUV, 0, SEEK_END)) {
929       int64_t i_size = ftello (pFileYUV);
930       fseeko (pFileYUV, 0, SEEK_SET);
931       iTotalFrameMax = WELS_MAX ((int32_t) (i_size / kiPicResSize), iTotalFrameMax);
932     }
933 #endif
934   } else {
935     fprintf (stderr, "Unable to open source sequence file (%s), check corresponding path!\n",
936              fs.strSeqFile.c_str());
937     iRet = 1;
938     goto INSIDE_MEM_FREE;
939   }
940 
941   iFrameIdx = 0;
942   while (iFrameIdx < iTotalFrameMax && (((int32_t)fs.uiFrameToBeCoded <= 0)
943                                         || (iFrameIdx < (int32_t)fs.uiFrameToBeCoded))) {
944 
945 #ifdef ONLY_ENC_FRAMES_NUM
946     // Only encoded some limited frames here
947     if (iActualFrameEncodedCount >= ONLY_ENC_FRAMES_NUM) {
948       break;
949     }
950 #endif//ONLY_ENC_FRAMES_NUM
951     bool bCanBeRead = false;
952     bCanBeRead = (fread (pYUV, 1, kiPicResSize, pFileYUV) == kiPicResSize);
953 
954     if (!bCanBeRead)
955       break;
956     // To encoder this frame
957     iStart = WelsTime();
958     pSrcPic->uiTimeStamp = WELS_ROUND (iFrameIdx * (1000 / sSvcParam.fMaxFrameRate));
959     int iEncFrames = pPtrEnc->EncodeFrame (pSrcPic, &sFbi);
960     iTotal += WelsTime() - iStart;
961     ++ iFrameIdx;
962     if (videoFrameTypeSkip == sFbi.eFrameType) {
963       continue;
964     }
965 
966     if (iEncFrames == cmResultSuccess) {
967       int iLayer = 0;
968 #if defined (STICK_STREAM_SIZE)
969       int iFrameSize = 0;
970 #endif//STICK_STREAM_SIZE
971       while (iLayer < sFbi.iLayerNum) {
972         SLayerBSInfo* pLayerBsInfo = &sFbi.sLayerInfo[iLayer];
973         if (pLayerBsInfo != NULL) {
974           int iLayerSize = 0;
975           int iNalIdx = pLayerBsInfo->iNalCount - 1;
976           do {
977             iLayerSize += pLayerBsInfo->pNalLengthInByte[iNalIdx];
978             -- iNalIdx;
979           } while (iNalIdx >= 0);
980 #if defined(COMPARE_DATA)
981           //Comparing the result of encoder with golden pData
982           {
983             unsigned char* pUCArry = new unsigned char [iLayerSize];
984 
985             fread (pUCArry, 1, iLayerSize, fpGolden);
986 
987             for (int w = 0; w < iLayerSize; w++) {
988               if (pUCArry[w] != pLayerBsInfo->pBsBuf[w]) {
989                 fprintf (stderr, "error @frame%d/layer%d/byte%d!!!!!!!!!!!!!!!!!!!!!!!!\n", iFrameIdx, iLayer, w);
990                 //fprintf(stderr, "%x - %x\n", pUCArry[w], pLayerBsInfo->pBsBuf[w]);
991                 break;
992               }
993             }
994             fprintf (stderr, "frame%d/layer%d comparation completed!\n", iFrameIdx, iLayer);
995 
996             delete [] pUCArry;
997           }
998 #endif
999           if (sSvcParam.iSpatialLayerNum == 1 || fs.bEnableMultiBsFile == false)
1000             fwrite (pLayerBsInfo->pBsBuf, 1, iLayerSize, pFpBs[0]); // write pure bit stream into file
1001           else { //multi bs file write
1002             if (pLayerBsInfo->uiSpatialId == 0) {
1003               unsigned char five_bits = pLayerBsInfo->pBsBuf[4] & 0x1f;
1004               if ((five_bits == 0x07) || (five_bits == 0x08)) { //sps or pps
1005                 for (int i = 0; i < sSvcParam.iSpatialLayerNum; ++i) {
1006                   fwrite (pLayerBsInfo->pBsBuf, 1, iLayerSize, pFpBs[i]);
1007                 }
1008               } else {
1009                 fwrite (pLayerBsInfo->pBsBuf, 1, iLayerSize, pFpBs[0]);
1010               }
1011             } else {
1012               fwrite (pLayerBsInfo->pBsBuf, 1, iLayerSize, pFpBs[pLayerBsInfo->uiSpatialId]);
1013             }
1014           }
1015 #if defined (STICK_STREAM_SIZE)
1016           iFrameSize += iLayerSize;
1017 #endif//STICK_STREAM_SIZE
1018         }
1019         ++ iLayer;
1020       }
1021 #if defined (STICK_STREAM_SIZE)
1022       if (fTrackStream) {
1023         fwrite (&iFrameSize, 1, sizeof (int), fTrackStream);
1024       }
1025 #endif//STICK_STREAM_SIZE
1026       ++ iActualFrameEncodedCount; // excluding skipped frame time
1027     } else {
1028       fprintf (stderr, "EncodeFrame(), ret: %d, frame index: %d.\n", iEncFrames, iFrameIdx);
1029     }
1030 
1031   }
1032 
1033   if (iActualFrameEncodedCount > 0) {
1034     double dElapsed = iTotal / 1e6;
1035     printf ("Width:\t\t%d\nHeight:\t\t%d\nFrames:\t\t%d\nencode time:\t%f sec\nFPS:\t\t%f fps\n",
1036             sSvcParam.iPicWidth, sSvcParam.iPicHeight,
1037             iActualFrameEncodedCount, dElapsed, (iActualFrameEncodedCount * 1.0) / dElapsed);
1038 #if defined (WINDOWS_PHONE)
1039     g_fFPS = (iActualFrameEncodedCount * 1.0f) / (float) dElapsed;
1040     g_dEncoderTime = dElapsed;
1041     g_iEncodedFrame = iActualFrameEncodedCount;
1042 #endif
1043   }
1044 INSIDE_MEM_FREE:
1045   for (int i = 0; i < sSvcParam.iSpatialLayerNum; ++i) {
1046     if (pFpBs[i]) {
1047       fclose (pFpBs[i]);
1048       pFpBs[i] = NULL;
1049     }
1050   }
1051 #if defined (STICK_STREAM_SIZE)
1052   if (fTrackStream) {
1053     fclose (fTrackStream);
1054     fTrackStream = NULL;
1055   }
1056 #endif
1057 #if defined (COMPARE_DATA)
1058   if (fpGolden) {
1059     fclose (fpGolden);
1060     fpGolden = NULL;
1061   }
1062 #endif
1063   // Destruction memory introduced in this routine
1064   if (pFileYUV != NULL) {
1065     fclose (pFileYUV);
1066     pFileYUV = NULL;
1067   }
1068   if (pYUV) {
1069     delete[] pYUV;
1070     pYUV = NULL;
1071   }
1072   if (pSrcPic) {
1073     delete pSrcPic;
1074     pSrcPic = NULL;
1075   }
1076   return iRet;
1077 }
1078 
1079 //  Merge from Heifei's Wonder.  Lock process to a single core
LockToSingleCore()1080 void LockToSingleCore() {
1081 #ifdef HAVE_PROCESS_AFFINITY
1082   //for 2005 compiler, change "DWORD" to "DWORD_PTR"
1083   ULONG_PTR ProcessAffMask = 0, SystemAffMask = 0;
1084   HANDLE hProcess = GetCurrentProcess();
1085 
1086   GetProcessAffinityMask (hProcess, &ProcessAffMask, &SystemAffMask);
1087   if (ProcessAffMask > 1) {
1088     // more than one CPU core available. Fix to only one:
1089     if (ProcessAffMask & 2) {
1090       ProcessAffMask = 2;
1091     } else {
1092       ProcessAffMask = 1;
1093     }
1094     // Lock process to a single CPU core
1095     SetProcessAffinityMask (hProcess, ProcessAffMask);
1096   }
1097 
1098   // set high priority to avoid interrupts during test
1099   SetPriorityClass (hProcess, REALTIME_PRIORITY_CLASS);
1100 #endif
1101   return ;
1102 }
1103 
CreateSVCEncHandle(ISVCEncoder ** ppEncoder)1104 int32_t CreateSVCEncHandle (ISVCEncoder** ppEncoder) {
1105   int32_t ret = 0;
1106   ret = WelsCreateSVCEncoder (ppEncoder);
1107   return ret;
1108 }
1109 
DestroySVCEncHandle(ISVCEncoder * pEncoder)1110 void DestroySVCEncHandle (ISVCEncoder* pEncoder) {
1111   if (pEncoder) {
1112     WelsDestroySVCEncoder (pEncoder);
1113 
1114   }
1115 }
1116 
1117 /****************************************************************************
1118  * main:
1119  ****************************************************************************/
1120 #if defined(ANDROID_NDK) || defined(APPLE_IOS) || defined (WINDOWS_PHONE)
EncMain(int argc,char ** argv)1121 extern "C" int EncMain (int argc, char** argv)
1122 #else
1123 int main (int argc, char** argv)
1124 #endif
1125 {
1126   ISVCEncoder* pSVCEncoder = NULL;
1127   int iRet = 0;
1128 
1129 #ifdef _MSC_VER
1130   _setmode (_fileno (stdin), _O_BINARY);  /* thanks to Marcoss Morais <morais at dee.ufcg.edu.br> */
1131   _setmode (_fileno (stdout), _O_BINARY);
1132 
1133   // remove the LOCK_TO_SINGLE_CORE micro, user need to enable it with manual
1134   // LockToSingleCore();
1135 #endif
1136 
1137   /* Control-C handler */
1138   signal (SIGINT, SigIntHandler);
1139 
1140   iRet = CreateSVCEncHandle (&pSVCEncoder);
1141   if (iRet) {
1142     cout << "WelsCreateSVCEncoder() failed!!" << endl;
1143     goto exit;
1144   }
1145 
1146   if (argc < 2) {
1147     goto exit;
1148   } else {
1149     if (!strstr (argv[1], ".cfg")) { // check configuration type (like .cfg?)
1150       if (argc > 2) {
1151         iRet = ProcessEncoding (pSVCEncoder, argc, argv, false);
1152         if (iRet != 0)
1153           goto exit;
1154       } else if (argc == 2 && ! strcmp (argv[1], "-h"))
1155         PrintHelp();
1156       else {
1157         cout << "You specified pCommand is invalid!!" << endl;
1158         goto exit;
1159       }
1160     } else {
1161       iRet = ProcessEncoding (pSVCEncoder, argc, argv, true);
1162       if (iRet > 0)
1163         goto exit;
1164     }
1165   }
1166 
1167   DestroySVCEncHandle (pSVCEncoder);
1168   return 0;
1169 
1170 exit:
1171   DestroySVCEncHandle (pSVCEncoder);
1172   PrintHelp();
1173   return 1;
1174 }
1175