1 // Copyright (c) 2019 Intel Corporation
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 #include <vector>
22 #include <unordered_map>
23 #include <algorithm>
24 #include <numeric>
25 
26 #include "common_utils.h"
27 #include "cmd_options.h"
28 
usage(CmdOptionsCtx * ctx)29 static void usage(CmdOptionsCtx* ctx)
30 {
31     printf(
32         "Transcodes INPUT and optionally writes OUTPUT.\n"
33         "\n"
34         "Usage: %s [options] INPUT [OUTPUT]\n", ctx->program);
35 }
36 
37 // ------------  H.264 bit stream FRAME reader utility -------------
38 mfxBitstream lastBs = { };
39 
40 std::vector < mfxU8 > bsBuffer;
41 
FindSlice(mfxBitstream * pBS,int & pos2ndnalu)42 int FindSlice(mfxBitstream* pBS, int& pos2ndnalu)
43 {
44     int nNalu = 0;
45     size_t i = 0;
46     for (i = pBS->DataOffset;
47          nNalu < 2 && i + 3 < pBS->DataOffset + pBS->DataLength; i++) {
48         if (pBS->Data[i] == 0 && pBS->Data[i + 1] == 0
49             && pBS->Data[i + 2] == 1) {
50             if (0 == nNalu) {
51                 int nType = pBS->Data[i + 3] & 0x1F;
52 
53                 if (nType == 1 ||       //slice
54                     nType == 5) //IDR slice
55                     nNalu++;
56             } else {
57                 //any backend nalu
58                 nNalu++;
59             }
60         }
61     }
62     if (nNalu == 2) {
63         pos2ndnalu = (int)i;
64     }
65     return nNalu;
66 }
67 
MoveMfxBitstream(mfxBitstream * pTarget,mfxBitstream * pSrc,mfxU32 nBytes)68 mfxStatus MoveMfxBitstream(mfxBitstream* pTarget, mfxBitstream* pSrc,
69                            mfxU32 nBytes)
70 {
71     MSDK_CHECK_POINTER(pTarget, MFX_ERR_NULL_PTR);
72     MSDK_CHECK_POINTER(pSrc, MFX_ERR_NULL_PTR);
73 
74     mfxU32 nFreeSpaceTail = pTarget->MaxLength - pTarget->DataOffset - pTarget->DataLength;
75     mfxU32 nFreeSpace = pTarget->MaxLength - pTarget->DataLength;
76 
77     if (!(pSrc->DataLength >= nBytes))
78         return MFX_ERR_MORE_DATA;
79     if (!(nFreeSpace >= nBytes))
80         return MFX_ERR_NOT_ENOUGH_BUFFER;
81 
82     if (nFreeSpaceTail < nBytes) {
83         memmove(pTarget->Data, pTarget->Data + pTarget->DataOffset, pTarget->DataLength);
84         pTarget->DataOffset = 0;
85     }
86     memcpy(pTarget->Data + pTarget->DataOffset, pSrc->Data + pSrc->DataOffset, nBytes);
87     pTarget->DataLength += nBytes;
88     pSrc->DataLength -= nBytes;
89     pSrc->DataOffset += nBytes;
90 
91     return MFX_ERR_NONE;
92 }
93 
ReadNextBitStreamFrame(mfxBitstream * pBS,FILE * fSource)94 mfxStatus ReadNextBitStreamFrame(mfxBitstream* pBS, FILE* fSource)
95 {
96     MSDK_CHECK_POINTER(pBS, MFX_ERR_NULL_PTR);
97     pBS->DataFlag = MFX_BITSTREAM_COMPLETE_FRAME;
98 
99     if (lastBs.Data == NULL) {
100         //alloc same bitstream
101         bsBuffer.resize(pBS->MaxLength);
102         lastBs.Data = &bsBuffer.front();
103         lastBs.MaxLength = pBS->MaxLength;
104     }
105     //checking for available nalu
106     int nNalu;
107     int pos2ndNaluStart = 0;
108     //check nalu in input bs, it always=1 if decoder didnt take a frame
109     if ((nNalu = FindSlice(pBS, pos2ndNaluStart)) < 1) {
110         //copy nalu from internal buffer
111         if ((nNalu = FindSlice(&lastBs, pos2ndNaluStart)) < 2) {
112             mfxStatus sts = ReadBitStreamData(&lastBs, fSource);
113             if (MFX_ERR_MORE_DATA == sts) {
114                 //lets feed last nalu if present
115                 if (nNalu == 1) {
116                     sts = MoveMfxBitstream(pBS, &lastBs, lastBs.DataLength);
117                     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
118 
119                     return MFX_ERR_NONE;
120                 }
121 
122                 return MFX_ERR_MORE_DATA;
123             }
124             //buffer is to small to accept whole frame
125             if (!(FindSlice(&lastBs, pos2ndNaluStart) == 2))
126                 return MFX_ERR_NOT_ENOUGH_BUFFER;
127         }
128         mfxU32 naluLen = pos2ndNaluStart - lastBs.DataOffset;
129         mfxStatus sts = MoveMfxBitstream(pBS, &lastBs, naluLen);
130         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
131     }
132 
133     return MFX_ERR_NONE;
134 }
135 
136 // ---------------------------------------------------------------------------
137 
main(int argc,char ** argv)138 int main(int argc, char** argv)
139 {
140     mfxStatus sts = MFX_ERR_NONE;
141     bool bEnableOutput; // if true, removes all output bitsteam file writing and printing the progress
142     CmdOptions options;
143 
144     // =====================================================================
145     // Intel Media SDK transcode opaque pipeline setup
146     // - In this example we are decoding and encoding an AVC (H.264) stream
147     // - Opaque transcode pipeline configured for low latency
148     // - Simplistic latency measurement technique used
149     //
150 
151     // Read options from the command line (if any is given)
152     memset(&options, 0, sizeof(CmdOptions));
153     options.ctx.options = OPTIONS_TRANSCODE | OPTION_MEASURE_LATENCY;
154     options.ctx.usage = usage;
155     // Set default values:
156     options.values.impl = MFX_IMPL_AUTO_ANY;
157     options.values.MeasureLatency = true;
158 
159     // here we parse options
160     ParseOptions(argc, argv, &options);
161 
162     if (!options.values.Bitrate) {
163         printf("error: bitrate not set (mandatory)\n");
164         return -1;
165     }
166     if (!options.values.FrameRateN || !options.values.FrameRateD) {
167         printf("error: framerate not set (mandatory)\n");
168         return -1;
169     }
170     if (!options.values.SourceName[0]) {
171         printf("error: source file name not set (mandatory)\n");
172         return -1;
173     }
174 
175     bEnableOutput = (options.values.SinkName[0] != '\0');
176 
177     // Open input H.264 elementary stream (ES) file
178     fileUniPtr fSource(OpenFile(options.values.SourceName, "rb"), &CloseFile);
179     MSDK_CHECK_POINTER(fSource, MFX_ERR_NULL_PTR);
180 
181     // Create output elementary stream (ES) H.264 file
182     fileUniPtr fSink(nullptr, &CloseFile);
183     if (bEnableOutput) {
184         fSink.reset(OpenFile(options.values.SinkName, "wb"));
185         MSDK_CHECK_POINTER(fSink, MFX_ERR_NULL_PTR);
186     }
187 
188     // Initialize Media SDK session
189     // - MFX_IMPL_AUTO_ANY selects HW acceleration if available (on any adapter)
190     // - Version 1.3 is selected since the opaque memory feature was added in this API release
191     //   If more recent API features are needed, change the version accordingly
192     mfxIMPL impl = options.values.impl;
193     mfxVersion ver = { {3, 1} };      // Note: API 1.3 !
194     MFXVideoSession session;
195     sts = Initialize(impl, ver, &session, NULL);
196     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
197 
198     // Create Media SDK decoder & encoder
199     MFXVideoDECODE mfxDEC(session);
200     MFXVideoENCODE mfxENC(session);
201 
202     // Set required video parameters for decode
203     mfxVideoParam mfxDecParams;
204     memset(&mfxDecParams, 0, sizeof(mfxDecParams));
205     mfxDecParams.mfx.CodecId = MFX_CODEC_AVC;
206     mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
207 
208     // Configuration for low latency
209     mfxDecParams.AsyncDepth = 1;
210 
211     // Prepare Media SDK bit stream buffer for decoder
212     // - Arbitrary buffer size for this example
213     mfxBitstream mfxBS;
214     memset(&mfxBS, 0, sizeof(mfxBS));
215     mfxBS.MaxLength = 1024 * 1024;
216     std::vector<mfxU8> bstData(mfxBS.MaxLength);
217     mfxBS.Data = bstData.data();
218 
219 
220     // Read a chunk of data from stream file into bit stream buffer
221     // - Parse bit stream, searching for header and fill video parameters structure
222     // - Abort if bit stream header is not found in the first bit stream buffer chunk
223     sts = ReadNextBitStreamFrame(&mfxBS, fSource.get());
224     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
225 
226     sts = mfxDEC.DecodeHeader(&mfxBS, &mfxDecParams);
227     MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
228     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
229 
230     // Initialize encoder parameters
231     mfxVideoParam mfxEncParams;
232     memset(&mfxEncParams, 0, sizeof(mfxEncParams));
233     mfxEncParams.mfx.CodecId = MFX_CODEC_AVC;
234     mfxEncParams.mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED;
235     mfxEncParams.mfx.TargetKbps = options.values.Bitrate;
236     mfxEncParams.mfx.RateControlMethod = MFX_RATECONTROL_VBR;
237     mfxEncParams.mfx.FrameInfo.FrameRateExtN = options.values.FrameRateN;
238     mfxEncParams.mfx.FrameInfo.FrameRateExtD = options.values.FrameRateD;
239     mfxEncParams.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
240     mfxEncParams.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
241     mfxEncParams.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
242     mfxEncParams.mfx.FrameInfo.CropX = 0;
243     mfxEncParams.mfx.FrameInfo.CropY = 0;
244     mfxEncParams.mfx.FrameInfo.CropW = mfxDecParams.mfx.FrameInfo.CropW;
245     mfxEncParams.mfx.FrameInfo.CropH = mfxDecParams.mfx.FrameInfo.CropH;
246     // width must be a multiple of 16
247     // height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture
248     mfxEncParams.mfx.FrameInfo.Width = MSDK_ALIGN16(mfxEncParams.mfx.FrameInfo.CropW);
249     mfxEncParams.mfx.FrameInfo.Height =
250         (MFX_PICSTRUCT_PROGRESSIVE == mfxEncParams.mfx.FrameInfo.PicStruct) ?
251         MSDK_ALIGN16(mfxEncParams.mfx.FrameInfo.CropH) :
252         MSDK_ALIGN32(mfxEncParams.mfx.FrameInfo.CropH);
253 
254     mfxEncParams.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY;
255 
256     // Configuration for low latency
257     mfxEncParams.AsyncDepth = 1;
258     mfxEncParams.mfx.GopRefDist = 1;
259 
260     mfxExtCodingOption extendedCodingOptions;
261     memset(&extendedCodingOptions, 0, sizeof(extendedCodingOptions));
262     extendedCodingOptions.Header.BufferId = MFX_EXTBUFF_CODING_OPTION;
263     extendedCodingOptions.Header.BufferSz = sizeof(extendedCodingOptions);
264     extendedCodingOptions.MaxDecFrameBuffering = 1;
265     mfxExtBuffer* extendedBuffers[1];
266     extendedBuffers[0] = (mfxExtBuffer*) & extendedCodingOptions;
267     mfxEncParams.ExtParam = extendedBuffers;
268     mfxEncParams.NumExtParam = 1;
269     // ---
270 
271     // Query number required surfaces for decoder
272     mfxFrameAllocRequest DecRequest;
273     memset(&DecRequest, 0, sizeof(DecRequest));
274     sts = mfxDEC.QueryIOSurf(&mfxDecParams, &DecRequest);
275     MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
276     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
277 
278     // Query number required surfaces for encoder
279     mfxFrameAllocRequest EncRequest;
280     memset(&EncRequest, 0, sizeof(EncRequest));
281     sts = mfxENC.QueryIOSurf(&mfxEncParams, &EncRequest);
282     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
283 
284     mfxU16 nSurfNum = EncRequest.NumFrameSuggested + DecRequest.NumFrameSuggested;
285 
286     // Initialize shared surfaces for decoder and encoder
287     // - Note that no buffer memory is allocated, for opaque memory this is handled by Media SDK internally
288     // - Frame surface array keeps reference to all surfaces
289     // - Opaque memory is configured with the mfxExtOpaqueSurfaceAlloc extended buffers
290     // we need vector of raw pointers for opaque buffer;
291     std::vector<mfxFrameSurface1*> pSurfaces(nSurfNum);
292     // additional vector for resource control
293     std::vector<std::unique_ptr<mfxFrameSurface1>> pSurfacesPtrs(nSurfNum);
294     for (int i = 0; i < nSurfNum; i++) {
295         pSurfacesPtrs[i].reset(new mfxFrameSurface1);
296         pSurfaces[i] = pSurfacesPtrs[i].get();
297         MSDK_CHECK_POINTER(pSurfaces[i], MFX_ERR_MEMORY_ALLOC);
298         memset(pSurfaces[i], 0, sizeof(mfxFrameSurface1));
299         pSurfaces[i]->Info = DecRequest.Info;
300     }
301 
302     mfxExtOpaqueSurfaceAlloc extOpaqueAllocDec;
303     memset(&extOpaqueAllocDec, 0, sizeof(extOpaqueAllocDec));
304     extOpaqueAllocDec.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
305     extOpaqueAllocDec.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc);
306     mfxExtBuffer* pExtParamsDec = (mfxExtBuffer*) & extOpaqueAllocDec;
307 
308     mfxExtOpaqueSurfaceAlloc extOpaqueAllocEnc;
309     memset(&extOpaqueAllocEnc, 0, sizeof(extOpaqueAllocEnc));
310     extOpaqueAllocEnc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
311     extOpaqueAllocEnc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc);
312     mfxExtBuffer* pExtParamsEnc = (mfxExtBuffer*) & extOpaqueAllocEnc;
313 
314     extOpaqueAllocDec.Out.Surfaces = pSurfaces.data();
315     extOpaqueAllocDec.Out.NumSurface = nSurfNum;
316     extOpaqueAllocDec.Out.Type = DecRequest.Type;
317     memcpy(&extOpaqueAllocEnc.In, &extOpaqueAllocDec.Out, sizeof(extOpaqueAllocDec.Out));
318 
319     mfxDecParams.ExtParam = &pExtParamsDec;
320     mfxDecParams.NumExtParam = 1;
321     mfxEncParams.ExtParam = &pExtParamsEnc;
322     mfxEncParams.NumExtParam = 1;
323 
324     // Initialize the Media SDK decoder
325     sts = mfxDEC.Init(&mfxDecParams);
326     MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
327     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
328 
329     // Initialize the Media SDK encoder
330     sts = mfxENC.Init(&mfxEncParams);
331     MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
332     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
333 
334     // Retrieve video parameters selected by encoder.
335     // - BufferSizeInKB parameter is required to set bit stream buffer size
336     mfxVideoParam par;
337     memset(&par, 0, sizeof(par));
338     sts = mfxENC.GetVideoParam(&par);
339     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
340 
341     // Prepare Media SDK bit stream buffer for encoder
342     mfxBitstream mfxEncBS;
343     memset(&mfxEncBS, 0, sizeof(mfxEncBS));
344     mfxEncBS.MaxLength = par.mfx.BufferSizeInKB * 1000;
345     std::vector<mfxU8> bstEncData(mfxEncBS.MaxLength);
346     mfxEncBS.Data = bstEncData.data();
347 
348 
349     // ===================================
350     // Start transcoding the frames
351     //
352 
353     mfxTime tStart, tEnd;
354     mfxGetTime(&tStart);
355 
356 
357     // Record e2e latency for first 1000 frames
358     // - Store timing in map (for speed), where unique timestamp value is the key
359     std::unordered_map < mfxU64, mfxTime > decInTimeMap;
360     std::unordered_map < mfxU64, mfxTime > encOutTimeMap;
361     mfxU64 currentTimeStamp = 0;    // key value to hashes storing timestamps
362     mfxU32 bsInLength = 0;
363 
364     if (options.values.MeasureLatency) {
365         decInTimeMap.rehash(1000);
366         encOutTimeMap.rehash(1000);
367     }
368 
369     mfxSyncPoint syncpD, syncpE;
370     mfxFrameSurface1* pmfxOutSurface = NULL;
371     int nIndex = 0;
372     mfxU32 nFrame = 0;
373 
374     //
375     // Stage 1: Main transcoding loop
376     //
377     while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts || MFX_ERR_MORE_SURFACE == sts) {
378         if (MFX_WRN_DEVICE_BUSY == sts)
379             MSDK_SLEEP(1);  // just wait and then repeat the same call to DecodeFrameAsync
380 
381         if (MFX_ERR_MORE_DATA == sts) {
382             sts = ReadNextBitStreamFrame(&mfxBS, fSource.get());  // Read more data to input bit stream
383             MSDK_BREAK_ON_ERROR(sts);
384         }
385 
386         if (MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE == sts) {
387             nIndex = GetFreeSurfaceIndex(pSurfaces.data(), nSurfNum);      // Find free frame surface
388             MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex, MFX_ERR_MEMORY_ALLOC);
389         }
390         if (options.values.MeasureLatency && (decInTimeMap.size() < 1000)) {
391             mfxBS.TimeStamp = currentTimeStamp;
392             mfxGetTime(&decInTimeMap[mfxBS.TimeStamp]);
393             bsInLength = mfxBS.DataLength;
394         }
395 
396         // For low latency
397         mfxBS.DataFlag = MFX_BITSTREAM_COMPLETE_FRAME;
398 
399 
400 
401         // Decode a frame asychronously (returns immediately)
402         sts =
403             mfxDEC.DecodeFrameAsync(&mfxBS, pSurfaces[nIndex], &pmfxOutSurface, &syncpD);
404 
405         // Since no splitter, artificial timestamp insertion used (TimeStampCalc could also be used)
406         if (options.values.MeasureLatency && (decInTimeMap.size() < 1000)) {
407             if (MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE == sts) {       // check if decode operation was successful
408 
409                 if (bsInLength != mfxBS.DataLength) {   // check if data was consumed
410                     currentTimeStamp++;
411                 }
412             }
413         }
414 
415         // Ignore warnings if output is available,
416         // if no output and no action required just repeat the DecodeFrameAsync call
417         if (MFX_ERR_NONE < sts && syncpD)
418             sts = MFX_ERR_NONE;
419 
420         if (MFX_ERR_NONE == sts) {
421             for (;;) {
422                 // Encode a frame asychronously (returns immediately)
423                 sts = mfxENC.EncodeFrameAsync(NULL, pmfxOutSurface, &mfxEncBS, &syncpE);
424 
425                 if (MFX_ERR_NONE < sts && !syncpE) {    // repeat the call if warning and no output
426                     if (MFX_WRN_DEVICE_BUSY == sts)
427                         MSDK_SLEEP(1);  // wait if device is busy
428                 } else if (MFX_ERR_NONE < sts && syncpE) {
429                     sts = MFX_ERR_NONE;     // ignore warnings if output is available
430                     break;
431                 } else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) {
432                     // Allocate more bitstream buffer memory here if needed...
433                     break;
434                 } else
435                     break;
436             }
437 
438             if (MFX_ERR_MORE_DATA == sts) {
439                 // MFX_ERR_MORE_DATA indicates encoder need more input, request more surfaces from previous operation
440                 sts = MFX_ERR_NONE;
441                 continue;
442             }
443 
444             if (MFX_ERR_NONE == sts) {
445                 sts = session.SyncOperation(syncpE, 60000);  // Synchronize. Wait until frame processing is ready
446                 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
447 
448                 if (options.values.MeasureLatency && (encOutTimeMap.size() < 1000)) {
449                     mfxGetTime(&encOutTimeMap[mfxEncBS.TimeStamp]);
450 
451                     /*printf( "Finished encoding frame %d Type: %c latency: %f ms\n",
452                             (int)mfxEncBS.TimeStamp,
453                             mfxFrameTypeString(mfxEncBS.FrameType),
454                             TimeDiffMsec(encOutTimeMap[mfxEncBS.TimeStamp], decInTimeMap[mfxEncBS.TimeStamp]));*/
455                 }
456 
457                 sts = WriteBitStreamFrame(&mfxEncBS, fSink.get());
458                 MSDK_BREAK_ON_ERROR(sts);
459 
460                 ++nFrame;
461                 if (bEnableOutput)
462                     printf("Frame number: %d\r", nFrame);
463             }
464         }
465     }
466 
467     // MFX_ERR_MORE_DATA means that file has ended, need to go to buffering loop, exit in case of other errors
468     MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
469     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
470 
471     //
472     // Stage 2: Retrieve the buffered decoded frames
473     //
474     while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_SURFACE == sts) {
475         if (MFX_WRN_DEVICE_BUSY == sts)
476             MSDK_SLEEP(1);
477 
478         nIndex = GetFreeSurfaceIndex(pSurfaces.data(), nSurfNum);      // Find free frame surface
479         MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex, MFX_ERR_MEMORY_ALLOC);
480 
481         // Decode a frame asychronously (returns immediately)
482         sts = mfxDEC.DecodeFrameAsync(NULL, pSurfaces[nIndex], &pmfxOutSurface, &syncpD);
483 
484         // Ignore warnings if output is available,
485         // if no output and no action required just repeat the DecodeFrameAsync call
486         if (MFX_ERR_NONE < sts && syncpD)
487             sts = MFX_ERR_NONE;
488 
489         if (MFX_ERR_NONE == sts) {
490             for (;;) {
491                 // Encode a frame asychronously (returns immediately)
492                 sts = mfxENC.EncodeFrameAsync(NULL, pmfxOutSurface, &mfxEncBS, &syncpE);
493 
494                 if (MFX_ERR_NONE < sts && !syncpE) {    // repeat the call if warning and no output
495                     if (MFX_WRN_DEVICE_BUSY == sts)
496                         MSDK_SLEEP(1);  // wait if device is busy
497                 } else if (MFX_ERR_NONE < sts && syncpE) {
498                     sts = MFX_ERR_NONE;     // ignore warnings if output is available
499                     break;
500                 } else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) {
501                     // Allocate more bitstream buffer memory here if needed...
502                     break;
503                 } else
504                     break;
505             }
506 
507             if (MFX_ERR_MORE_DATA == sts) {
508                 // MFX_ERR_MORE_DATA indicates encoder need more input, request more surfaces from previous operation
509                 sts = MFX_ERR_NONE;
510                 continue;
511             }
512 
513             if (MFX_ERR_NONE == sts) {
514                 sts = session.SyncOperation(syncpE, 60000);  // Synchronize. Wait until frame processing is ready
515                 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
516 
517                 if (options.values.MeasureLatency && (encOutTimeMap.size() < 1000)) {
518                     mfxGetTime(&encOutTimeMap[mfxEncBS.TimeStamp]);
519 
520                     /*printf( "Finished encoding frame %d Type: %c latency: %f ms\n",
521                             (int)mfxEncBS.TimeStamp,
522                             mfxFrameTypeString(mfxEncBS.FrameType),
523                             TimeDiffMsec(encOutTimeMap[mfxEncBS.TimeStamp], decInTimeMap[mfxEncBS.TimeStamp]));*/
524                 }
525 
526                 sts = WriteBitStreamFrame(&mfxEncBS, fSink.get());
527                 MSDK_BREAK_ON_ERROR(sts);
528 
529                 ++nFrame;
530                 if (bEnableOutput) {
531                     printf("Frame number: %d\r", nFrame);
532                 }
533             }
534         }
535     }
536 
537     // MFX_ERR_MORE_DATA indicates that all decode buffers has been fetched, exit in case of other errors
538     MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
539     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
540 
541     //
542     // Stage 3: Retrieve the buffered encoded frames
543     //
544     while (MFX_ERR_NONE <= sts) {
545         for (;;) {
546             // Encode a frame asychronously (returns immediately)
547             sts = mfxENC.EncodeFrameAsync(NULL, NULL, &mfxEncBS, &syncpE);
548 
549             if (MFX_ERR_NONE < sts && !syncpE) {    // repeat the call if warning and no output
550                 if (MFX_WRN_DEVICE_BUSY == sts)
551                     MSDK_SLEEP(1);  // Wait if device is busy, then repeat the same call
552             } else if (MFX_ERR_NONE < sts && syncpE) {
553                 sts = MFX_ERR_NONE;     // ignore warnings if output is available
554                 break;
555             } else
556                 break;
557         }
558 
559         if (MFX_ERR_NONE == sts) {
560             sts = session.SyncOperation(syncpE, 60000);  // Synchronize. Wait until frame processing is ready
561             MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
562 
563             if (options.values.MeasureLatency && (encOutTimeMap.size() < 1000))
564                 mfxGetTime(&encOutTimeMap[mfxEncBS.TimeStamp]);
565 
566             sts = WriteBitStreamFrame(&mfxEncBS, fSink.get());
567             MSDK_BREAK_ON_ERROR(sts);
568 
569             ++nFrame;
570             if (bEnableOutput) {
571                 printf("Frame number: %d\r", nFrame);
572                 fflush(stdout);
573             }
574         }
575     }
576 
577     // MFX_ERR_MORE_DATA indicates that there are no more buffered frames, exit in case of other errors
578     MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
579     MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
580 
581     mfxGetTime(&tEnd);
582     double elapsed = TimeDiffMsec(tEnd, tStart) / 1000;
583     double fps = ((double)nFrame / elapsed);
584     printf("\nExecution time: %3.2f s (%3.2f fps)\n", elapsed, fps);
585 
586     if (options.values.MeasureLatency) {
587         std::vector < double >frameLatencies;
588 
589         // Store all frame latencies in vector
590         for (std::unordered_map < mfxU64, mfxTime >::iterator it = decInTimeMap.begin(); it != decInTimeMap.end(); ++it) {
591             const mfxU64 tsKey = (*it).first;
592             mfxTime startTime = (*it).second;
593             mfxTime endTime = encOutTimeMap[tsKey];
594             double frameLatency = TimeDiffMsec(endTime, startTime);
595             if (frameLatency>0)
596                 frameLatencies.push_back(frameLatency);
597             //printf("[%4d]: %.2f\n", tsKey, frameLatency);
598         }
599         // Calculate overall latency metrics
600         printf("Latency: AVG=%5.1f ms, MAX=%5.1f ms, MIN=%5.1f ms\n",
601                std::accumulate(frameLatencies.begin(), frameLatencies.end(), 0.0) / frameLatencies.size(),
602                *std::max_element(frameLatencies.begin(), frameLatencies.end()),
603                *std::min_element(frameLatencies.begin(), frameLatencies.end()));
604     }
605 
606     // ===================================================================
607     // Clean up resources
608     //  - It is recommended to close Media SDK components first, before releasing allocated surfaces, since
609     //    some surfaces may still be locked by internal Media SDK resources.
610 
611     mfxENC.Close();
612     mfxDEC.Close();
613     // session closed automatically on destruction
614 
615     Release();
616 
617     return 0;
618 }
619