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