-
Notifications
You must be signed in to change notification settings - Fork 45
/
Copy pathProgramConfig.h
510 lines (474 loc) · 20.6 KB
/
ProgramConfig.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
/*
* Copyright (C) 2016 Google, Inc.
* Copyright 2020 NVIDIA Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _PROGRAMSETTINGS_H_
#define _PROGRAMSETTINGS_H_
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <functional>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include "vulkan_interfaces.h"
struct ProgramConfig {
struct ArgSpec {
const char *flag;
const char *short_flag;
int numArgs;
const char *help;
std::function<bool(const char **, const std::vector<ArgSpec> &)> lambda;
};
ProgramConfig(const char* programName) {
appName = programName;
initialWidth = 1920;
initialHeight = 1080;
initialBitdepth = 8;
videoWidth = 0;
videoHeight = 0;
queueCount = 1;
numDecodeImagesInFlight = 8;
numDecodeImagesToPreallocate = -1; // pre-allocate the maximum num of images
numBitstreamBuffersToPreallocate = 8;
backBufferCount = 3;
ticksPerSecond = 30;
vsync = true;
verbose = false;
validate = false;
validateVerbose = false;
noPresent = false;
maxFrameCount = -1;
videoFileName = "";
loopCount = 1;
queueId = 0;
gpuIndex = -1;
forceParserType = VK_VIDEO_CODEC_OPERATION_NONE_KHR;
decoderQueueSize = 5;
enablePostProcessFilter = -1,
enableStreamDemuxing = true;
deviceId = (uint32_t)-1;
directMode = false;
enableHwLoadBalancing = false;
selectVideoWithComputeQueue = false;
enableVideoEncoder = false;
crcOutput = nullptr;
outputy4m = false;
outputcrcPerFrame = false;
outputcrc = false;
crcOutputFile = nullptr;
numberOfDecodeWorkers = 0;
enableWorkerProcessesPoll = false;
ipcType = 0;
}
using ProgramArgs = std::vector<ArgSpec>;
static bool showHelp(const char ** argv, const ProgramArgs &spec) {
std::cout << argv[0] << std::endl;
for ( auto& flag : spec ) {
std::stringstream ss;
if (flag.flag) {
ss << flag.flag << (flag.short_flag ? ", " : "");
}
if (flag.short_flag) {
ss << flag.short_flag;
}
// Print flags column 30 chars wide, left justified
std::cout << " " << std::left << std::setw(30) << ss.str();
// Print help if available, left justified
if (flag.help) {
std::cout << flag.help;
}
std::cout << std::endl;
}
return true;
};
void ParseArgs(int argc, const char *argv[]) {
ProgramArgs spec = {
{"--help", nullptr, 0, "Show this help",
[argv](const char **, const ProgramArgs &a) {
int rtn = showHelp(argv, a);
exit(EXIT_SUCCESS);
return rtn;
}},
{"--enableStrDemux", nullptr, 0, "Enable stream demuxing",
[this](const char **, const ProgramArgs &a) {
enableStreamDemuxing = true;
return true;
}},
{"--disableStrDemux", nullptr, 0, "Disable stream demuxing",
[this](const char **, const ProgramArgs &a) {
enableStreamDemuxing = false;
return true;
}},
{"--codec", nullptr, 1, "Codec to decode",
[this](const char **args, const ProgramArgs &a) {
if ((strcmp(args[0], "hevc") == 0) ||
(strcmp(args[0], "h265") == 0)) {
forceParserType = VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR;
return true;
} else if ((strcmp(args[0], "avc") == 0) ||
(strcmp(args[0], "h264") == 0)) {
forceParserType = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR;
return true;
} else {
std::cerr << "Invalid codec \"" << args[0] << "\"" << std::endl;
return false;
}
}},
{"--disableVsync", "-b", 0, "Disable vsync",
[this](const char **args, const ProgramArgs &a) {
vsync = false;
return true;
}},
{"--initialWidth", "-w", 1, "Initial width of the video",
[this](const char **args, const ProgramArgs &a) {
initialWidth = std::atoi(args[0]);
return true;
}},
{"--initialHeight", "-h", 1, "Initial height of the video",
[this](const char **args, const ProgramArgs &a) {
initialHeight = std::atoi(args[0]);
return true;
}},
{"--validate", "-v", 0, "Validate input bitstream",
[this](const char **args, const ProgramArgs &a) {
validate = true;
return true;
}},
{"--verboseValidate", "-vv", 0,
"Validate input bitstream and be verbose",
[this](const char **args, const ProgramArgs &a) {
validate = true;
verbose = true;
return true;
}},
{"--selectVideoWithComputeQueue", nullptr, 0,
"Select a video queue that supports compute",
[this](const char **args, const ProgramArgs &a) {
selectVideoWithComputeQueue = true;
return true;
}},
{"--noPresent", nullptr, 0,
"Runs this program headless without presenting decode result to "
"screen",
[this](const char **args, const ProgramArgs &a) {
noPresent = true;
return true;
}},
{"--enableHwLoadBalancing", nullptr, 0,
"Enable hardware load balancing by doing a round-robin through all "
"available decode queues",
[this](const char **args, const ProgramArgs &a) {
enableHwLoadBalancing = true;
return true;
}},
{"--input", "-i", 1, "Input filename to decode",
[this](const char **args, const ProgramArgs &a) {
videoFileName = args[0];
// std::ifstream validVideoFileStream(videoFileName, std::ifstream::in);
// return (bool)validVideoFileStream;
return true;
}},
{"--output", "-o", 1, "Output filename to dump raw video to",
[this](const char **args, const ProgramArgs &a) {
outputFileName = args[0];
return true;
}},
{"--gpu", "-gpu", 1, "Index to Vulkan physical device to use",
[this](const char **args, const ProgramArgs &a) {
gpuIndex = std::atoi(args[0]);
return true;
}},
{"--queueSize", nullptr, 1,
"Size of decode operation in-flight before synchronizing for the "
"result - only used with --noDisplay (when no presentation is enabled)",
[this](const char **args, const ProgramArgs &a) {
decoderQueueSize = std::atoi(args[0]);
return true;
}},
{"--decodeImagesInFlight", nullptr, 1,
"The number of decode images that are in-flight in addition to the DPB required",
[this](const char **args, const ProgramArgs &a) {
numDecodeImagesInFlight = std::atoi(args[0]);
return true;
}},
{"--displayBackBufferSize", nullptr, 1,
"Size of display back-buffers swapchain queue size",
[this](const char **args, const ProgramArgs &a) {
backBufferCount = std::atoi(args[0]);
return true;
}},
{"--enablePostProcessFilter", nullptr, 1, "Enables post processing by running "
"a compute shader on the decode output",
[this](const char **args, const ProgramArgs &a) {
enablePostProcessFilter = std::atoi(args[0]);
return true;
}},
{"--loop", nullptr, 1,
"Number of times the playback from input should be repeated",
[this](const char **args, const ProgramArgs &a) {
loopCount = std::atoi(args[0]);
if (loopCount < 0) {
std::cerr << "Loop count must not be negative" << std::endl;
return false;
}
return true;
}},
{"--maxFrameCount", "-c", 1,
"Limit number of frames to be processed",
[this](const char **args, const ProgramArgs &a) {
maxFrameCount = std::atoi(args[0]);
return true;
}},
{"--queueid", nullptr, 1, "Index of the decoder queue to be used",
[this](const char **args, const ProgramArgs &a) {
queueId = std::atoi(args[0]);
std::cout << queueId << std::endl;
if (queueId < 0) {
std::cerr << "queueid must not be negative" << std::endl;
return false;
}
return true;
}},
{"--deviceID", "-deviceID", 1, "Hex ID of the device to be used",
[this](const char **args, const ProgramArgs &a) {
sscanf(args[0], "%x", &deviceId);
return true;
}},
{"--deviceUuid", "-deviceUuid", 1, "UUID HEX string of the device to be used",
[this](const char **args, const ProgramArgs &a) {
size_t size = SetHexDeviceUUID(args[0]);
if (size != VK_UUID_SIZE) {
std::cerr << "Invalid deviceUuid format used: " << args[0]
<< " with size: " << strlen(args[0])
<< std::endl;
std::cerr << "deviceUuid must be represented by 16 hex (32 bytes) values."
<< std::endl;
return false;
}
return true;
}},
{"--direct", nullptr, 0, "Direct to display mode",
[this](const char **args, const ProgramArgs &a) {
directMode = true;
return true;
}},
{"--y4m", nullptr, 0, "Output to a Y4M container for easier loading by tools",
[this](const char **args, const ProgramArgs &a) {
outputy4m = true;
return true;
}},
{"--crc", nullptr, 0, "Output a CRC for the entire stream",
[this](const char **args, const ProgramArgs &a) {
outputcrc = true;
return true;
}},
{"--crcperframe", nullptr, 0, "Output a CRC for each frame",
[this](const char **args, const ProgramArgs &a) {
outputcrcPerFrame = true;
return true;
}},
{"--crcoutfile", nullptr, 1, "Output file to store the CRC output into.",
[this](const char **args, const ProgramArgs &a) {
crcOutputFile = fopen(args[0], "wt");
return true;
}},
{"--crcinit", nullptr, 1, "Initial value of the CRC separated by a comma, a set of CRCs can be specified with this commandline parameter",
[this](const char **args, const ProgramArgs &a) {
// Find out the amount of CRCs that need to be calculated.
// Using this feature allows the CRC generator to create multiple CRCs for the same frame or stream where the seed of the CRCs is different.
// Usually this will just be 1 entry, but can be used if a 32bit integer CRC is causing hash collisions.
// Example
// --crcinit ffffffff,0,5,6 will produce 4 crc's per frame and 4 crc's for the stream. Where each CRC is different.
// --crcinit X,Y,Z,W -> CRC: X^,Y^,Z^,W^
// --crcinit X,Y -> CRC: X^,Y^
// --crcinit X -> CRC: X^
std::vector<uint32_t> crcInitValueTemp;
std::istringstream stream(args[0]);
std::string token;
while (std::getline(stream, token, ',')) {
char* endPtr = NULL;
uint32_t initValue = strtoul(token.c_str(), &endPtr, 16);
if ((endPtr == NULL) || (*endPtr != 0)) {
std::cerr << "Failed to parse the following initial CRC value:"
<< token << std::endl;
return false;
}
crcInitValueTemp.push_back(initValue);
}
crcInitValue = crcInitValueTemp;
return true;
}},
{"--poll-of-processes", nullptr, 1, "Use poll of worker processes and specify number of workers.",
[this](const char **args, const ProgramArgs &a) {
enableWorkerProcessesPoll = true;
numberOfDecodeWorkers = std::atoi(args[0]);
return true;
}},
{"--files-to-decode", nullptr, 1, "Specify a file location where command lines for the poll of worker processes are saved.",
[this](const char **args, const ProgramArgs &a) {
fileListIpc = args[0];
return true;
}},
};
for (int i = 1; i < argc; i++) {
auto flag = std::find_if(spec.begin(), spec.end(), [&](ArgSpec &a) {
return (a.flag != nullptr && strcmp(argv[i], a.flag) == 0) ||
(a.short_flag != nullptr && strcmp(argv[i], a.short_flag) == 0);
});
if (flag == spec.end()) {
std::cerr << "Unknown argument \"" << argv[i] << "\"" << std::endl;
std::cout << std::endl;
showHelp(argv, spec);
exit(EXIT_FAILURE);
}
if (i + flag->numArgs >= argc) {
std::cerr << "Missing arguments for \"" << argv[i] << "\"" << std::endl;
exit(EXIT_FAILURE);
}
bool disableValueCheck = false;
if (i + 1 < argc && strcmp(argv[i + 1], "--") == 0) {
if (i + 1 + flag->numArgs >= argc) {
std::cerr << "Missing arguments for \"" << argv[i] << "\"" << std::endl;
exit(EXIT_FAILURE);
}
disableValueCheck = true;
i++;
}
// Only allow values not starting with `-` unless prefixed with `-- ` (e.g. -i -- --inputfile-starting-with-minus)
// This allows us to give better error messages as we don't expect any values to start with `-`
if (!disableValueCheck) {
for (int j = 1; j <= flag->numArgs; j++) {
if (argv[i + j][0] == '-') {
std::cerr << "Invalid value \"" << argv[i + j] << "\" for \"" << argv[i] << "\" "
"(we don't allow values starting with `-` by default). You probably missed to "
"set a value for \"" << argv[i] << "\"." << std::endl;
std::cerr << "Use \"-- " << argv[i + j] << "\" if you meant to set \"" << argv[i + j]
<< "\" for \"" << argv[i] << "\"." << std::endl;
exit(EXIT_FAILURE);
}
}
}
if (!flag->lambda(argv + i + 1, spec)) {
exit(EXIT_FAILURE);
}
i += flag->numArgs;
}
// Resolve the CRC request in case there is a --crcinit specified.
if (((outputcrcPerFrame != 0) || (outputcrc != 0))) {
if (crcInitValue.empty() != false) {
if (outputFileName.empty() != false) {
std::cerr << "Please specify -o if you intend to use CRC calculation, CRC calculation requires HOST accessible memory."
"Host accessible linear images requires an extra copy at the moment."
<< std::endl;
exit(EXIT_FAILURE);
}
crcInitValue.push_back(0);
}
if (crcOutputFile == nullptr) {
crcOutputFile = stdout;
}
}
if (!enableWorkerProcessesPoll) {
if (videoFileName.length() == 0) {
std::cerr << "Input file should be specified" << std::endl;
exit(EXIT_FAILURE);
}
std::ifstream validVideoFileStream(videoFileName, std::ifstream::in);
if (!(bool)validVideoFileStream) {
std::cerr << "Can't open input file: invalid file name" << std::endl;
exit(EXIT_FAILURE);
}
}
}
// Assuming we have the length as a parameter:
size_t SetDeviceUUID(const uint8_t* pDeviceUuid, size_t length) {
if ((pDeviceUuid == nullptr) || (length == 0)) {
deviceUUID.clear();
}
deviceUUID.assign(pDeviceUuid, pDeviceUuid + length);
return length;
}
// If deviceUuid is null-terminated (less common for binary data):
size_t SetDeviceUUID(const uint8_t* pDeviceUuid) {
size_t length = strlen(reinterpret_cast<const char*>(pDeviceUuid));
return SetDeviceUUID(pDeviceUuid, length);
}
size_t SetHexDeviceUUID(const char* pDeviceUuid) {
size_t deviceUuidLen = strnlen(pDeviceUuid, (VK_UUID_SIZE * 2));
if (deviceUuidLen < (VK_UUID_SIZE * 2)) {
return 0;
}
deviceUUID.clear();
for (size_t i = 0; i < VK_UUID_SIZE; ++i) {
uint8_t hexByte = 0;
sscanf(pDeviceUuid, "%2hhx", &hexByte);
deviceUUID.push_back(hexByte);
pDeviceUuid += 2;
}
return VK_UUID_SIZE;
}
const uint8_t* GetDeviceUUID() const {
return deviceUUID.empty() ? nullptr : deviceUUID.data();
}
FILE* crcOutputFile;
std::string appName;
std::basic_string<uint8_t> deviceUUID;
int initialWidth;
int initialHeight;
int initialBitdepth;
int videoWidth;
int videoHeight;
int queueCount;
int32_t numDecodeImagesInFlight;
int32_t numDecodeImagesToPreallocate;
int32_t numBitstreamBuffersToPreallocate;
int backBufferCount;
int ticksPerSecond;
int maxFrameCount;
std::string videoFileName;
std::string outputFileName;
int gpuIndex;
int loopCount;
int queueId;
VkVideoCodecOperationFlagBitsKHR forceParserType;
std::vector<uint32_t> crcInitValue;
uint32_t *crcValues;
uint32_t deviceId;
uint32_t decoderQueueSize;
int32_t enablePostProcessFilter;
uint32_t *crcOutput;
uint32_t numberOfDecodeWorkers;
uint32_t enableStreamDemuxing : 1;
uint32_t directMode : 1;
uint32_t vsync : 1;
uint32_t validate : 1;
uint32_t validateVerbose : 1;
uint32_t verbose : 1;
uint32_t noPresent : 1;
uint32_t enableHwLoadBalancing : 1;
uint32_t selectVideoWithComputeQueue : 1;
uint32_t enableVideoEncoder : 1;
uint32_t outputy4m : 1;
uint32_t outputcrc : 1;
uint32_t outputcrcPerFrame : 1;
uint32_t enableWorkerProcessesPoll : 1;
uint32_t ipcType : 1;
std::string fileListIpc;
};
#endif /* _PROGRAMSETTINGS_H_ */