1 /* ----------------------------------------------------------------------------- 2 The copyright in this software is being made available under the BSD 3 License, included below. No patent rights, trademark rights and/or 4 other Intellectual Property Rights other than the copyrights concerning 5 the Software are granted under this license. 6 7 For any license concerning other Intellectual Property rights than the software, 8 especially patent licenses, a separate Agreement needs to be closed. 9 For more information please contact: 10 11 Fraunhofer Heinrich Hertz Institute 12 Einsteinufer 37 13 10587 Berlin, Germany 14 www.hhi.fraunhofer.de/vvc 15 vvc@hhi.fraunhofer.de 16 17 Copyright (c) 2018-2021, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. 18 All rights reserved. 19 20 Redistribution and use in source and binary forms, with or without 21 modification, are permitted provided that the following conditions are met: 22 23 * Redistributions of source code must retain the above copyright notice, 24 this list of conditions and the following disclaimer. 25 * Redistributions in binary form must reproduce the above copyright notice, 26 this list of conditions and the following disclaimer in the documentation 27 and/or other materials provided with the distribution. 28 * Neither the name of Fraunhofer nor the names of its contributors may 29 be used to endorse or promote products derived from this software without 30 specific prior written permission. 31 32 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 33 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 36 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 37 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 40 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 41 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 42 THE POSSIBILITY OF SUCH DAMAGE. 43 44 45 ------------------------------------------------------------------------------------------- */ 46 47 #pragma once 48 49 #include <string> 50 #include <iostream> 51 #include <stdio.h> 52 #include <string.h> 53 #include <algorithm> 54 #include <cctype> 55 56 #include "vvdec/vvdec.h" 57 58 namespace vvdecoderapp { 59 60 class CmdLineParser 61 { 62 public: 63 /// Constructor CmdLineParser()64 CmdLineParser(){} 65 66 /// Destructor ~CmdLineParser()67 virtual ~CmdLineParser() {} 68 print_usage(std::string cApp,vvdecParams & rcParams)69 static void print_usage( std::string cApp, vvdecParams& rcParams ) 70 { 71 printf( "\n Usage: %s [param1] [pararm2] [...] \n", cApp.c_str() ); 72 std::cout << "\n" 73 "\t File input Options\n" 74 "\t\t [--bitstream,-b <str> ] : bitstream input file\n" 75 "\t\t [--frames,-f <int> ] : max. frames to decode (default: -1 all frames) \n" 76 "\n" 77 "\t YUV output options\n" 78 "\n" 79 "\t\t [--output,-o <str> ] : yuv output file (default: not set)\n" 80 "\t\t [--upscale,-uo ] : set upscaling mode for RPR pictures(default: 0: off, 1: copy without rescaling, 2: rescale to target resolution)\n" 81 "\n" 82 "\t Decoder Options\n" 83 "\n" 84 "\t\t [--threads,-t <int> ] : number of threads (default: <= 0 auto detection )\n" 85 "\t\t [--parsedelay,-p <int> ] : maximal number of frames to read before decoding (default: <= 0 auto detection )\n" 86 "\t\t [--simd <int> ] : used simd extension (0: scalar, 1: sse41, 2: sse42, 3: avx, 4: avx2, 5: avx512) (default: < 0 auto detection)\n" 87 "\n" 88 "\t\t [--SEIDecodedPictureHash,-dph ] : enable handling of decoded picture hash SEI messages\n" 89 "\t\t [--CheckYuvMD5,-md5 <md5str> ] : enable calculation of md5 hash over the full YUV output and check against the provided value.\n" 90 "\n" 91 "\t General Options\n" 92 "\n" 93 "\t\t [--loops,-L <int> ] : number of decoder loops (default: 0, -1 endless)\n" 94 "\t\t [--verbosity,-v <int> ] : verbosity level (0: silent, 1: error, 2: warning, 3: info, 4: notice: 5, verbose, 6: debug) (default: " << (int)rcParams.logLevel << ")\n" 95 "\t\t [--version ] : show version\n" 96 "\t\t [--help,-h ] : show help\n" 97 "\n" ; 98 std::cout << std::endl; 99 } 100 101 parse_command_line(int argc,char * argv[],vvdecParams & rcParams,std::string & rcBitstreamFile,std::string & rcOutputFile,int & riFrames,int & riLoops,std::string & rcExpectYuvMD5)102 static int parse_command_line( int argc, char* argv[] , vvdecParams& rcParams, std::string& rcBitstreamFile, std::string& rcOutputFile, 103 int& riFrames, int& riLoops, std::string& rcExpectYuvMD5 ) 104 { 105 int iRet = 0; 106 /* Check command line parameters */ 107 int32_t i_arg = 1; 108 109 /* Check general options firs*/ 110 while( i_arg < argc ) 111 { 112 if( (!strcmp( (const char*)argv[i_arg], "-v" )) || !strcmp( (const char*)argv[i_arg], "--verbosity" ) ) 113 { 114 if( i_arg == argc-1 ){ fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 115 i_arg++; 116 int iLogLevel = atoi( argv[i_arg++] ); 117 if( iLogLevel < 0 ) iLogLevel = 0; 118 if( iLogLevel > (int)vvdecLogLevel::VVDEC_DETAILS ) iLogLevel = (int)vvdecLogLevel::VVDEC_DETAILS ; 119 rcParams.logLevel = (vvdecLogLevel)iLogLevel; 120 121 if( rcParams.logLevel > VVDEC_VERBOSE ) 122 { 123 std::string cll; 124 switch (rcParams.logLevel) 125 { 126 case VVDEC_SILENT : cll = "SILENT"; break; 127 case VVDEC_ERROR : cll = "ERROR"; break; 128 case VVDEC_WARNING: cll = "WARNING"; break; 129 case VVDEC_INFO : cll = "INFO"; break; 130 case VVDEC_NOTICE : cll = "NOTICE"; break; 131 case VVDEC_VERBOSE: cll = "VERBOSE"; break; 132 case VVDEC_DETAILS: cll = "DETAILS"; break; 133 default: cll = "UNKNOWN"; break; 134 }; 135 fprintf( stdout, "[verbosity] : %d - %s\n", (int)rcParams.logLevel, cll.c_str() ); 136 } 137 } 138 else if( (!strcmp( (const char*)argv[i_arg], "-h" )) || !strcmp( (const char*)argv[i_arg], "--help" ) ) 139 { 140 i_arg++; 141 iRet = 2; 142 return iRet; 143 } 144 else if( !strcmp( (const char*)argv[i_arg], "--version" ) ) 145 { 146 i_arg++; 147 iRet = 3; 148 return iRet; 149 } 150 else 151 { 152 i_arg++; 153 } 154 } 155 156 157 i_arg = 1; 158 while( i_arg < argc ) 159 { 160 if( (!strcmp( (const char*)argv[i_arg], "-b" )) || !strcmp( (const char*)argv[i_arg], "--bitstream" ) ) /* In: input-file */ 161 { 162 if( i_arg == argc-1 ){ fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 163 i_arg++; 164 if( rcParams.logLevel > VVDEC_VERBOSE ) 165 fprintf( stdout, "[bitstream] input-file: %s\n", argv[i_arg] ); 166 rcBitstreamFile = argv[i_arg++]; 167 } 168 else if( (!strcmp( (const char*)argv[i_arg], "-o" )) || !strcmp( (const char*)argv[i_arg], "--output" ) ) /* Out: bitstream-file */ 169 { 170 if( i_arg == argc-1 ){ fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 171 i_arg++; 172 if( i_arg < argc && strlen( argv[i_arg] ) > 0 ) 173 { 174 if( rcParams.logLevel > VVDEC_VERBOSE ) 175 fprintf( stdout, "[output] yuv-file: %s\n", argv[i_arg] ); 176 rcOutputFile = argv[i_arg++]; 177 } 178 } 179 else if( (!strcmp( (const char*)argv[i_arg], "-uo" )) || !strcmp( (const char*)argv[i_arg], "--upscale" ) ) /* In: upscale */ 180 { 181 i_arg++; 182 183 rcParams.upscaleOutput = (vvdecRPRUpscaling) atoi( argv[i_arg++]); 184 185 if( rcParams.logLevel > VVDEC_VERBOSE ) 186 { 187 std::string scale; 188 switch( rcParams.upscaleOutput ) 189 { 190 case VVDEC_UPSCALING_OFF : scale = "OFF"; break; 191 case VVDEC_UPSCALING_COPY_ONLY: scale = "COPY_ONLY"; break; 192 case VVDEC_UPSCALING_RESCALE : scale = "RESCALE"; break; 193 default: scale = "UNKNOWN"; break; 194 }; 195 fprintf( stdout, "[upscale] : %s\n", scale.c_str() ); 196 } 197 } 198 else if( (!strcmp( (const char*)argv[i_arg], "-f" )) || !strcmp( (const char*)argv[i_arg], "--frames" ) ) 199 { 200 if( i_arg == argc-1 ){ fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 201 i_arg++; 202 riFrames = atoi( argv[i_arg++] ); 203 if( rcParams.logLevel > VVDEC_VERBOSE ) 204 fprintf( stdout, "[frames] : %d\n", riFrames ); 205 } 206 else if( (!strcmp( (const char*)argv[i_arg], "-t" )) || !strcmp( (const char*)argv[i_arg], "--threads" ) ) 207 { 208 if( i_arg == argc-1 ){ fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 209 i_arg++; 210 int iThreads = atoi( argv[i_arg++] ); 211 if( rcParams.logLevel > VVDEC_VERBOSE ) 212 fprintf( stdout, "[threads] : %d\n", iThreads ); 213 rcParams.threads = iThreads; 214 } 215 else if( (!strcmp( (const char*)argv[i_arg], "-p" )) || !strcmp( (const char*)argv[i_arg], "--parsedelay" ) ) 216 { 217 if( i_arg == argc-1 ){ fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 218 i_arg++; 219 int iThreads = atoi( argv[i_arg++] ); 220 if( rcParams.logLevel > VVDEC_VERBOSE ) 221 fprintf( stdout, "[parsedelay] : %d\n", iThreads ); 222 rcParams.parseThreads = iThreads; 223 } 224 else if( (!strcmp( (const char*)argv[i_arg], "-dph" )) || !strcmp( (const char*)argv[i_arg], "--SEIDecodedPictureHash" ) ) 225 { 226 i_arg++; 227 if( i_arg < argc ) 228 { 229 if( std::isdigit(argv[i_arg][0])) 230 { 231 i_arg++; 232 } 233 } 234 235 if( rcParams.logLevel > VVDEC_VERBOSE ) 236 fprintf( stdout, "[SEIDecodedPictureHash] : true\n" ); 237 rcParams.verifyPictureHash = true; 238 } 239 else if( ( !strcmp( (const char*)argv[i_arg], "-md5" ) ) || !strcmp( (const char*)argv[i_arg], "--CheckYuvMD5" ) ) 240 { 241 if( i_arg >= argc - 1 ) { fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 242 i_arg++; 243 if( strlen( argv[i_arg] ) != 32 ) 244 { 245 fprintf( stderr, " - the provided md5 hash to %s should be exactly 32 characters long\n", argv[i_arg - 1] ); 246 return -1; 247 } 248 249 rcExpectYuvMD5 = std::string( argv[i_arg++] ); 250 251 if( rcParams.logLevel > VVDEC_VERBOSE ) 252 fprintf( stdout, "[CheckYuvMD5] : %s\n", rcExpectYuvMD5.c_str() ); 253 } 254 else if( (!strcmp( (const char*)argv[i_arg], "-L" )) || !strcmp( (const char*)argv[i_arg], "--loops" ) ) 255 { 256 if( i_arg == argc-1 ){ fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 257 i_arg++; 258 riLoops = atoi( argv[i_arg++] ); 259 if( rcParams.logLevel > VVDEC_VERBOSE ) 260 fprintf( stdout, "[loops] : %d\n", riLoops ); 261 } 262 else if( (!strcmp( (const char*)argv[i_arg], "-v" )) || !strcmp( (const char*)argv[i_arg], "--verbosity" ) ) 263 { 264 // already processed 265 i_arg++; 266 i_arg++; 267 } 268 else if( (!strcmp( (const char*)argv[i_arg], "-h" )) || !strcmp( (const char*)argv[i_arg], "--help" ) ) 269 { 270 // already processed 271 i_arg++; 272 } 273 else if( !strcmp( (const char*)argv[i_arg], "--version" ) ) 274 { 275 // already processed 276 i_arg++; 277 } 278 else if( !strcmp( ( const char* ) argv[i_arg], "--simd" ) ) 279 { 280 if( i_arg == argc-1 ){ fprintf( stderr, " - missing argument for: %s \n", argv[i_arg] ); return -1; } 281 i_arg++; 282 rcParams.simd = vvdecSIMD_Extension( std::max( -1, atoi( argv[i_arg++] ) ) + 1 ); 283 284 if( rcParams.logLevel > VVDEC_VERBOSE ) 285 { 286 std::string cll; 287 switch( rcParams.simd ) 288 { 289 case VVDEC_SIMD_DEFAULT: cll = "DEFAULT"; break; 290 case VVDEC_SIMD_SCALAR: cll = "SCALAR"; break; 291 case VVDEC_SIMD_SSE41: cll = "SSE41"; break; 292 case VVDEC_SIMD_SSE42: cll = "SSE42"; break; 293 case VVDEC_SIMD_AVX: cll = "AVX"; break; 294 case VVDEC_SIMD_AVX2: cll = "AVX2"; break; 295 case VVDEC_SIMD_AVX512: cll = "AVX512"; break; 296 default: cll = "UNKNOWN"; break; 297 }; 298 fprintf( stdout, "[simd] : %s\n", cll.c_str() ); 299 } 300 } 301 else 302 { 303 fprintf( stderr, " - unknown argument: %s \n", argv[i_arg++] ); 304 iRet = -1; 305 } 306 } 307 308 return iRet; 309 } 310 311 private: 312 std::ofstream m_cOS; 313 }; 314 315 316 317 } // namespace 318 319