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