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