1 /******************************************************************************\
2 Copyright (c) 2005-2020, Intel Corporation
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6 
7 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 
9 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10 
11 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12 
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 
15 This sample was distributed or derived from the Intel's Media Samples package.
16 The original version of this sample may be obtained from https://software.intel.com/en-us/intel-media-server-studio
17 or https://software.intel.com/en-us/media-client-solutions-support.
18 \**********************************************************************************/
19 
20 #ifndef __SAMPLE_UTILS_H__
21 #define __SAMPLE_UTILS_H__
22 
23 #include <stdio.h>
24 #include <string>
25 #include <sstream>
26 #include <vector>
27 #include <map>
28 #include <stdexcept>
29 #include <mutex>
30 #include <algorithm>
31 #include <fstream>
32 
33 #include "mfxstructures.h"
34 #include "mfxvideo.h"
35 #include "mfxvideo++.h"
36 #include "mfxjpeg.h"
37 #include "mfxplugin.h"
38 #include "mfxbrc.h"
39 #include "mfxfei.h"
40 #include "mfxfeihevc.h"
41 #include "mfxmvc.h"
42 #include "mfxla.h"
43 
44 #include "vm/strings_defs.h"
45 #include "vm/file_defs.h"
46 #include "vm/time_defs.h"
47 #include "vm/atomic_defs.h"
48 #include "vm/thread_defs.h"
49 
50 #include "sample_types.h"
51 
52 #include "abstract_splitter.h"
53 #include "avc_bitstream.h"
54 #include "avc_spl.h"
55 #include "avc_headers.h"
56 #include "avc_nal_spl.h"
57 
58 
59 // A macro to disallow the copy constructor and operator= functions
60 // This should be used in the private: declarations for a class
61 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
62     TypeName(const TypeName&);               \
63     void operator=(const TypeName&)
64 
65 //! Base class for types that should not be assigned.
66 class no_assign {
67     // Deny assignment
68     void operator=( const no_assign& );
69 public:
70 #if __GNUC__
71     //! Explicitly define default construction, because otherwise gcc issues gratuitous warning.
no_assign()72     no_assign() {}
73 #endif /* __GNUC__ */
74 };
75 
76 //! Base class for types that should not be copied or assigned.
77 class no_copy: no_assign {
78     //! Deny copy construction
79     no_copy( const no_copy& );
80 public:
81     //! Allow default construction
no_copy()82     no_copy() {}
83 };
84 
85 enum {
86     CODEC_VP8 = MFX_MAKEFOURCC('V','P','8',' '),
87     CODEC_MVC = MFX_MAKEFOURCC('M','V','C',' '),
88 };
89 
90 #define MFX_CODEC_DUMP MFX_MAKEFOURCC('D','U','M','P')
91 #define MFX_CODEC_RGB4 MFX_FOURCC_RGB4
92 #define MFX_CODEC_NV12 MFX_FOURCC_NV12
93 #define MFX_CODEC_I420 MFX_FOURCC_I420
94 #define MFX_CODEC_P010 MFX_FOURCC_P010
95 
96 enum
97 {
98     MFX_FOURCC_IMC3         = MFX_MAKEFOURCC('I','M','C','3'),
99     MFX_FOURCC_YUV400       = MFX_MAKEFOURCC('4','0','0','P'),
100     MFX_FOURCC_YUV411       = MFX_MAKEFOURCC('4','1','1','P'),
101     MFX_FOURCC_YUV422H      = MFX_MAKEFOURCC('4','2','2','H'),
102     MFX_FOURCC_YUV422V      = MFX_MAKEFOURCC('4','2','2','V'),
103     MFX_FOURCC_YUV444       = MFX_MAKEFOURCC('4','4','4','P'),
104 #if (MFX_VERSION <= 1027)
105     MFX_FOURCC_RGBP         = MFX_MAKEFOURCC('R','G','B','P'),
106 #endif
107     MFX_FOURCC_I420         = MFX_MAKEFOURCC('I','4','2','0')
108 };
109 
110 enum ExtBRCType {
111     EXTBRC_DEFAULT,
112     EXTBRC_OFF,
113     EXTBRC_ON,
114     EXTBRC_IMPLICIT
115 };
116 
117 namespace QPFile {
118 
119     enum ReaderStatus
120     {
121         READER_ERR_NONE,
122         READER_ERR_NOT_INITIALIZED,
123         READER_ERR_CODEC_UNSUPPORTED,
124         READER_ERR_FILE_NOT_OPEN,
125         READER_ERR_INCORRECT_FILE
126     };
127 
128     struct FrameInfo
129     {
130         mfxU32 displayOrder;
131         mfxU16 QP;
132         mfxU16 frameType;
133     };
134 
135     // QPFile::Reader reads QP and frame type per frame in encoding order
136     // from external text file (for encoding in qpfile mode)
137     class Reader
138     {
139     public:
140         mfxStatus Read(const msdk_string& strFileName, mfxU32 codecid);
141         void ResetState();
142 
143         mfxU32 GetCurrentEncodedOrder() const;
144         mfxU32 GetCurrentDisplayOrder() const;
145         mfxU16 GetCurrentQP() const;
146         mfxU16 GetCurrentFrameType() const;
147         mfxU32 GetFramesNum() const;
148         void NextFrame();
149         std::string GetErrorMessage() const;
150 
151     private:
152         void ResetState(ReaderStatus set_sts);
153 
154         ReaderStatus            m_ReaderSts   = READER_ERR_NOT_INITIALIZED;
155         mfxU32                  m_nFrames     = std::numeric_limits<mfxU32>::max();
156         mfxU32                  m_CurFrameNum = std::numeric_limits<mfxU32>::max();
157         std::vector<FrameInfo>  m_FrameVals {};
158     };
159 
get_line(std::ifstream & ifs,std::string & line)160     inline bool get_line(std::ifstream& ifs, std::string& line)
161     {
162         std::getline(ifs, line, '\n');
163         if (!line.empty() && line.back() == '\r')
164             line.pop_back();
165         return !ifs.fail();
166     }
find_nth(const std::string & str,size_t pos,const std::string & needle,mfxU32 nth)167     inline size_t find_nth(const std::string& str, size_t pos, const std::string& needle, mfxU32 nth)
168     {
169         size_t found_pos = str.find(needle, pos);
170         for(; nth != 0 && std::string::npos != found_pos; --nth)
171             found_pos = str.find(needle, found_pos + 1);
172         return found_pos;
173     }
StringToFrameType(std::string str)174     inline mfxU16 StringToFrameType(std::string str)
175     {
176         if ("IDR_REF" == str) return MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_REF;
177         else if ("I_REF" == str) return MFX_FRAMETYPE_I | MFX_FRAMETYPE_REF;
178         else if ("P_REF" == str) return MFX_FRAMETYPE_P | MFX_FRAMETYPE_REF;
179         else if ("P" == str) return MFX_FRAMETYPE_P;
180         else if ("B_REF" == str) return MFX_FRAMETYPE_B | MFX_FRAMETYPE_REF;
181         else if ("B" == str) return MFX_FRAMETYPE_B;
182         else return MFX_FRAMETYPE_UNKNOWN;
183     }
ReaderStatusToString(ReaderStatus sts)184     inline std::string ReaderStatusToString(ReaderStatus sts)
185     {
186         switch (sts)
187         {
188         case READER_ERR_NOT_INITIALIZED:
189             return std::string("reader not initialized (qpfile has not yet read the file)\n");
190         case READER_ERR_FILE_NOT_OPEN:
191             return std::string("failed to open file contains frame parameters (check provided path in -qpfile <path>)\n");
192         case READER_ERR_INCORRECT_FILE:
193             return std::string("incorrect file with frame parameters\n");
194         case READER_ERR_CODEC_UNSUPPORTED:
195             return std::string("codecs, except h264 and h265, are not supported\n");
196         default:
197             return std::string();
198         }
199     }
ReadDisplayOrder(const std::string & line)200     inline mfxU32 ReadDisplayOrder(const std::string& line)
201     {
202         return std::stoi(line.substr(0, find_nth(line, 0, ",", 0)));
203     }
ReadQP(const std::string & line)204     inline mfxU16 ReadQP(const std::string& line)
205     {
206         size_t pos = find_nth(line, 0, ",", 0) + 1;
207         return static_cast<mfxU16>(std::stoi(line.substr(pos, find_nth(line, 0, ",", 1) - pos)));
208     }
ReadFrameType(const std::string & line)209     inline mfxU16 ReadFrameType(const std::string& line)
210     {
211         size_t pos = find_nth(line, 0, ",", 1) + 1;
212         return StringToFrameType(line.substr(pos, line.length() - pos));
213     }
214 }
215 
216 namespace TCBRCTestFile {
217 
218     enum ReaderStatus
219     {
220         READER_ERR_NONE,
221         READER_ERR_NOT_INITIALIZED,
222         READER_ERR_CODEC_UNSUPPORTED,
223         READER_ERR_FILE_NOT_OPEN,
224         READER_ERR_INCORRECT_FILE
225     };
226 
227     struct FrameInfo
228     {
229         mfxU32 displayOrder;
230         mfxU32 targetFrameSize;
231     };
232 
233     // TCBRCTestFile reads target frame size in display order
234     // from external text file (for encoding in Low delay BRC mode)
235 
236     class Reader
237     {
238     public:
239         mfxStatus Read(const msdk_string& strFileName, mfxU32 codecid);
240         void ResetState();
241 
242         mfxU32 GetTargetFrameSize(mfxU32 frameOrder) const;
243         mfxU32 GetFramesNum() const;
244         void NextFrame();
245         std::string GetErrorMessage() const;
246 
247     private:
248         void ResetState(ReaderStatus set_sts);
249 
250         ReaderStatus            m_ReaderSts = READER_ERR_NOT_INITIALIZED;
251         mfxU32                  m_CurFrameNum = std::numeric_limits<mfxU32>::max();
252         std::vector<FrameInfo>  m_FrameVals{};
253     };
254 
get_line(std::ifstream & ifs,std::string & line)255     inline bool get_line(std::ifstream& ifs, std::string& line)
256     {
257         std::getline(ifs, line, '\n');
258         if (!line.empty() && line.back() == '\r')
259             line.pop_back();
260         return !ifs.fail();
261     }
find_nth(const std::string & str,size_t pos,const std::string & needle,mfxU32 nth)262     inline size_t find_nth(const std::string& str, size_t pos, const std::string& needle, mfxU32 nth)
263     {
264         size_t found_pos = str.find(needle, pos);
265         for (; nth != 0 && std::string::npos != found_pos; --nth)
266             found_pos = str.find(needle, found_pos + 1);
267         return found_pos;
268     }
269 
ReaderStatusToString(ReaderStatus sts)270     inline std::string ReaderStatusToString(ReaderStatus sts)
271     {
272         switch (sts)
273         {
274         case READER_ERR_NOT_INITIALIZED:
275             return std::string("reader not initialized (TCBRCTestfile has not yet read the file)\n");
276         case READER_ERR_FILE_NOT_OPEN:
277             return std::string("failed to open file  with TargetFrameSize parameters (check provided path in -tcbrcfile <path>)\n");
278         case READER_ERR_INCORRECT_FILE:
279             return std::string("incorrect file with frame parameters\n");
280         case READER_ERR_CODEC_UNSUPPORTED:
281             return std::string("h264 and h265 are supported now\n");
282         default:
283             return std::string();
284         }
285     }
ReadDisplayOrder(const std::string & line)286     inline mfxU32 ReadDisplayOrder(const std::string& line)
287     {
288         size_t pos = find_nth(line, 0, ":", 0);
289         if (pos != std::string::npos)
290             return std::stoi(line.substr(0, pos));
291         else
292             return 0;
293     }
ReadTargetFrameSize(const std::string & line)294     inline mfxU16 ReadTargetFrameSize(const std::string& line)
295     {
296         size_t pos = find_nth(line, 0, ":", 0);
297         pos = (pos != std::string::npos) ? pos + 1 : 0;
298         return static_cast<mfxU16>(std::stoi(line.substr(pos, line.size() - pos)));
299     }
300 }
301 mfxStatus GetFrameLength(mfxU16 width, mfxU16 height, mfxU32 ColorFormat, mfxU32 &length);
302 
303 bool IsDecodeCodecSupported(mfxU32 codecFormat);
304 bool IsEncodeCodecSupported(mfxU32 codecFormat);
305 bool IsPluginCodecSupported(mfxU32 codecFormat);
306 
307 // class is used as custom exception
308 class mfxError : public std::runtime_error
309 {
310 public:
311     mfxError(mfxStatus status = MFX_ERR_UNKNOWN, std::string msg = "")
runtime_error(msg)312         : runtime_error(msg)
313         , m_Status(status)
314     {}
315 
GetStatus()316     mfxStatus GetStatus() const
317     { return m_Status; }
318 
319 private:
320     mfxStatus m_Status;
321 };
322 
323 //declare used extension buffers
324 template<class T>
325 struct mfx_ext_buffer_id{};
326 
327 template<>struct mfx_ext_buffer_id<mfxExtCodingOption>{
328     enum {id = MFX_EXTBUFF_CODING_OPTION};
329 };
330 template<>struct mfx_ext_buffer_id<mfxExtCodingOption2>{
331     enum {id = MFX_EXTBUFF_CODING_OPTION2};
332 };
333 template<>struct mfx_ext_buffer_id<mfxExtCodingOption3>{
334     enum {id = MFX_EXTBUFF_CODING_OPTION3};
335 };
336 template<>struct mfx_ext_buffer_id<mfxExtAvcTemporalLayers>{
337     enum {id = MFX_EXTBUFF_AVC_TEMPORAL_LAYERS};
338 };
339 template<>struct mfx_ext_buffer_id<mfxExtAVCRefListCtrl>{
340     enum {id = MFX_EXTBUFF_AVC_REFLIST_CTRL};
341 };
342 template<>struct mfx_ext_buffer_id<mfxExtThreadsParam>{
343     enum {id = MFX_EXTBUFF_THREADS_PARAM};
344 };
345 template<>struct mfx_ext_buffer_id<mfxExtFeiParam> {
346     enum {id = MFX_EXTBUFF_FEI_PARAM};
347 };
348 template<>struct mfx_ext_buffer_id<mfxExtFeiPreEncCtrl> {
349     enum {id = MFX_EXTBUFF_FEI_PREENC_CTRL};
350 };
351 template<>struct mfx_ext_buffer_id<mfxExtFeiPreEncMV>{
352     enum {id = MFX_EXTBUFF_FEI_PREENC_MV};
353 };
354 template<>struct mfx_ext_buffer_id<mfxExtFeiPreEncMBStat>{
355     enum {id = MFX_EXTBUFF_FEI_PREENC_MB};
356 };
357 template<>struct mfx_ext_buffer_id<mfxExtFeiHevcEncFrameCtrl>{
358     enum {id = MFX_EXTBUFF_HEVCFEI_ENC_CTRL};
359 };
360 template<>struct mfx_ext_buffer_id<mfxExtFeiHevcEncMVPredictors>{
361     enum {id = MFX_EXTBUFF_HEVCFEI_ENC_MV_PRED};
362 };
363 template<>struct mfx_ext_buffer_id<mfxExtFeiHevcEncQP>{
364     enum {id = MFX_EXTBUFF_HEVCFEI_ENC_QP};
365 };
366 template<>struct mfx_ext_buffer_id<mfxExtFeiHevcEncCtuCtrl>{
367     enum {id = MFX_EXTBUFF_HEVCFEI_ENC_CTU_CTRL};
368 };
369 template<>struct mfx_ext_buffer_id<mfxExtHEVCRefLists>{
370     enum {id = MFX_EXTBUFF_HEVC_REFLISTS};
371 };
372 template<>struct mfx_ext_buffer_id<mfxExtFeiHevcRepackCtrl>{
373     enum {id = MFX_EXTBUFF_HEVCFEI_REPACK_CTRL};
374 };
375 template<>struct mfx_ext_buffer_id<mfxExtFeiHevcRepackStat>{
376     enum {id = MFX_EXTBUFF_HEVCFEI_REPACK_STAT};
377 };
378 template<>struct mfx_ext_buffer_id<mfxExtBRC> {
379     enum {id = MFX_EXTBUFF_BRC};
380 };
381 template<>struct mfx_ext_buffer_id<mfxExtHEVCParam> {
382     enum {id = MFX_EXTBUFF_HEVC_PARAM};
383 };
384 template<>struct mfx_ext_buffer_id<mfxExtDecVideoProcessing> {
385     enum {id = MFX_EXTBUFF_DEC_VIDEO_PROCESSING};
386 };
387 template<>struct mfx_ext_buffer_id<mfxExtDecodeErrorReport> {
388     enum {id = MFX_EXTBUFF_DECODE_ERROR_REPORT};
389 };
390 template<>struct mfx_ext_buffer_id<mfxExtMVCSeqDesc> {
391     enum {id = MFX_EXTBUFF_MVC_SEQ_DESC};
392 };
393 template<>struct mfx_ext_buffer_id<mfxExtVPPDoNotUse> {
394     enum {id = MFX_EXTBUFF_VPP_DONOTUSE};
395 };
396 template<>struct mfx_ext_buffer_id<mfxExtVPPDoUse> {
397     enum {id = MFX_EXTBUFF_VPP_DOUSE};
398 };
399 template<>struct mfx_ext_buffer_id<mfxExtVPPDeinterlacing> {
400     enum {id = MFX_EXTBUFF_VPP_DEINTERLACING};
401 };
402 template<>struct mfx_ext_buffer_id<mfxExtCodingOptionSPSPPS> {
403     enum {id = MFX_EXTBUFF_CODING_OPTION_SPSPPS};
404 };
405 template<>struct mfx_ext_buffer_id<mfxExtOpaqueSurfaceAlloc> {
406     enum {id = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION};
407 };
408 template<>struct mfx_ext_buffer_id<mfxExtVppMctf> {
409     enum {id = MFX_EXTBUFF_VPP_MCTF};
410 };
411 template<>struct mfx_ext_buffer_id<mfxExtVPPComposite> {
412     enum {id = MFX_EXTBUFF_VPP_COMPOSITE};
413 };
414 template<>struct mfx_ext_buffer_id<mfxExtVPPFieldProcessing> {
415     enum {id = MFX_EXTBUFF_VPP_FIELD_PROCESSING};
416 };
417 template<>struct mfx_ext_buffer_id<mfxExtVPPDetail> {
418     enum {id = MFX_EXTBUFF_VPP_DETAIL};
419 };
420 template<>struct mfx_ext_buffer_id<mfxExtVPPFrameRateConversion> {
421     enum {id = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION};
422 };
423 template<>struct mfx_ext_buffer_id<mfxExtLAControl> {
424     enum {id = MFX_EXTBUFF_LOOKAHEAD_CTRL};
425 };
426 template<>struct mfx_ext_buffer_id<mfxExtMultiFrameControl> {
427     enum {id = MFX_EXTBUFF_MULTI_FRAME_CONTROL};
428 };
429 template<>struct mfx_ext_buffer_id<mfxExtMultiFrameParam> {
430     enum {id = MFX_EXTBUFF_MULTI_FRAME_PARAM};
431 };
432 template<>struct mfx_ext_buffer_id<mfxExtHEVCTiles> {
433     enum {id = MFX_EXTBUFF_HEVC_TILES};
434 };
435 template<>struct mfx_ext_buffer_id<mfxExtVP9Param> {
436     enum {id = MFX_EXTBUFF_VP9_PARAM};
437 };
438 template<>struct mfx_ext_buffer_id<mfxExtVideoSignalInfo> {
439     enum {id = MFX_EXTBUFF_VIDEO_SIGNAL_INFO};
440 };
441 template<>struct mfx_ext_buffer_id<mfxExtHEVCRegion> {
442     enum {id = MFX_EXTBUFF_HEVC_REGION};
443 };
444 template<>struct mfx_ext_buffer_id<mfxExtAVCRoundingOffset> {
445     enum {id = MFX_EXTBUFF_AVC_ROUNDING_OFFSET};
446 };
447 template<>struct mfx_ext_buffer_id<mfxExtVPPDenoise> {
448     enum {id = MFX_EXTBUFF_VPP_DENOISE};
449 };
450 template<>struct mfx_ext_buffer_id<mfxExtVPPProcAmp> {
451     enum {id = MFX_EXTBUFF_VPP_PROCAMP};
452 };
453 template<>struct mfx_ext_buffer_id<mfxExtVPPImageStab> {
454     enum {id = MFX_EXTBUFF_VPP_IMAGE_STABILIZATION};
455 };
456 template<>struct mfx_ext_buffer_id<mfxExtVPPVideoSignalInfo> {
457     enum {id = MFX_EXTBUFF_VPP_VIDEO_SIGNAL_INFO};
458 };
459 template<>struct mfx_ext_buffer_id<mfxExtVPPMirroring> {
460     enum {id = MFX_EXTBUFF_VPP_MIRRORING};
461 };
462 template<>struct mfx_ext_buffer_id<mfxExtVPPColorFill> {
463     enum {id = MFX_EXTBUFF_VPP_COLORFILL};
464 };
465 template<>struct mfx_ext_buffer_id<mfxExtVPPRotation> {
466     enum {id = MFX_EXTBUFF_VPP_ROTATION};
467 };
468 template<>struct mfx_ext_buffer_id<mfxExtVPPScaling> {
469     enum {id = MFX_EXTBUFF_VPP_SCALING};
470 };
471 template<>struct mfx_ext_buffer_id<mfxExtColorConversion> {
472     enum {id = MFX_EXTBUFF_VPP_COLOR_CONVERSION};
473 };
474 template<>struct mfx_ext_buffer_id<mfxExtPredWeightTable> {
475     enum {id = MFX_EXTBUFF_PRED_WEIGHT_TABLE};
476 };
477 template<>struct mfx_ext_buffer_id<mfxExtFeiDecStreamOut> {
478     enum {id = MFX_EXTBUFF_FEI_DEC_STREAM_OUT};
479 };
480 template<>struct mfx_ext_buffer_id<mfxExtFeiSliceHeader> {
481     enum {id = MFX_EXTBUFF_FEI_SLICE};
482 };
483 template<>struct mfx_ext_buffer_id<mfxExtFeiEncFrameCtrl> {
484     enum {id = MFX_EXTBUFF_FEI_ENC_CTRL};
485 };
486 template<>struct mfx_ext_buffer_id<mfxExtFeiEncMVPredictors> {
487     enum {id = MFX_EXTBUFF_FEI_ENC_MV_PRED};
488 };
489 template<>struct mfx_ext_buffer_id<mfxExtFeiRepackCtrl> {
490     enum {id = MFX_EXTBUFF_FEI_REPACK_CTRL};
491 };
492 template<>struct mfx_ext_buffer_id<mfxExtFeiEncMBCtrl> {
493     enum {id = MFX_EXTBUFF_FEI_ENC_MB};
494 };
495 template<>struct mfx_ext_buffer_id<mfxExtFeiEncQP> {
496     enum {id = MFX_EXTBUFF_FEI_ENC_QP};
497 };
498 template<>struct mfx_ext_buffer_id<mfxExtFeiEncMBStat> {
499     enum {id = MFX_EXTBUFF_FEI_ENC_MB_STAT};
500 };
501 template<>struct mfx_ext_buffer_id<mfxExtFeiEncMV> {
502     enum {id = MFX_EXTBUFF_FEI_ENC_MV};
503 };
504 template<>struct mfx_ext_buffer_id<mfxExtFeiPakMBCtrl> {
505     enum {id = MFX_EXTBUFF_FEI_PAK_CTRL};
506 };
507 template<>struct mfx_ext_buffer_id<mfxExtFeiRepackStat> {
508     enum {id = MFX_EXTBUFF_FEI_REPACK_STAT};
509 };
510 template<>struct mfx_ext_buffer_id<mfxExtFeiSPS> {
511     enum {id = MFX_EXTBUFF_FEI_SPS};
512 };
513 template<>struct mfx_ext_buffer_id<mfxExtFeiPPS > {
514     enum {id = MFX_EXTBUFF_FEI_PPS};
515 };
516 
517 constexpr uint16_t max_num_ext_buffers = 63 * 2; // '*2' is for max estimation if all extBuffer were 'paired'
518 
519 //helper function to initialize mfx ext buffer structure
520 template <class T>
521 void init_ext_buffer(T & ext_buffer)
522 {
523     memset(&ext_buffer, 0, sizeof(ext_buffer));
524     reinterpret_cast<mfxExtBuffer*>(&ext_buffer)->BufferId = mfx_ext_buffer_id<T>::id;
525     reinterpret_cast<mfxExtBuffer*>(&ext_buffer)->BufferSz = sizeof(ext_buffer);
526 }
527 
528 template <typename T> struct IsPairedMfxExtBuffer                 : std::false_type {};
529 template <> struct IsPairedMfxExtBuffer<mfxExtAVCRefListCtrl>     : std::true_type {};
530 template <> struct IsPairedMfxExtBuffer<mfxExtAVCRoundingOffset>  : std::true_type {};
531 template <> struct IsPairedMfxExtBuffer<mfxExtPredWeightTable>    : std::true_type {};
532 template <> struct IsPairedMfxExtBuffer<mfxExtFeiSliceHeader>     : std::true_type {};
533 template <> struct IsPairedMfxExtBuffer<mfxExtFeiEncFrameCtrl>    : std::true_type {};
534 template <> struct IsPairedMfxExtBuffer<mfxExtFeiEncMVPredictors> : std::true_type {};
535 template <> struct IsPairedMfxExtBuffer<mfxExtFeiRepackCtrl>      : std::true_type {};
536 template <> struct IsPairedMfxExtBuffer<mfxExtFeiEncMBCtrl>       : std::true_type {};
537 template <> struct IsPairedMfxExtBuffer<mfxExtFeiEncQP>           : std::true_type {};
538 template <> struct IsPairedMfxExtBuffer<mfxExtFeiEncMBStat>       : std::true_type {};
539 template <> struct IsPairedMfxExtBuffer<mfxExtFeiEncMV>           : std::true_type {};
540 template <> struct IsPairedMfxExtBuffer<mfxExtFeiPakMBCtrl>       : std::true_type {};
541 template <> struct IsPairedMfxExtBuffer<mfxExtFeiRepackStat>      : std::true_type {};
542 
543 template <typename R>
544 struct ExtParamAccessor
545 {
546 private:
547     using mfxExtBufferDoublePtr = mfxExtBuffer**;
548 public:
549     mfxU16& NumExtParam;
550     mfxExtBufferDoublePtr& ExtParam;
551     ExtParamAccessor(const R& r):
552         NumExtParam(const_cast<mfxU16&>(r.NumExtParam)),
553         ExtParam(const_cast<mfxExtBufferDoublePtr&>(r.ExtParam)) {}
554 };
555 
556 template <>
557 struct ExtParamAccessor<mfxFrameSurface1>
558 {
559 private:
560     using mfxExtBufferDoublePtr = mfxExtBuffer**;
561 public:
562     mfxU16& NumExtParam;
563     mfxExtBufferDoublePtr& ExtParam;
564     ExtParamAccessor(const mfxFrameSurface1& r):
565         NumExtParam(const_cast<mfxU16&>(r.Data.NumExtParam)),
566         ExtParam(const_cast<mfxExtBufferDoublePtr&>(r.Data.ExtParam)) {}
567 };
568 
569 /** ExtBufHolder is an utility class which
570  *  provide interface for mfxExtBuffer objects management in any mfx structure (e.g. mfxVideoParam)
571  */
572 template<typename T>
573 class ExtBufHolder : public T
574 {
575 public:
576     ExtBufHolder() : T()
577     {
578         m_ext_buf.reserve(max_num_ext_buffers);
579     }
580 
581     ~ExtBufHolder() // only buffers allocated by wrapper can be released
582     {
583         for (auto it = m_ext_buf.begin(); it != m_ext_buf.end(); it++ )
584         {
585             delete [] (mfxU8*)(*it);
586         }
587     }
588 
589     ExtBufHolder(const ExtBufHolder& ref)
590     {
591         m_ext_buf.reserve(max_num_ext_buffers);
592         *this = ref; // call to operator=
593     }
594 
595     ExtBufHolder& operator=(const ExtBufHolder& ref)
596     {
597         const T* src_base = &ref;
598         return operator=(*src_base);
599     }
600 
601     ExtBufHolder(const T& ref)
602     {
603         *this = ref; // call to operator=
604     }
605 
606     ExtBufHolder& operator=(const T& ref)
607     {
608         // copy content of main structure type T
609         T* dst_base = this;
610         const T* src_base = &ref;
611         *dst_base = *src_base;
612 
613         //remove all existing extension buffers
614         ClearBuffers();
615 
616         const auto ref_ = ExtParamAccessor<T>(ref);
617 
618         //reproduce list of extension buffers and copy its content
619         for (size_t i = 0; i < ref_.NumExtParam; ++i)
620         {
621             const auto src_buf = ref_.ExtParam[i];
622             if (!src_buf) throw mfxError(MFX_ERR_NULL_PTR, "Null pointer attached to source ExtParam");
623             if (!IsCopyAllowed(src_buf->BufferId))
624             {
625                 auto msg = "Deep copy of '" + Fourcc2Str(src_buf->BufferId) + "' extBuffer is not allowed";
626                 throw mfxError(MFX_ERR_UNDEFINED_BEHAVIOR, msg);
627             }
628 
629             // 'false' below is because here we just copy extBuffer's one by one
630             auto dst_buf = AddExtBuffer(src_buf->BufferId, src_buf->BufferSz, false);
631             // copy buffer content w/o restoring its type
632             memcpy((void*)dst_buf, (void*)src_buf, src_buf->BufferSz);
633         }
634 
635         return *this;
636     }
637 
638     ExtBufHolder(ExtBufHolder &&)             = default;
639     ExtBufHolder & operator= (ExtBufHolder&&) = default;
640 
641     // Always returns a valid pointer or throws an exception
642     template<typename TB>
643     TB* AddExtBuffer()
644     {
645         mfxExtBuffer* b = AddExtBuffer(mfx_ext_buffer_id<TB>::id, sizeof(TB), IsPairedMfxExtBuffer<TB>::value);
646         return (TB*)b;
647     }
648 
649     template<typename TB>
650     void RemoveExtBuffer()
651     {
652         auto it = std::find_if(m_ext_buf.begin(), m_ext_buf.end(), CmpExtBufById(mfx_ext_buffer_id<TB>::id));
653         if (it != m_ext_buf.end())
654         {
655             delete [] (mfxU8*)(*it);
656             it = m_ext_buf.erase(it);
657 
658             if (IsPairedMfxExtBuffer<TB>::value)
659             {
660                 if (it == m_ext_buf.end() || (*it)->BufferId != mfx_ext_buffer_id<TB>::id)
661                     throw mfxError(MFX_ERR_NULL_PTR, "RemoveExtBuffer: ExtBuffer's parity has been broken");
662 
663                 delete [] (mfxU8*)(*it);
664                 m_ext_buf.erase(it);
665             }
666 
667             RefreshBuffers();
668         }
669     }
670 
671     template <typename TB>
672     TB* GetExtBuffer(uint32_t fieldId = 0) const
673     {
674         return (TB*)FindExtBuffer(mfx_ext_buffer_id<TB>::id, fieldId);
675     }
676 
677     template <typename TB>
678     operator TB*()
679     {
680         return (TB*)FindExtBuffer(mfx_ext_buffer_id<TB>::id, 0);
681     }
682 
683     template <typename TB>
684     operator TB*() const
685     {
686         return (TB*)FindExtBuffer(mfx_ext_buffer_id<TB>::id, 0);
687     }
688 
689 private:
690 
691     mfxExtBuffer* AddExtBuffer(mfxU32 id, mfxU32 size, bool isPairedExtBuffer)
692     {
693         if (!size || !id)
694             throw mfxError(MFX_ERR_NULL_PTR, "AddExtBuffer: wrong size or id!");
695 
696         auto it = std::find_if(m_ext_buf.begin(), m_ext_buf.end(), CmpExtBufById(id));
697         if (it == m_ext_buf.end())
698         {
699             auto buf = (mfxExtBuffer*)new mfxU8[size];
700             memset(buf, 0, size);
701             m_ext_buf.push_back(buf);
702 
703             buf->BufferId = id;
704             buf->BufferSz = size;
705 
706             if (isPairedExtBuffer)
707             {
708                 // Allocate the other mfxExtBuffer _right_after_ the first one ...
709                 buf = (mfxExtBuffer*)new mfxU8[size];
710                 memset(buf, 0, size);
711                 m_ext_buf.push_back(buf);
712 
713                 buf->BufferId = id;
714                 buf->BufferSz = size;
715 
716                 RefreshBuffers();
717                 return m_ext_buf[m_ext_buf.size() - 2]; // ... and return a pointer to the first one
718             }
719 
720             RefreshBuffers();
721             return m_ext_buf.back();
722         }
723 
724         return *it;
725     }
726 
727     mfxExtBuffer* FindExtBuffer(mfxU32 id, uint32_t fieldId) const
728     {
729         auto it = std::find_if(m_ext_buf.begin(), m_ext_buf.end(), CmpExtBufById(id));
730         if (fieldId && it != m_ext_buf.end())
731         {
732             ++it;
733             return it != m_ext_buf.end() ? *it : nullptr;
734         }
735         return it != m_ext_buf.end() ? *it : nullptr;
736     }
737 
738     void RefreshBuffers()
739     {
740         auto this_ = ExtParamAccessor<T>(*this);
741         this_.NumExtParam = static_cast<mfxU16>(m_ext_buf.size());
742         this_.ExtParam    = this_.NumExtParam ? m_ext_buf.data() : nullptr;
743     }
744 
745     void ClearBuffers()
746     {
747         if (m_ext_buf.size())
748         {
749             for (auto it = m_ext_buf.begin(); it != m_ext_buf.end(); it++ )
750             {
751                 delete [] (mfxU8*)(*it);
752             }
753             m_ext_buf.clear();
754         }
755         RefreshBuffers();
756     }
757 
758     bool IsCopyAllowed(mfxU32 id)
759     {
760         static const mfxU32 allowed[] = {
761             MFX_EXTBUFF_CODING_OPTION,
762             MFX_EXTBUFF_CODING_OPTION2,
763             MFX_EXTBUFF_CODING_OPTION3,
764             MFX_EXTBUFF_FEI_PARAM,
765             MFX_EXTBUFF_BRC,
766             MFX_EXTBUFF_HEVC_PARAM,
767             MFX_EXTBUFF_VP9_PARAM,
768             MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION,
769             MFX_EXTBUFF_FEI_PPS,
770             MFX_EXTBUFF_FEI_SPS,
771             MFX_EXTBUFF_LOOKAHEAD_CTRL,
772             MFX_EXTBUFF_LOOKAHEAD_STAT,
773             MFX_EXTBUFF_DEC_VIDEO_PROCESSING
774         };
775 
776         auto it = std::find_if(std::begin(allowed), std::end(allowed),
777                                [&id](const mfxU32 allowed_id)
778                                {
779                                    return allowed_id == id;
780                                });
781         return it != std::end(allowed);
782     }
783 
784     struct CmpExtBufById
785     {
786         mfxU32 id;
787 
788         CmpExtBufById(mfxU32 _id)
789             : id(_id)
790         { };
791 
792         bool operator () (mfxExtBuffer* b)
793         {
794             return  (b && b->BufferId == id);
795         };
796     };
797 
798     static std::string Fourcc2Str(mfxU32 fourcc)
799     {
800         std::string s;
801         for (size_t i = 0; i < 4; i++)
802         {
803             s.push_back(*(i + (char*)&fourcc));
804         }
805         return s;
806     }
807 
808     std::vector<mfxExtBuffer*> m_ext_buf;
809 };
810 
811 using MfxVideoParamsWrapper = ExtBufHolder<mfxVideoParam>;
812 using mfxEncodeCtrlWrap     = ExtBufHolder<mfxEncodeCtrl>;
813 using mfxInitParamlWrap     = ExtBufHolder<mfxInitParam>;
814 using mfxFrameSurfaceWrap   = ExtBufHolder<mfxFrameSurface1>;
815 
816 class mfxBitstreamWrapper : public ExtBufHolder<mfxBitstream>
817 {
818     typedef ExtBufHolder<mfxBitstream> base;
819 public:
820     mfxBitstreamWrapper()
821         : base()
822     {}
823 
824     mfxBitstreamWrapper(mfxU32 n_bytes)
825         : base()
826     {
827         Extend(n_bytes);
828     }
829 
830     mfxBitstreamWrapper(const mfxBitstreamWrapper & bs_wrapper)
831         : base(bs_wrapper)
832         , m_data(bs_wrapper.m_data)
833     {
834         Data = m_data.data();
835     }
836 
837     mfxBitstreamWrapper& operator=(mfxBitstreamWrapper const& bs_wrapper)
838     {
839         mfxBitstreamWrapper tmp(bs_wrapper);
840 
841         *this = std::move(tmp);
842 
843         return *this;
844     }
845 
846     mfxBitstreamWrapper(mfxBitstreamWrapper && bs_wrapper)             = default;
847     mfxBitstreamWrapper & operator= (mfxBitstreamWrapper&& bs_wrapper) = default;
848     ~mfxBitstreamWrapper()                                             = default;
849 
850     void Extend(mfxU32 n_bytes)
851     {
852         if (MaxLength >= n_bytes)
853             return;
854 
855         m_data.resize(n_bytes);
856 
857         Data      = m_data.data();
858         MaxLength = n_bytes;
859     }
860 private:
861     std::vector<mfxU8> m_data;
862 };
863 
864 class CSmplYUVReader
865 {
866 public :
867     typedef std::list<msdk_string>::iterator ls_iterator;
868     CSmplYUVReader();
869     virtual ~CSmplYUVReader();
870 
871     virtual void Close();
872     virtual mfxStatus Init(std::list<msdk_string> inputs, mfxU32 ColorFormat, bool shouldShiftP010=false);
873     virtual mfxStatus SkipNframesFromBeginning(mfxU16 w, mfxU16 h, mfxU32 viewId, mfxU32 nframes);
874     virtual mfxStatus LoadNextFrame(mfxFrameSurface1* pSurface);
875     virtual void Reset();
876     mfxU32 m_ColorFormat; // color format of input YUV data, YUV420 or NV12
877 
878 protected:
879 
880     std::vector<FILE*> m_files;
881 
882     bool shouldShift10BitsHigh;
883     bool m_bInited;
884 };
885 
886 class CSmplBitstreamWriter
887 {
888 public :
889 
890     CSmplBitstreamWriter();
891     virtual ~CSmplBitstreamWriter();
892 
893     virtual mfxStatus Init(const msdk_char *strFileName);
894     virtual mfxStatus WriteNextFrame(mfxBitstream *pMfxBitstream, bool isPrint = true);
895     virtual mfxStatus Reset();
896     virtual void Close();
897     mfxU32 m_nProcessedFramesNum;
898 
899 protected:
900     FILE*       m_fSource;
901     bool        m_bInited;
902     msdk_string m_sFile;
903 };
904 
905 class CSmplYUVWriter
906 {
907 public :
908 
909     CSmplYUVWriter();
910     virtual ~CSmplYUVWriter();
911 
912     virtual void      Close();
913     virtual mfxStatus Init(const msdk_char *strFileName, const mfxU32 numViews);
914     virtual mfxStatus Reset();
915     virtual mfxStatus WriteNextFrame(mfxFrameSurface1 *pSurface);
916     virtual mfxStatus WriteNextFrameI420(mfxFrameSurface1 *pSurface);
917 
918     void SetMultiView() { m_bIsMultiView = true; }
919 
920 protected:
921     FILE         *m_fDest, **m_fDestMVC;
922     bool         m_bInited, m_bIsMultiView;
923     mfxU32       m_numCreatedFiles;
924     msdk_string  m_sFile;
925     mfxU32       m_nViews;
926 };
927 
928 class CSmplBitstreamReader
929 {
930 public :
931 
932     CSmplBitstreamReader();
933     virtual ~CSmplBitstreamReader();
934 
935     //resets position to file begin
936     virtual void      Reset();
937     virtual void      Close();
938     virtual mfxStatus Init(const msdk_char *strFileName);
939     virtual mfxStatus ReadNextFrame(mfxBitstream *pBS);
940 
941 protected:
942     FILE*     m_fSource;
943     bool      m_bInited;
944 };
945 
946 class CH264FrameReader : public CSmplBitstreamReader
947 {
948 public:
949     CH264FrameReader();
950     virtual ~CH264FrameReader();
951 
952     /** Free resources.*/
953     virtual void      Close();
954     virtual mfxStatus Init(const msdk_char *strFileName);
955     virtual mfxStatus ReadNextFrame(mfxBitstream *pBS);
956 
957 private:
958     mfxBitstream *m_processedBS;
959     // input bit stream
960     mfxBitstreamWrapper m_originalBS;
961 
962     mfxStatus PrepareNextFrame(mfxBitstream *in, mfxBitstream **out);
963 
964     // is stream ended
965     bool m_isEndOfStream;
966 
967     std::unique_ptr<AbstractSplitter> m_pNALSplitter;
968     FrameSplitterInfo *m_frame;
969     mfxU8 *m_plainBuffer;
970     mfxU32 m_plainBufferSize;
971     mfxBitstream m_outBS;
972 };
973 
974 //provides output bistream with at least 1 frame, reports about error
975 class CJPEGFrameReader : public CSmplBitstreamReader
976 {
977     enum JPEGMarker
978     {
979         SOI=0xD8FF,
980         EOI=0xD9FF
981     };
982 public:
983     virtual mfxStatus ReadNextFrame(mfxBitstream *pBS);
984 protected:
985     mfxU32 FindMarker(mfxBitstream *pBS,mfxU32 startOffset,JPEGMarker marker);
986 };
987 
988 //appends output bistream with exactly 1 frame, reports about error
989 class CIVFFrameReader : public CSmplBitstreamReader
990 {
991 public:
992     CIVFFrameReader();
993     virtual void      Reset();
994     virtual mfxStatus Init(const msdk_char *strFileName);
995     virtual mfxStatus ReadNextFrame(mfxBitstream *pBS);
996 
997 protected:
998 
999       /*bytes 0-3    signature: 'DKIF'
1000     bytes 4-5    version (should be 0)
1001     bytes 6-7    length of header in bytes
1002     bytes 8-11   codec FourCC (e.g., 'VP80')
1003     bytes 12-13  width in pixels
1004     bytes 14-15  height in pixels
1005     bytes 16-19  frame rate
1006     bytes 20-23  time scale
1007     bytes 24-27  number of frames in file
1008     bytes 28-31  unused*/
1009 
1010     struct DKIFHrd
1011     {
1012         mfxU32 dkif;
1013         mfxU16 version;
1014         mfxU16 header_len;
1015         mfxU32 codec_FourCC;
1016         mfxU16 width;
1017         mfxU16 height;
1018         mfxU32 frame_rate;
1019         mfxU32 time_scale;
1020         mfxU32 num_frames;
1021         mfxU32 unused;
1022     }m_hdr;
1023     mfxStatus ReadHeader();
1024 };
1025 
1026 // writes bitstream to duplicate-file & supports joining
1027 // (for ViewOutput encoder mode)
1028 class CSmplBitstreamDuplicateWriter : public CSmplBitstreamWriter
1029 {
1030 public:
1031     CSmplBitstreamDuplicateWriter();
1032 
1033     virtual mfxStatus InitDuplicate(const msdk_char *strFileName);
1034     virtual mfxStatus JoinDuplicate(CSmplBitstreamDuplicateWriter *pJoinee);
1035     virtual mfxStatus WriteNextFrame(mfxBitstream *pMfxBitstream, bool isPrint = true);
1036     virtual void Close();
1037 protected:
1038     FILE*     m_fSourceDuplicate;
1039     bool      m_bJoined;
1040 };
1041 
1042 //timeinterval calculation helper
1043 
1044 template <int tag = 0>
1045 class CTimeInterval : private no_copy
1046 {
1047     static double g_Freq;
1048     double       &m_start;
1049     double        m_own;//reference to this if external counter not required
1050     //since QPC functions are quite slow it makes sense to optionally enable them
1051     bool         m_bEnable;
1052     msdk_tick    m_StartTick;
1053 
1054 public:
1055     CTimeInterval(double &dRef , bool bEnable = true)
1056         : m_start(dRef)
1057         , m_bEnable(bEnable)
1058         , m_StartTick(0)
1059     {
1060         if (!m_bEnable)
1061             return;
1062         Initialize();
1063     }
1064     CTimeInterval(bool bEnable = true)
1065         : m_start(m_own)
1066         , m_own()
1067         , m_bEnable(bEnable)
1068         , m_StartTick(0)
1069     {
1070         if (!m_bEnable)
1071             return;
1072         Initialize();
1073     }
1074 
1075     //updates external value with current time
1076     double Commit()
1077     {
1078         if (!m_bEnable)
1079             return 0.0;
1080 
1081         if (0.0 != g_Freq)
1082         {
1083             m_start = MSDK_GET_TIME(msdk_time_get_tick(), m_StartTick, g_Freq);
1084         }
1085         return m_start;
1086     }
1087     //last comitted value
1088     double Last()
1089     {
1090         return m_start;
1091     }
1092     ~CTimeInterval()
1093     {
1094         Commit();
1095     }
1096 private:
1097     void Initialize()
1098     {
1099         if (0.0 == g_Freq)
1100         {
1101             g_Freq = (double)msdk_time_get_frequency();
1102         }
1103         m_StartTick = msdk_time_get_tick();
1104     }
1105 };
1106 
1107 template <int tag>double CTimeInterval<tag>::g_Freq = 0.0f;
1108 
1109 /** Helper class to measure execution time of some code. Use this class
1110  * if you need manual measurements.
1111  *
1112  * Usage example:
1113  * {
1114  *   CTimer timer;
1115  *   msdk_tick summary_tick;
1116  *
1117  *   timer.Start()
1118  *   function_to_measure();
1119  *   summary_tick = timer.GetDelta();
1120  *   printf("Elapsed time 1: %f\n", timer.GetTime());
1121  *   ...
1122  *   if (condition) timer.Start();
1123      function_to_measure();
1124  *   if (condition) {
1125  *     summary_tick += timer.GetDelta();
1126  *     printf("Elapsed time 2: %f\n", timer.GetTime();
1127  *   }
1128  *   printf("Overall time: %f\n", CTimer::ConvertToSeconds(summary_tick);
1129  * }
1130  */
1131 class CTimer
1132 {
1133 public:
1134     CTimer():
1135         start(0)
1136     {
1137     }
1138     static msdk_tick GetFrequency()
1139     {
1140         if (!frequency) frequency = msdk_time_get_frequency();
1141         return frequency;
1142     }
1143     static mfxF64 ConvertToSeconds(msdk_tick elapsed)
1144     {
1145         return MSDK_GET_TIME(elapsed, 0, GetFrequency());
1146     }
1147 
1148     inline void Start()
1149     {
1150         start = msdk_time_get_tick();
1151     }
1152     inline msdk_tick GetDelta()
1153     {
1154         return msdk_time_get_tick() - start;
1155     }
1156     inline mfxF64 GetTime()
1157     {
1158         return MSDK_GET_TIME(msdk_time_get_tick(), start, GetFrequency());
1159     }
1160 
1161 protected:
1162     static msdk_tick frequency;
1163     msdk_tick start;
1164 private:
1165     CTimer(const CTimer&);
1166     void operator=(const CTimer&);
1167 };
1168 
1169 /** Helper class to measure overall execution time of some code. Use this
1170  * class if you want to measure execution time of the repeatedly executed
1171  * code.
1172  *
1173  * Usage example 1:
1174  *
1175  * msdk_tick summary_tick = 0;
1176  *
1177  * void function() {
1178  *
1179  * {
1180  *   CAutoTimer timer(&summary_tick);
1181  *   ...
1182  * }
1183  *     ...
1184  * int main() {
1185  *   for (;condition;) {
1186  *     function();
1187  *   }
1188  *   printf("Elapsed time: %f\n", CTimer::ConvertToSeconds(summary_tick);
1189  *   return 0;
1190  * }
1191  *
1192  * Usage example 2:
1193  * {
1194  *   msdk_tick summary_tick = 0;
1195  *
1196  *   {
1197  *     CAutoTimer timer(&summary_tick);
1198  *
1199  *     for (;condition;) {
1200  *       ...
1201  *       {
1202  *         function_to_measure();
1203  *         timer.Sync();
1204  *         printf("Progress: %f\n", CTimer::ConvertToSeconds(summary_tick);
1205  *       }
1206  *       ...
1207  *     }
1208  *   }
1209  *   printf("Elapsed time: %f\n", CTimer::ConvertToSeconds(summary_tick);
1210  * }
1211  *
1212  */
1213 class CAutoTimer
1214 {
1215 public:
1216     CAutoTimer(msdk_tick& _elapsed):
1217         elapsed(_elapsed),
1218         start(0)
1219     {
1220         elapsed = _elapsed;
1221         start = msdk_time_get_tick();
1222     }
1223     ~CAutoTimer()
1224     {
1225         elapsed += msdk_time_get_tick() - start;
1226     }
1227     msdk_tick Sync()
1228     {
1229         msdk_tick cur = msdk_time_get_tick();
1230         elapsed += cur - start;
1231         start = cur;
1232         return elapsed;
1233     }
1234 protected:
1235     msdk_tick& elapsed;
1236     msdk_tick start;
1237 private:
1238     CAutoTimer(const CAutoTimer&);
1239     void operator=(const CAutoTimer&);
1240 };
1241 
1242 mfxStatus ConvertFrameRate(mfxF64 dFrameRate, mfxU32* pnFrameRateExtN, mfxU32* pnFrameRateExtD);
1243 mfxF64 CalculateFrameRate(mfxU32 nFrameRateExtN, mfxU32 nFrameRateExtD);
1244 
1245 template <class T>
1246 mfxU16 GetFreeSurfaceIndex(T* pSurfacesPool, mfxU16 nPoolSize)
1247 {
1248     constexpr mfxU16 MSDK_INVALID_SURF_IDX = 0xffff;
1249 
1250     if (pSurfacesPool)
1251     {
1252         for (mfxU16 i = 0; i < nPoolSize; i++)
1253         {
1254             if (0 == pSurfacesPool[i].Data.Locked)
1255             {
1256                 return i;
1257             }
1258         }
1259     }
1260     return MSDK_INVALID_SURF_IDX;
1261 }
1262 
1263 mfxU16 GetFreeSurface(mfxFrameSurface1* pSurfacesPool, mfxU16 nPoolSize);
1264 void FreeSurfacePool(mfxFrameSurface1* pSurfacesPool, mfxU16 nPoolSize);
1265 
1266 mfxU16 CalculateDefaultBitrate(mfxU32 nCodecId, mfxU32 nTargetUsage, mfxU32 nWidth, mfxU32 nHeight, mfxF64 dFrameRate);
1267 
1268 //serialization fnc set
1269 std::basic_string<msdk_char> CodecIdToStr(mfxU32 nFourCC);
1270 mfxU16 StrToTargetUsage(msdk_string strInput);
1271 const msdk_char* TargetUsageToStr(mfxU16 tu);
1272 const msdk_char* ColorFormatToStr(mfxU32 format);
1273 const msdk_char* MfxStatusToStr(mfxStatus sts);
1274 
1275 // sets bitstream->PicStruct parsing first APP0 marker in bitstream
1276 mfxStatus MJPEG_AVI_ParsePicStruct(mfxBitstream *bitstream);
1277 
1278 // For MVC encoding/decoding purposes
1279 std::basic_string<msdk_char> FormMVCFileName(const msdk_char *strFileName, const mfxU32 numView);
1280 
1281 //piecewise linear function for bitrate approximation
1282 class PartiallyLinearFNC
1283 {
1284     mfxF64 *m_pX;
1285     mfxF64 *m_pY;
1286     mfxU32  m_nPoints;
1287     mfxU32  m_nAllocated;
1288 
1289 public:
1290     PartiallyLinearFNC();
1291     ~PartiallyLinearFNC();
1292 
1293     void AddPair(mfxF64 x, mfxF64 y);
1294     mfxF64 at(mfxF64);
1295 private:
1296     DISALLOW_COPY_AND_ASSIGN(PartiallyLinearFNC);
1297 };
1298 
1299 // function for getting a pointer to a specific external buffer from the array
1300 mfxExtBuffer* GetExtBuffer(mfxExtBuffer** ebuffers, mfxU32 nbuffers, mfxU32 BufferId);
1301 
1302 // returns false if buf length is insufficient, otherwise
1303 // skips step bytes in buf with specified length and returns true
1304 template <typename Buf_t, typename Length_t>
1305 bool skip(const Buf_t *&buf, Length_t &length, Length_t step)
1306 {
1307     if (length < step)
1308         return false;
1309 
1310     buf    += step;
1311     length -= step;
1312 
1313     return true;
1314 }
1315 
1316 //do not link MediaSDK dispatched if class not used
1317 struct MSDKAdapter {
1318     // returns the number of adapter associated with MSDK session, 0 for SW session
1319     static mfxU32 GetNumber(mfxSession session, mfxIMPL implVia = 0) {
1320         mfxU32 adapterNum = 0; // default
1321         mfxIMPL impl = MFX_IMPL_SOFTWARE; // default in case no HW IMPL is found
1322 
1323         // we don't care for error codes in further code; if something goes wrong we fall back to the default adapter
1324         if (session)
1325         {
1326             MFXQueryIMPL(session, &impl);
1327         }
1328         else
1329         {
1330             // an auxiliary session, internal for this function
1331             mfxSession auxSession;
1332             memset(&auxSession, 0, sizeof(auxSession));
1333 
1334             mfxVersion ver = { {1, 1 }}; // minimum API version which supports multiple devices
1335             MFXInit(MFX_IMPL_HARDWARE_ANY | implVia, &ver, &auxSession);
1336             MFXQueryIMPL(auxSession, &impl);
1337             MFXClose(auxSession);
1338         }
1339 
1340         // extract the base implementation type
1341         mfxIMPL baseImpl = MFX_IMPL_BASETYPE(impl);
1342 
1343         const struct
1344         {
1345             // actual implementation
1346             mfxIMPL impl;
1347             // adapter's number
1348             mfxU32 adapterID;
1349 
1350         } implTypes[] = {
1351             {MFX_IMPL_HARDWARE, 0},
1352             {MFX_IMPL_SOFTWARE, 0},
1353             {MFX_IMPL_HARDWARE2, 1},
1354             {MFX_IMPL_HARDWARE3, 2},
1355             {MFX_IMPL_HARDWARE4, 3}
1356         };
1357 
1358 
1359         // get corresponding adapter number
1360         for (mfxU8 i = 0; i < sizeof(implTypes)/sizeof(*implTypes); i++)
1361         {
1362             if (implTypes[i].impl == baseImpl)
1363             {
1364                 adapterNum = implTypes[i].adapterID;
1365                 break;
1366             }
1367         }
1368 
1369         return adapterNum;
1370     }
1371 };
1372 
1373 struct APIChangeFeatures {
1374     bool JpegDecode;
1375     bool JpegEncode;
1376     bool MVCDecode;
1377     bool MVCEncode;
1378     bool IntraRefresh;
1379     bool LowLatency;
1380     bool ViewOutput;
1381     bool LookAheadBRC;
1382     bool AudioDecode;
1383     bool SupportCodecPluginAPI;
1384 };
1385 
1386 inline
1387 mfxU32 MakeVersion(mfxU16 major, mfxU16 minor)
1388 {
1389     return major * 1000 + minor;
1390 }
1391 
1392 mfxVersion getMinimalRequiredVersion(const APIChangeFeatures &features);
1393 
1394 enum msdkAPIFeature {
1395     MSDK_FEATURE_NONE,
1396     MSDK_FEATURE_MVC,
1397     MSDK_FEATURE_JPEG_DECODE,
1398     MSDK_FEATURE_LOW_LATENCY,
1399     MSDK_FEATURE_MVC_VIEWOUTPUT,
1400     MSDK_FEATURE_JPEG_ENCODE,
1401     MSDK_FEATURE_LOOK_AHEAD,
1402     MSDK_FEATURE_PLUGIN_API
1403 };
1404 
1405 /* Returns true if feature is supported in the given API version */
1406 bool CheckVersion(mfxVersion* version, msdkAPIFeature feature);
1407 
1408 void ConfigureAspectRatioConversion(mfxInfoVPP* pVppInfo);
1409 
1410 void SEICalcSizeType(std::vector<mfxU8>& data, mfxU16 type, mfxU32 size);
1411 
1412 mfxU8 Char2Hex(msdk_char ch);
1413 
1414 enum MsdkTraceLevel {
1415     MSDK_TRACE_LEVEL_SILENT = -1,
1416     MSDK_TRACE_LEVEL_CRITICAL = 0,
1417     MSDK_TRACE_LEVEL_ERROR = 1,
1418     MSDK_TRACE_LEVEL_WARNING = 2,
1419     MSDK_TRACE_LEVEL_INFO = 3,
1420     MSDK_TRACE_LEVEL_DEBUG = 4,
1421 };
1422 
1423 msdk_string NoFullPath(const msdk_string &);
1424 int  msdk_trace_get_level();
1425 void msdk_trace_set_level(int);
1426 bool msdk_trace_is_printable(int);
1427 
1428 msdk_ostream & operator <<(msdk_ostream & os, MsdkTraceLevel tt);
1429 
1430 template<typename T>
1431     mfxStatus msdk_opt_read(const msdk_char* string, T& value);
1432 
1433 template<size_t S>
1434     mfxStatus msdk_opt_read(const msdk_char* string, msdk_char (&value)[S])
1435     {
1436         if (!S)
1437         {
1438             return MFX_ERR_UNKNOWN;
1439         }
1440         value[0]=0;
1441     #if defined(_WIN32) || defined(_WIN64)
1442         value[S - 1] = 0;
1443         return (0 == _tcsncpy_s(value, string,S-1))? MFX_ERR_NONE: MFX_ERR_UNKNOWN;
1444     #else
1445         if (strlen(string) < S) {
1446             strncpy(value, string, S-1);
1447             value[S - 1] = 0;
1448             return MFX_ERR_NONE;
1449         }
1450         return MFX_ERR_UNKNOWN;
1451     #endif
1452     }
1453 
1454 template<typename T>
1455     inline mfxStatus msdk_opt_read(const msdk_string& string, T& value)
1456     {
1457         return msdk_opt_read(string.c_str(), value);
1458     }
1459 
1460 mfxStatus StrFormatToCodecFormatFourCC(msdk_char* strInput, mfxU32 &codecFormat);
1461 msdk_string StatusToString(mfxStatus sts);
1462 mfxI32 getMonitorType(msdk_char* str);
1463 
1464 void WaitForDeviceToBecomeFree(MFXVideoSession& session, mfxSyncPoint& syncPoint, mfxStatus& currentStatus);
1465 
1466 mfxU16 FourCCToChroma(mfxU32 fourCC);
1467 
1468 class FPSLimiter
1469 {
1470 public:
1471     FPSLimiter()  = default;
1472     ~FPSLimiter() = default;
1473     void Reset(mfxU32 fps)
1474     {
1475         m_delayTicks = fps ? msdk_time_get_frequency() / fps : 0;
1476     }
1477     void Work()
1478     {
1479         msdk_tick current_tick = msdk_time_get_tick();
1480         while( m_delayTicks && (m_startTick + m_delayTicks > current_tick) )
1481         {
1482             msdk_tick left_tick = m_startTick + m_delayTicks - current_tick;
1483             uint32_t sleepTime = (uint32_t)(left_tick * 1000 / msdk_time_get_frequency());
1484             MSDK_SLEEP(sleepTime);
1485             current_tick = msdk_time_get_tick();
1486         };
1487         m_startTick = msdk_time_get_tick();
1488     }
1489 
1490 protected:
1491     msdk_tick               m_startTick  = 0;
1492     msdk_tick               m_delayTicks = 0;
1493 };
1494 
1495 #endif //__SAMPLE_UTILS_H__
1496