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 }