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