1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "command_parser.h"
17 #include <cinttypes>
18 #include <getopt.h>
19 #include <iostream>
20 #include <sstream>
21 #include "hcodec_log.h"
22 
23 namespace OHOS::MediaAVCodec {
24 using namespace std;
25 
26 enum ShortOption {
27     OPT_UNKONWN = 0,
28     OPT_HELP,
29     OPT_INPUT = 'i',
30     OPT_WIDTH = 'w',
31     OPT_HEIGHT = 'h',
32     OPT_API_TYPE = UINT8_MAX + 1,
33     OPT_IS_ENCODER,
34     OPT_IS_BUFFER_MODE,
35     OPT_REPEAT_CNT,
36     OPT_MAX_READ_CNT,
37     OPT_PROTOCOL,
38     OPT_PIXEL_FMT,
39     OPT_FRAME_RATE,
40     OPT_TIME_OUT,
41     OPT_IS_HIGH_PERF_MODE,
42     OPT_SET_PARAMETER,
43     OPT_SET_PER_FRAME,
44     OPT_SET_RESOURCE,
45     // encoder only
46     OPT_MOCK_FRAME_CNT,
47     OPT_COLOR_RANGE,
48     OPT_COLOR_PRIMARY,
49     OPT_COLOR_TRANSFER,
50     OPT_COLOR_MATRIX,
51     OPT_I_FRAME_INTERVAL,
52     OPT_PROFILE,
53     OPT_BITRATE_MODE,
54     OPT_BITRATE,
55     OPT_QUALITY,
56     OPT_QP_RANGE,
57     OPT_LTR_FRAME_COUNT,
58     OPT_REPEAT_AFTER,
59     OPT_REPEAT_MAX_CNT,
60     OPT_LAYER_COUNT,
61     OPT_WATERMARK,
62     OPT_ENABLE_PARAMS_FEEDBACK,
63     // decoder only
64     OPT_RENDER,
65     OPT_DEC_THEN_ENC,
66     OPT_ROTATION,
67     OPT_FLUSH_CNT,
68     OPT_SCALE_MODE,
69 };
70 
71 static struct option g_longOptions[] = {
72     {"help",            no_argument,        nullptr, OPT_HELP},
73     {"in",              required_argument,  nullptr, OPT_INPUT},
74     {"width",           required_argument,  nullptr, OPT_WIDTH},
75     {"height",          required_argument,  nullptr, OPT_HEIGHT},
76     {"apiType",         required_argument,  nullptr, OPT_API_TYPE},
77     {"isEncoder",       required_argument,  nullptr, OPT_IS_ENCODER},
78     {"isBufferMode",    required_argument,  nullptr, OPT_IS_BUFFER_MODE},
79     {"repeatCnt",       required_argument,  nullptr, OPT_REPEAT_CNT},
80     {"maxReadFrameCnt", required_argument,  nullptr, OPT_MAX_READ_CNT},
81     {"protocol",        required_argument,  nullptr, OPT_PROTOCOL},
82     {"pixelFmt",        required_argument,  nullptr, OPT_PIXEL_FMT},
83     {"frameRate",       required_argument,  nullptr, OPT_FRAME_RATE},
84     {"timeout",         required_argument,  nullptr, OPT_TIME_OUT},
85     {"isHighPerfMode",  required_argument,  nullptr, OPT_IS_HIGH_PERF_MODE},
86     {"setParameter",    required_argument,  nullptr, OPT_SET_PARAMETER},
87     {"setPerFrame",     required_argument,  nullptr, OPT_SET_PER_FRAME},
88     {"setResource",     required_argument,  nullptr, OPT_SET_RESOURCE},
89     // encoder only
90     {"mockFrameCnt",    required_argument,  nullptr, OPT_MOCK_FRAME_CNT},
91     {"colorRange",      required_argument,  nullptr, OPT_COLOR_RANGE},
92     {"colorPrimary",    required_argument,  nullptr, OPT_COLOR_PRIMARY},
93     {"colorTransfer",   required_argument,  nullptr, OPT_COLOR_TRANSFER},
94     {"colorMatrix",     required_argument,  nullptr, OPT_COLOR_MATRIX},
95     {"iFrameInterval",  required_argument,  nullptr, OPT_I_FRAME_INTERVAL},
96     {"profile",         required_argument,  nullptr, OPT_PROFILE},
97     {"bitRateMode",     required_argument,  nullptr, OPT_BITRATE_MODE},
98     {"bitRate",         required_argument,  nullptr, OPT_BITRATE},
99     {"quality",         required_argument,  nullptr, OPT_QUALITY},
100     {"qpRange",         required_argument,  nullptr, OPT_QP_RANGE},
101     {"ltrFrameCount",   required_argument,  nullptr, OPT_LTR_FRAME_COUNT},
102     {"repeatAfter",     required_argument,  nullptr, OPT_REPEAT_AFTER},
103     {"repeatMaxCnt",    required_argument,  nullptr, OPT_REPEAT_MAX_CNT},
104     {"layerCnt",        required_argument,  nullptr, OPT_LAYER_COUNT},
105     {"waterMark",       required_argument,  nullptr, OPT_WATERMARK},
106     {"paramsFeedback",  required_argument,  nullptr, OPT_ENABLE_PARAMS_FEEDBACK},
107     // decoder only
108     {"rotation",        required_argument,  nullptr, OPT_ROTATION},
109     {"render",          required_argument,  nullptr, OPT_RENDER},
110     {"decThenEnc",      required_argument,  nullptr, OPT_DEC_THEN_ENC},
111     {"flushCnt",        required_argument,  nullptr, OPT_FLUSH_CNT},
112     {"scaleMode",       required_argument,  nullptr, OPT_SCALE_MODE},
113     {nullptr,           no_argument,        nullptr, OPT_UNKONWN},
114 };
115 
ShowUsage()116 void ShowUsage()
117 {
118     std::cout << "HCodec Test Options:" << std::endl;
119     std::cout << " --help               help info." << std::endl;
120     std::cout << " -i, --in             file name for input file." << std::endl;
121     std::cout << " -w, --width          video width." << std::endl;
122     std::cout << " -h, --height         video height." << std::endl;
123     std::cout << " --apiType            0: codecbase, 1: new capi, 2: old capi." << std::endl;
124     std::cout << " --isEncoder          1 is test encoder, 0 is test decoder" << std::endl;
125     std::cout << " --isBufferMode       0 is surface mode, 1 is buffer mode." << std::endl;
126     std::cout << " --repeatCnt          repeat test, default is 1" << std::endl;
127     std::cout << " --maxReadFrameCnt    read up to frame count from input file" << std::endl;
128     std::cout << " --protocol           video protocol. 0 is H264, 1 is H265" << std::endl;
129     std::cout << " --pixelFmt           video pixel fmt. 1 is I420, 2 is NV12, 3 is NV21, 5 is RGBA" << std::endl;
130     std::cout << " --frameRate          video frame rate." << std::endl;
131     std::cout << " --timeout            thread timeout(ms). -1 means wait forever" << std::endl;
132     std::cout << " --isHighPerfMode     0 is normal mode, 1 is high perf mode" << std::endl;
133     std::cout << " --setParameter       eg. 11:frameRate,60 or 24:requestIdr,1" << std::endl;
134     std::cout << " --setPerFrame        eg. 11:ltr,1,0,30 or 24:qp,3,40 or 25:discard,1 or 30:ebr,16,30,25,0"
135               << std::endl;
136     std::cout << " --setResource        eg. 11:/data/test/a.yuv,1280,720,2" << std::endl;
137     std::cout << " [encoder only]" << std::endl;
138     std::cout << " --mockFrameCnt       when read up to maxReadFrameCnt, just send old frames" << std::endl;
139     std::cout << " --colorRange         color range. 1 is full range, 0 is limited range." << std::endl;
140     std::cout << " --colorPrimary       color primary. see H.273 standard." << std::endl;
141     std::cout << " --colorTransfer      color transfer characteristic. see H.273 standard." << std::endl;
142     std::cout << " --colorMatrix        color matrix coefficient. see H.273 standard." << std::endl;
143     std::cout << " --iFrameInterval     <0 means only one I frame, =0 means all intra" << std::endl;
144     std::cout << "                      >0 means I frame interval in milliseconds" << std::endl;
145     std::cout << " --profile            video profile, for 264: 0(baseline), 1(constrained baseline), " << std::endl;
146     std::cout << "                      2(constrained high), 3(extended), 4(high), 8(main)" << std::endl;
147     std::cout << "                      for 265: 0(main), 1(main 10)" << std::endl;
148     std::cout << " --bitRateMode        bit rate mode for encoder. 0(CBR), 1(VBR), 2(CQ)" << std::endl;
149     std::cout << " --bitRate            target encode bit rate (bps)" << std::endl;
150     std::cout << " --quality            target encode quality" << std::endl;
151     std::cout << " --qpRange            target encode qpRange, eg. 13,42" << std::endl;
152     std::cout << " --ltrFrameCount      The number of long-term reference frames." << std::endl;
153     std::cout << " --repeatAfter        repeat previous frame after target ms" << std::endl;
154     std::cout << " --repeatMaxCnt       repeat previous frame up to target times" << std::endl;
155     std::cout << " --layerCnt           target encode layerCnt, H264:2, H265:2 and 3" << std::endl;
156     std::cout << " --waterMark          eg. /data/test/a.rgba,1280,720,2:16,16,1280,720" << std::endl;
157     std::cout << " [decoder only]" << std::endl;
158     std::cout << " --rotation           rotation angle after decode, eg. 0/90/180/270" << std::endl;
159     std::cout << " --render             0 means don't render, 1 means render to window" << std::endl;
160     std::cout << " --paramsFeedback     0 means don't feedback, 1 means feedback" << std::endl;
161     std::cout << " --decThenEnc         do surface encode after surface decode" << std::endl;
162     std::cout << " --flushCnt           total flush count during decoding" << std::endl;
163     std::cout << " --scaleMode          target scale mode after decode, see @OH_ScalingMode" << std::endl;
164 }
165 
Parse(int argc,char * argv[])166 CommandOpt Parse(int argc, char *argv[])
167 {
168     CommandOpt opt;
169     int c;
170     while ((c = getopt_long(argc, argv, "i:w:h:", g_longOptions, nullptr)) != -1) {
171         switch (c) {
172             case OPT_HELP:
173                 ShowUsage();
174                 break;
175             case OPT_INPUT:
176                 opt.inputFile = string(optarg);
177                 break;
178             case OPT_WIDTH:
179                 opt.dispW = stol(optarg);
180                 break;
181             case OPT_HEIGHT:
182                 opt.dispH = stol(optarg);
183                 break;
184             case OPT_API_TYPE:
185                 opt.apiType = static_cast<ApiType>(stol(optarg));
186                 break;
187             case OPT_IS_ENCODER:
188                 opt.isEncoder = stol(optarg);
189                 break;
190             case OPT_IS_BUFFER_MODE:
191                 opt.isBufferMode = stol(optarg);
192                 break;
193             case OPT_REPEAT_CNT:
194                 opt.repeatCnt = stol(optarg);
195                 break;
196             case OPT_MAX_READ_CNT:
197                 opt.maxReadFrameCnt = stol(optarg);
198                 break;
199             case OPT_PROTOCOL:
200                 opt.protocol = static_cast<CodeType>(stol(optarg));
201                 break;
202             case OPT_PIXEL_FMT:
203                 opt.pixFmt = static_cast<VideoPixelFormat>(stol(optarg));
204                 break;
205             case OPT_FRAME_RATE:
206                 opt.frameRate = stol(optarg);
207                 break;
208             case OPT_TIME_OUT:
209                 opt.timeout = stol(optarg);
210                 break;
211             case OPT_IS_HIGH_PERF_MODE:
212                 opt.isHighPerfMode = stol(optarg);
213                 break;
214             case OPT_SET_PARAMETER:
215                 opt.ParseParamFromCmdLine(SET_PARAM, optarg);
216                 break;
217             case OPT_SET_PER_FRAME:
218                 opt.ParseParamFromCmdLine(PER_FRAME_PARAM, optarg);
219                 break;
220             case OPT_SET_RESOURCE:
221                 opt.ParseParamFromCmdLine(RESOURCE_PARAM, optarg);
222                 break;
223             // encoder only
224             case OPT_MOCK_FRAME_CNT:
225                 opt.mockFrameCnt = stol(optarg);
226                 break;
227             case OPT_COLOR_RANGE:
228                 opt.rangeFlag = stol(optarg);
229                 break;
230             case OPT_COLOR_PRIMARY:
231                 opt.primary = static_cast<ColorPrimary>(stol(optarg));
232                 break;
233             case OPT_COLOR_TRANSFER:
234                 opt.transfer = static_cast<TransferCharacteristic>(stol(optarg));
235                 break;
236             case OPT_COLOR_MATRIX:
237                 opt.matrix = static_cast<MatrixCoefficient>(stol(optarg));
238                 break;
239             case OPT_I_FRAME_INTERVAL:
240                 opt.iFrameInterval = stol(optarg);
241                 break;
242             case OPT_PROFILE:
243                 opt.profile = stol(optarg);
244                 break;
245             case OPT_BITRATE_MODE:
246                 opt.rateMode = static_cast<VideoEncodeBitrateMode>(stol(optarg));
247                 break;
248             case OPT_BITRATE:
249                 opt.bitRate = stol(optarg);
250                 break;
251             case OPT_QUALITY:
252                 opt.quality = stol(optarg);
253                 break;
254             case OPT_QP_RANGE: {
255                 istringstream is(optarg);
256                 QPRange range;
257                 char tmp;
258                 is >> range.qpMin >> tmp >> range.qpMax;
259                 opt.qpRange = range;
260                 break;
261             }
262             case OPT_LTR_FRAME_COUNT:
263                 opt.ltrFrameCount = stol(optarg);
264                 break;
265             case OPT_REPEAT_AFTER:
266                 opt.repeatAfter = stol(optarg);
267                 break;
268             case OPT_REPEAT_MAX_CNT:
269                 opt.repeatMaxCnt = stol(optarg);
270                 break;
271             case OPT_LAYER_COUNT:
272                 opt.layerCnt = stol(optarg);
273                 break;
274             case OPT_WATERMARK:
275                 opt.ParseWaterMark(optarg);
276                 break;
277             case OPT_ENABLE_PARAMS_FEEDBACK:
278                 opt.paramsFeedback = stol(optarg);
279                 break;
280             // decoder only
281             case OPT_RENDER:
282                 opt.render = stol(optarg);
283                 break;
284             case OPT_DEC_THEN_ENC:
285                 opt.decThenEnc = stol(optarg);
286                 break;
287             case OPT_ROTATION:
288                 opt.rotation = static_cast<VideoRotation>(stol(optarg));
289                 break;
290             case OPT_FLUSH_CNT:
291                 opt.flushCnt = stol(optarg);
292                 break;
293             case OPT_SCALE_MODE:
294                 opt.scaleMode = static_cast<OH_ScalingMode>(stol(optarg));
295                 break;
296             default:
297                 break;
298         }
299     }
300     return opt;
301 }
302 
ParseParamFromCmdLine(ParamType paramType,const char * cmd)303 void CommandOpt::ParseParamFromCmdLine(ParamType paramType, const char *cmd)
304 {
305     string s(cmd);
306     auto pos = s.find(':');
307     if (pos == string::npos) {
308         return;
309     }
310     auto frameNo = stoul(s.substr(0, pos));
311     string paramList = s.substr(pos + 1);
312     switch (paramType) {
313         case SET_PARAM: {
314             ParseSetParameter(frameNo, paramList);
315             break;
316         }
317         case PER_FRAME_PARAM: {
318             ParsePerFrameParam(frameNo, paramList);
319             break;
320         }
321         case RESOURCE_PARAM: {
322             ResourceParams dst;
323             ParseResourceParam(paramList, dst);
324             resourceParamsMap[frameNo] = dst;
325             break;
326         }
327         default: {
328             break;
329         }
330     }
331 }
332 
ParseSetParameter(uint32_t frameNo,const string & s)333 void CommandOpt::ParseSetParameter(uint32_t frameNo, const string &s)
334 {
335     auto pos = s.find(',');
336     if (pos == string::npos) {
337         return;
338     }
339     char c;
340     string key = s.substr(0, pos);
341     istringstream value(s.substr(pos + 1));
342     if (key == "requestIdr") {
343         bool requestIdr;
344         value >> requestIdr;
345         setParameterParamsMap[frameNo].requestIdr = requestIdr;
346     }
347     if (key == "bitRate") {
348         uint32_t bitRate;
349         value >> bitRate;
350         setParameterParamsMap[frameNo].bitRate = bitRate;
351     }
352     if (key == "frameRate") {
353         double fr;
354         value >> fr;
355         setParameterParamsMap[frameNo].frameRate = fr;
356     }
357     if (key == "qpRange") {
358         QPRange qpRange;
359         value >> qpRange.qpMin >> c >> qpRange.qpMax;
360         setParameterParamsMap[frameNo].qpRange = qpRange;
361     }
362 }
363 
ParsePerFrameParam(uint32_t frameNo,const string & s)364 void CommandOpt::ParsePerFrameParam(uint32_t frameNo, const string &s)
365 {
366     auto pos = s.find(',');
367     if (pos == string::npos) {
368         return;
369     }
370     string key = s.substr(0, pos);
371     istringstream value(s.substr(pos + 1));
372     char c;
373     if (key == "requestIdr") {
374         bool requestIdr;
375         value >> requestIdr;
376         perFrameParamsMap[frameNo].requestIdr = requestIdr;
377     }
378     if (key == "qpRange") {
379         QPRange qpRange;
380         value >> qpRange.qpMin >> c >> qpRange.qpMax;
381         perFrameParamsMap[frameNo].qpRange = qpRange;
382     }
383     if (key == "ltr") {
384         LTRParam ltr;
385         value >> ltr.markAsLTR >> c >> ltr.useLTR >> c >> ltr.useLTRPoc;
386         perFrameParamsMap[frameNo].ltrParam = ltr;
387     }
388     if (key == "discard") {
389         bool discard;
390         value >> discard;
391         perFrameParamsMap[frameNo].discard = discard;
392     }
393     if (key == "ebr") {
394         EBRParam ebrParam;
395         value >> ebrParam.minQp >> c >> ebrParam.maxQp >> c >> ebrParam.startQp >> c >> ebrParam.isSkip;
396         perFrameParamsMap[frameNo].ebrParam = ebrParam;
397     }
398 }
399 
ParseResourceParam(const std::string & src,ResourceParams & dst)400 void CommandOpt::ParseResourceParam(const std::string &src, ResourceParams& dst)
401 {
402     auto pos = src.find(',');
403     if (pos == string::npos) {
404         return;
405     }
406     dst.inputFile = src.substr(0, pos);
407     istringstream value(src.substr(pos + 1));
408     int pixelFmt;
409     char c;
410     value >> dst.dispW >> c >> dst.dispH >> c >> pixelFmt;
411     dst.pixFmt = static_cast<VideoPixelFormat>(pixelFmt);
412 }
413 
ParseWaterMark(const char * cmd)414 void CommandOpt::ParseWaterMark(const char *cmd) // "/data/test/a.rgba,1280,720,2:16,16,1280,720"
415 {
416     string s(cmd);
417     auto pos = s.find(':');
418     if (pos == string::npos) {
419         return;
420     }
421     waterMark.isSet = true;
422     string resource = s.substr(0, pos);           // "/data/test/a.rgba,1280,720,2"
423     ParseResourceParam(resource, waterMark.waterMarkFile);
424     istringstream coordinate(s.substr(pos + 1));  // "16,16,1280,720"
425     char c;
426     coordinate >> waterMark.dstX >> c >> waterMark.dstY >> c >> waterMark.dstW >> c >> waterMark.dstH;
427 }
428 
Print() const429 void CommandOpt::Print() const
430 {
431     TLOGI("-----------------------------");
432     TLOGI("api type=%d, %s, %s mode, render = %d", apiType,
433         (isEncoder ? "encoder" : (decThenEnc ? "dec + enc" : "decoder")),
434         isBufferMode ? "buffer" : "surface", render);
435     TLOGI("read inputFile %s up to %u frames", inputFile.c_str(), maxReadFrameCnt);
436     TLOGI("%u x %u @ %u fps", dispW, dispH, frameRate);
437     TLOGI("protocol = %d, pixFmt = %d", protocol, pixFmt);
438     TLOGI("repeat %u times, timeout = %d", repeatCnt, timeout);
439     TLOGI("enableHighPerfMode : %s", isHighPerfMode ? "yes" : "no");
440 
441     if (mockFrameCnt.has_value()) {
442         TLOGI("mockFrameCnt %u", mockFrameCnt.value());
443     }
444     if (rangeFlag.has_value()) {
445         TLOGI("rangeFlag %d", rangeFlag.value());
446     }
447     if (primary.has_value()) {
448         TLOGI("primary %d", primary.value());
449     }
450     if (transfer.has_value()) {
451         TLOGI("transfer %d", transfer.value());
452     }
453     if (matrix.has_value()) {
454         TLOGI("matrix %d", matrix.value());
455     }
456     if (iFrameInterval.has_value()) {
457         TLOGI("iFrameInterval %d", iFrameInterval.value());
458     }
459     if (profile.has_value()) {
460         TLOGI("profile %d", profile.value());
461     }
462     if (rateMode.has_value()) {
463         TLOGI("rateMode %d", rateMode.value());
464     }
465     if (bitRate.has_value()) {
466         TLOGI("bitRate %u", bitRate.value());
467     }
468     if (quality.has_value()) {
469         TLOGI("quality %u", quality.value());
470     }
471     if (qpRange.has_value()) {
472         TLOGI("qpRange %u~%u", qpRange->qpMin, qpRange->qpMax);
473     }
474     if (waterMark.isSet) {
475         TLOGI("dstX %d, dstY %d, dstW %d, dstH %d",
476               waterMark.dstX, waterMark.dstY, waterMark.dstW, waterMark.dstH);
477     }
478     TLOGI("rotation angle %u", rotation);
479     TLOGI("flush cnt %d", flushCnt);
480     for (const auto &[frameNo, setparam] : setParameterParamsMap) {
481         TLOGI("frameNo = %u:", frameNo);
482         if (setparam.requestIdr.has_value()) {
483             TLOGI("    requestIdr %d", setparam.requestIdr.value());
484         }
485         if (setparam.qpRange.has_value()) {
486             TLOGI("    qpRange %u~%u", setparam.qpRange->qpMin, setparam.qpRange->qpMax);
487         }
488         if (setparam.bitRate.has_value()) {
489             TLOGI("    bitRate %u", setparam.bitRate.value());
490         }
491         if (setparam.frameRate.has_value()) {
492             TLOGI("    frameRate %f", setparam.frameRate.value());
493         }
494     }
495     for (const auto &[frameNo, perFrame] : perFrameParamsMap) {
496         TLOGI("frameNo = %u:", frameNo);
497         if (perFrame.requestIdr.has_value()) {
498             TLOGI("    requestIdr %d", perFrame.requestIdr.value());
499         }
500         if (perFrame.qpRange.has_value()) {
501             TLOGI("    qpRange %u~%u", perFrame.qpRange->qpMin, perFrame.qpRange->qpMax);
502         }
503         if (perFrame.ltrParam.has_value()) {
504             TLOGI("    LTR, markAsLTR %d, useLTR %d, useLTRPoc %u",
505                   perFrame.ltrParam->markAsLTR, perFrame.ltrParam->useLTR, perFrame.ltrParam->useLTRPoc);
506         }
507     }
508     for (const auto &[frameNo, resourceParam] : resourceParamsMap) {
509         TLOGI("frameNo = %u, filePath = %s, %u x %u, pixFmt = %d", frameNo,
510               resourceParam.inputFile.c_str(), resourceParam.dispW, resourceParam.dispH, resourceParam.pixFmt);
511     }
512     TLOGI("-----------------------------");
513 }
514 }