1 //==============================================================================
2 // Copyright Intel Corporation
3 //
4 // SPDX-License-Identifier: MIT
5 //==============================================================================
6
7 ///
8 /// Utility library header file for sample code
9 ///
10 /// @file
11
12 #ifndef EXAMPLES_UTIL_H_
13 #define EXAMPLES_UTIL_H_
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #ifdef USE_MEDIASDK1
20 #include "mfxvideo.h"
21 enum {
22 MFX_FOURCC_I420 = MFX_FOURCC_IYUV /*!< Alias for the IYUV color format. */
23 };
24 #else
25 #include "vpl/mfxjpeg.h"
26 #include "vpl/mfxvideo.h"
27 #endif
28
29 #if (MFX_VERSION >= 2000)
30 #include "vpl/mfxdispatcher.h"
31 #endif
32
33 #ifdef __unix__
34 #include <fcntl.h>
35 #endif
36
37 #ifdef LIBVA_SUPPORT
38 #include "va/va.h"
39 #include "va/va_drm.h"
40 #endif
41
42 #define WAIT_5_MILLISECONDS 5
43 #define WAIT_100_MILLISECONDS 100
44 #define MAX_PATH 260
45 #define MAX_WIDTH 3840
46 #define MAX_HEIGHT 2160
47 #define IS_ARG_EQ(a, b) (!strcmp((a), (b)))
48
49 #define VERIFY(x, y) \
50 if (!(x)) { \
51 printf("%s\n", y); \
52 goto end; \
53 }
54
55 #define ALIGN16(value) (((value + 15) >> 4) << 4)
56 #define ALIGN32(X) (((mfxU32)((X) + 31)) & (~(mfxU32)31))
57 #define VPLVERSION(major, minor) (major << 16 | minor)
58
59 #if defined(_WIN32) || defined(_WIN64)
60 #include <windows.h>
61 #define sleep(msec) Sleep(msec)
62 #else
63 #include <unistd.h>
64 #define sleep(msec) usleep(1000 * msec)
65 #endif
66
67 enum ExampleParams { PARAM_IMPL = 0, PARAM_INFILE, PARAM_INRES, PARAM_COUNT };
68 enum ParamGroup {
69 PARAMS_CREATESESSION = 0,
70 PARAMS_DECODE,
71 PARAMS_ENCODE,
72 PARAMS_VPP,
73 PARAMS_TRANSCODE
74 };
75
76 typedef struct _Params {
77 mfxIMPL impl;
78 #if (MFX_VERSION >= 2000)
79 mfxVariant implValue;
80 #endif
81
82 char *infileName;
83 char *inmodelName;
84
85 mfxU16 srcWidth;
86 mfxU16 srcHeight;
87 } Params;
88
ValidateFileName(char * in)89 char *ValidateFileName(char *in) {
90 if (in) {
91 if (strnlen(in, MAX_PATH) > MAX_PATH)
92 return NULL;
93 }
94
95 return in;
96 }
97
ValidateSize(char * in,mfxU16 * vsize,mfxU32 vmax)98 bool ValidateSize(char *in, mfxU16 *vsize, mfxU32 vmax) {
99 if (in) {
100 *vsize = static_cast<mfxU16>(strtol(in, NULL, 10));
101 if (*vsize <= vmax)
102 return true;
103 }
104
105 *vsize = 0;
106 return false;
107 }
108
ParseArgsAndValidate(int argc,char * argv[],Params * params,ParamGroup group)109 bool ParseArgsAndValidate(int argc, char *argv[], Params *params, ParamGroup group) {
110 int idx;
111 char *s;
112
113 // init all params to 0
114 *params = {};
115 params->impl = MFX_IMPL_SOFTWARE;
116 #if (MFX_VERSION >= 2000)
117 params->implValue.Type = MFX_VARIANT_TYPE_U32;
118 params->implValue.Data.U32 = MFX_IMPL_TYPE_SOFTWARE;
119 #endif
120
121 for (idx = 1; idx < argc;) {
122 // all switches must start with '-'
123 if (argv[idx][0] != '-') {
124 printf("ERROR - invalid argument: %s\n", argv[idx]);
125 return false;
126 }
127
128 // switch string, starting after the '-'
129 s = &argv[idx][1];
130 idx++;
131
132 // search for match
133 if (IS_ARG_EQ(s, "i")) {
134 params->infileName = ValidateFileName(argv[idx++]);
135 if (!params->infileName) {
136 return false;
137 }
138 }
139 else if (IS_ARG_EQ(s, "m")) {
140 params->inmodelName = ValidateFileName(argv[idx++]);
141 if (!params->inmodelName) {
142 return false;
143 }
144 }
145 else if (IS_ARG_EQ(s, "w")) {
146 if (!ValidateSize(argv[idx++], ¶ms->srcWidth, MAX_WIDTH))
147 return false;
148 }
149 else if (IS_ARG_EQ(s, "h")) {
150 if (!ValidateSize(argv[idx++], ¶ms->srcHeight, MAX_HEIGHT))
151 return false;
152 }
153 else if (IS_ARG_EQ(s, "hw")) {
154 params->impl = MFX_IMPL_HARDWARE;
155 #if (MFX_VERSION >= 2000)
156 params->implValue.Data.U32 = MFX_IMPL_TYPE_HARDWARE;
157 #endif
158 }
159 else if (IS_ARG_EQ(s, "sw")) {
160 params->impl = MFX_IMPL_SOFTWARE;
161 #if (MFX_VERSION >= 2000)
162 params->implValue.Data.U32 = MFX_IMPL_TYPE_SOFTWARE;
163 #endif
164 }
165 }
166
167 // input file required by all except createsession
168 if ((group != PARAMS_CREATESESSION) && (!params->infileName)) {
169 printf("ERROR - input file name (-i) is required\n");
170 return false;
171 }
172
173 // VPP and encode samples require an input resolution
174 if ((PARAMS_VPP == group) || (PARAMS_ENCODE == group)) {
175 if ((!params->srcWidth) || (!params->srcHeight)) {
176 printf("ERROR - source width/height required\n");
177 return false;
178 }
179 }
180
181 return true;
182 }
183
InitAcceleratorHandle(mfxSession session,int * fd)184 void *InitAcceleratorHandle(mfxSession session, int *fd) {
185 mfxIMPL impl;
186 mfxStatus sts = MFXQueryIMPL(session, &impl);
187 if (sts != MFX_ERR_NONE)
188 return NULL;
189
190 #ifdef LIBVA_SUPPORT
191 if ((impl & MFX_IMPL_VIA_VAAPI) == MFX_IMPL_VIA_VAAPI) {
192 if (!fd)
193 return NULL;
194 VADisplay va_dpy = NULL;
195 // initialize VAAPI context and set session handle (req in Linux)
196 *fd = open("/dev/dri/renderD128", O_RDWR);
197 if (*fd >= 0) {
198 va_dpy = vaGetDisplayDRM(*fd);
199 if (va_dpy) {
200 int major_version = 0, minor_version = 0;
201 if (VA_STATUS_SUCCESS == vaInitialize(va_dpy, &major_version, &minor_version)) {
202 MFXVideoCORE_SetHandle(session,
203 static_cast<mfxHandleType>(MFX_HANDLE_VA_DISPLAY),
204 va_dpy);
205 }
206 }
207 }
208 return va_dpy;
209 }
210 #endif
211
212 return NULL;
213 }
214
FreeAcceleratorHandle(void * accelHandle,int fd)215 void FreeAcceleratorHandle(void *accelHandle, int fd) {
216 #ifdef LIBVA_SUPPORT
217 if (accelHandle) {
218 vaTerminate((VADisplay)accelHandle);
219 }
220 if (fd) {
221 close(fd);
222 }
223 #endif
224 }
225
226 //Shows implementation info for Media SDK or oneVPL
ShowImplInfo(mfxSession session)227 mfxVersion ShowImplInfo(mfxSession session) {
228 mfxIMPL impl;
229 mfxVersion version = { 0, 1 };
230
231 mfxStatus sts = MFXQueryIMPL(session, &impl);
232 if (sts != MFX_ERR_NONE)
233 return version;
234
235 sts = MFXQueryVersion(session, &version);
236 if (sts != MFX_ERR_NONE)
237 return version;
238
239 printf("Session loaded: ApiVersion = %d.%d \timpl= ", version.Major, version.Minor);
240
241 switch (impl) {
242 case MFX_IMPL_SOFTWARE:
243 puts("Software");
244 break;
245 case MFX_IMPL_HARDWARE | MFX_IMPL_VIA_VAAPI:
246 puts("Hardware:VAAPI");
247 break;
248 case MFX_IMPL_HARDWARE | MFX_IMPL_VIA_D3D11:
249 puts("Hardware:D3D11");
250 break;
251 case MFX_IMPL_HARDWARE | MFX_IMPL_VIA_D3D9:
252 puts("Hardware:D3D9");
253 break;
254 default:
255 puts("Unknown");
256 break;
257 }
258
259 return version;
260 }
261
262 // Shows implementation info with oneVPL
ShowImplementationInfo(mfxLoader loader,mfxU32 implnum)263 void ShowImplementationInfo(mfxLoader loader, mfxU32 implnum) {
264 mfxImplDescription *idesc = nullptr;
265 mfxStatus sts;
266 //Loads info about implementation at specified list location
267 sts = MFXEnumImplementations(loader, implnum, MFX_IMPLCAPS_IMPLDESCSTRUCTURE, (mfxHDL *)&idesc);
268 if (!idesc || (sts != MFX_ERR_NONE))
269 return;
270
271 printf("Implementation details:\n");
272 printf(" ApiVersion: %hu.%hu \n", idesc->ApiVersion.Major, idesc->ApiVersion.Minor);
273 printf(" Implementation type: %s\n", (idesc->Impl == MFX_IMPL_TYPE_SOFTWARE) ? "SW" : "HW");
274 printf(" AccelerationMode via: ");
275 switch (idesc->AccelerationMode) {
276 case MFX_ACCEL_MODE_NA:
277 printf("NA \n");
278 break;
279 case MFX_ACCEL_MODE_VIA_D3D9:
280 printf("D3D9\n");
281 break;
282 case MFX_ACCEL_MODE_VIA_D3D11:
283 printf("D3D11\n");
284 break;
285 case MFX_ACCEL_MODE_VIA_VAAPI:
286 printf("VAAPI\n");
287 break;
288 case MFX_ACCEL_MODE_VIA_VAAPI_DRM_MODESET:
289 printf("VAAPI_DRM_MODESET\n");
290 break;
291 case MFX_ACCEL_MODE_VIA_VAAPI_GLX:
292 printf("VAAPI_GLX\n");
293 break;
294 case MFX_ACCEL_MODE_VIA_VAAPI_X11:
295 printf("VAAPI_X11\n");
296 break;
297 case MFX_ACCEL_MODE_VIA_VAAPI_WAYLAND:
298 printf("VAAPI_WAYLAND\n");
299 break;
300 case MFX_ACCEL_MODE_VIA_HDDLUNITE:
301 printf("HDDLUNITE\n");
302 break;
303 default:
304 printf("unknown\n");
305 break;
306 }
307 MFXDispReleaseImplDescription(loader, idesc);
308
309 #if (MFX_VERSION >= 2004)
310 //Show implementation path, added in 2.4 API
311 mfxHDL implPath = nullptr;
312 sts = MFXEnumImplementations(loader, implnum, MFX_IMPLCAPS_IMPLPATH, &implPath);
313 if (!implPath || (sts != MFX_ERR_NONE))
314 return;
315
316 printf(" Path: %s\n\n", reinterpret_cast<mfxChar *>(implPath));
317 MFXDispReleaseImplDescription(loader, implPath);
318 #endif
319 }
320
PrepareFrameInfo(mfxFrameInfo * fi,mfxU32 format,mfxU16 w,mfxU16 h)321 void PrepareFrameInfo(mfxFrameInfo *fi, mfxU32 format, mfxU16 w, mfxU16 h) {
322 // Video processing input data format
323 fi->FourCC = format;
324 fi->ChromaFormat = MFX_CHROMAFORMAT_YUV420;
325 fi->CropX = 0;
326 fi->CropY = 0;
327 fi->CropW = w;
328 fi->CropH = h;
329 fi->PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
330 fi->FrameRateExtN = 30;
331 fi->FrameRateExtD = 1;
332 // width must be a multiple of 16
333 // height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture
334 fi->Width = ALIGN16(fi->CropW);
335 fi->Height =
336 (MFX_PICSTRUCT_PROGRESSIVE == fi->PicStruct) ? ALIGN16(fi->CropH) : ALIGN32(fi->CropH);
337 }
338
GetSurfaceSize(mfxU32 FourCC,mfxU32 width,mfxU32 height)339 mfxU32 GetSurfaceSize(mfxU32 FourCC, mfxU32 width, mfxU32 height) {
340 mfxU32 nbytes = 0;
341
342 switch (FourCC) {
343 case MFX_FOURCC_I420:
344 case MFX_FOURCC_NV12:
345 nbytes = width * height + (width >> 1) * (height >> 1) + (width >> 1) * (height >> 1);
346 break;
347 case MFX_FOURCC_I010:
348 case MFX_FOURCC_P010:
349 nbytes = width * height + (width >> 1) * (height >> 1) + (width >> 1) * (height >> 1);
350 nbytes *= 2;
351 break;
352 case MFX_FOURCC_RGB4:
353 nbytes = width * height * 4;
354 break;
355 default:
356 break;
357 }
358
359 return nbytes;
360 }
361
GetFreeSurfaceIndex(mfxFrameSurface1 * SurfacesPool,mfxU16 nPoolSize)362 int GetFreeSurfaceIndex(mfxFrameSurface1 *SurfacesPool, mfxU16 nPoolSize) {
363 for (mfxU16 i = 0; i < nPoolSize; i++) {
364 if (0 == SurfacesPool[i].Data.Locked)
365 return i;
366 }
367 return MFX_ERR_NOT_FOUND;
368 }
369
AllocateExternalSystemMemorySurfacePool(mfxU8 ** buf,mfxFrameSurface1 * surfpool,mfxFrameInfo frame_info,mfxU16 surfnum)370 mfxStatus AllocateExternalSystemMemorySurfacePool(mfxU8 **buf,
371 mfxFrameSurface1 *surfpool,
372 mfxFrameInfo frame_info,
373 mfxU16 surfnum) {
374 // initialize surface pool (I420, RGB4 format)
375 mfxU32 surfaceSize = GetSurfaceSize(frame_info.FourCC, frame_info.Width, frame_info.Height);
376 if (!surfaceSize)
377 return MFX_ERR_MEMORY_ALLOC;
378
379 size_t framePoolBufSize = static_cast<size_t>(surfaceSize) * surfnum;
380 *buf = reinterpret_cast<mfxU8 *>(calloc(framePoolBufSize, 1));
381
382 mfxU16 surfW;
383 mfxU16 surfH = frame_info.Height;
384
385 if (frame_info.FourCC == MFX_FOURCC_RGB4) {
386 surfW = frame_info.Width * 4;
387
388 for (mfxU32 i = 0; i < surfnum; i++) {
389 surfpool[i] = { 0 };
390 surfpool[i].Info = frame_info;
391 size_t buf_offset = static_cast<size_t>(i) * surfaceSize;
392 surfpool[i].Data.B = *buf + buf_offset;
393 surfpool[i].Data.G = surfpool[i].Data.B + 1;
394 surfpool[i].Data.R = surfpool[i].Data.B + 2;
395 surfpool[i].Data.A = surfpool[i].Data.B + 3;
396 surfpool[i].Data.Pitch = surfW;
397 }
398 }
399 else {
400 surfW = (frame_info.FourCC == MFX_FOURCC_P010) ? frame_info.Width * 2 : frame_info.Width;
401
402 for (mfxU32 i = 0; i < surfnum; i++) {
403 surfpool[i] = { 0 };
404 surfpool[i].Info = frame_info;
405 size_t buf_offset = static_cast<size_t>(i) * surfaceSize;
406 surfpool[i].Data.Y = *buf + buf_offset;
407 surfpool[i].Data.U = *buf + buf_offset + (surfW * surfH);
408 surfpool[i].Data.V = surfpool[i].Data.U + ((surfW / 2) * (surfH / 2));
409 surfpool[i].Data.Pitch = surfW;
410 }
411 }
412
413 return MFX_ERR_NONE;
414 }
415
FreeExternalSystemMemorySurfacePool(mfxU8 * dec_buf,mfxFrameSurface1 * surfpool)416 void FreeExternalSystemMemorySurfacePool(mfxU8 *dec_buf, mfxFrameSurface1 *surfpool) {
417 if (dec_buf)
418 free(dec_buf);
419
420 if (surfpool)
421 free(surfpool);
422 }
423
424 // Read encoded stream from file
ReadEncodedStream(mfxBitstream & bs,FILE * f)425 mfxStatus ReadEncodedStream(mfxBitstream &bs, FILE *f) {
426 mfxU8 *p0 = bs.Data;
427 mfxU8 *p1 = bs.Data + bs.DataOffset;
428 if (bs.DataOffset > bs.MaxLength - 1) {
429 return MFX_ERR_NOT_ENOUGH_BUFFER;
430 }
431 if (bs.DataLength + bs.DataOffset > bs.MaxLength) {
432 return MFX_ERR_NOT_ENOUGH_BUFFER;
433 }
434 for (mfxU32 i = 0; i < bs.DataLength; i++) {
435 *(p0++) = *(p1++);
436 }
437 bs.DataOffset = 0;
438 bs.DataLength += (mfxU32)fread(bs.Data + bs.DataLength, 1, bs.MaxLength - bs.DataLength, f);
439 if (bs.DataLength == 0)
440 return MFX_ERR_MORE_DATA;
441
442 return MFX_ERR_NONE;
443 }
444
445 // Write encoded stream to file
WriteEncodedStream(mfxBitstream & bs,FILE * f)446 void WriteEncodedStream(mfxBitstream &bs, FILE *f) {
447 fwrite(bs.Data + bs.DataOffset, 1, bs.DataLength, f);
448 bs.DataLength = 0;
449 return;
450 }
451
452 // Load raw I420 frames to mfxFrameSurface
ReadRawFrame(mfxFrameSurface1 * surface,FILE * f)453 mfxStatus ReadRawFrame(mfxFrameSurface1 *surface, FILE *f) {
454 mfxU16 w, h, i, pitch;
455 size_t bytes_read;
456 mfxU8 *ptr;
457 mfxFrameInfo *info = &surface->Info;
458 mfxFrameData *data = &surface->Data;
459
460 w = info->Width;
461 h = info->Height;
462
463 switch (info->FourCC) {
464 case MFX_FOURCC_I420:
465 // read luminance plane (Y)
466 pitch = data->Pitch;
467 ptr = data->Y;
468 for (i = 0; i < h; i++) {
469 bytes_read = (mfxU32)fread(ptr + i * pitch, 1, w, f);
470 if (w != bytes_read)
471 return MFX_ERR_MORE_DATA;
472 }
473
474 // read chrominance (U, V)
475 pitch /= 2;
476 h /= 2;
477 w /= 2;
478 ptr = data->U;
479 for (i = 0; i < h; i++) {
480 bytes_read = (mfxU32)fread(ptr + i * pitch, 1, w, f);
481 if (w != bytes_read)
482 return MFX_ERR_MORE_DATA;
483 }
484
485 ptr = data->V;
486 for (i = 0; i < h; i++) {
487 bytes_read = (mfxU32)fread(ptr + i * pitch, 1, w, f);
488 if (w != bytes_read)
489 return MFX_ERR_MORE_DATA;
490 }
491 break;
492 case MFX_FOURCC_NV12:
493 // Y
494 pitch = data->Pitch;
495 for (i = 0; i < h; i++) {
496 bytes_read = fread(data->Y + i * pitch, 1, w, f);
497 if (w != bytes_read)
498 return MFX_ERR_MORE_DATA;
499 }
500 // UV
501 h /= 2;
502 for (i = 0; i < h; i++) {
503 bytes_read = fread(data->UV + i * pitch, 1, w, f);
504 if (w != bytes_read)
505 return MFX_ERR_MORE_DATA;
506 }
507 break;
508 case MFX_FOURCC_RGB4:
509 // Y
510 pitch = data->Pitch;
511 for (i = 0; i < h; i++) {
512 bytes_read = fread(data->B + i * pitch, 1, pitch, f);
513 if (pitch != bytes_read)
514 return MFX_ERR_MORE_DATA;
515 }
516 break;
517 default:
518 printf("Unsupported FourCC code, skip LoadRawFrame\n");
519 break;
520 }
521
522 return MFX_ERR_NONE;
523 }
524
525 #if (MFX_VERSION >= 2000)
ReadRawFrame_InternalMem(mfxFrameSurface1 * surface,FILE * f)526 mfxStatus ReadRawFrame_InternalMem(mfxFrameSurface1 *surface, FILE *f) {
527 bool is_more_data = false;
528
529 // Map makes surface writable by CPU for all implementations
530 mfxStatus sts = surface->FrameInterface->Map(surface, MFX_MAP_WRITE);
531 if (sts != MFX_ERR_NONE) {
532 printf("mfxFrameSurfaceInterface->Map failed (%d)\n", sts);
533 return sts;
534 }
535
536 sts = ReadRawFrame(surface, f);
537 if (sts != MFX_ERR_NONE) {
538 if (sts == MFX_ERR_MORE_DATA)
539 is_more_data = true;
540 else
541 return sts;
542 }
543
544 // Unmap/release returns local device access for all implementations
545 sts = surface->FrameInterface->Unmap(surface);
546 if (sts != MFX_ERR_NONE) {
547 printf("mfxFrameSurfaceInterface->Unmap failed (%d)\n", sts);
548 return sts;
549 }
550
551 return (is_more_data == true) ? MFX_ERR_MORE_DATA : MFX_ERR_NONE;
552 }
553 #endif
554
555 // Write raw I420 frame to file
WriteRawFrame(mfxFrameSurface1 * surface,FILE * f)556 mfxStatus WriteRawFrame(mfxFrameSurface1 *surface, FILE *f) {
557 mfxU16 w, h, i, pitch;
558 mfxFrameInfo *info = &surface->Info;
559 mfxFrameData *data = &surface->Data;
560
561 w = info->Width;
562 h = info->Height;
563
564 // write the output to disk
565 switch (info->FourCC) {
566 case MFX_FOURCC_I420:
567 // Y
568 pitch = data->Pitch;
569 for (i = 0; i < h; i++) {
570 fwrite(data->Y + i * pitch, 1, w, f);
571 }
572 // U
573 pitch /= 2;
574 h /= 2;
575 w /= 2;
576 for (i = 0; i < h; i++) {
577 fwrite(data->U + i * pitch, 1, w, f);
578 }
579 // V
580 for (i = 0; i < h; i++) {
581 fwrite(data->V + i * pitch, 1, w, f);
582 }
583 break;
584 case MFX_FOURCC_NV12:
585 // Y
586 pitch = data->Pitch;
587 for (i = 0; i < h; i++) {
588 fwrite(data->Y + i * pitch, 1, w, f);
589 }
590 // UV
591 h /= 2;
592 for (i = 0; i < h; i++) {
593 fwrite(data->UV + i * pitch, 1, w, f);
594 }
595 break;
596 case MFX_FOURCC_RGB4:
597 // Y
598 pitch = data->Pitch;
599 for (i = 0; i < h; i++) {
600 fwrite(data->B + i * pitch, 1, pitch, f);
601 }
602 break;
603 default:
604 return MFX_ERR_UNSUPPORTED;
605 break;
606 }
607
608 return MFX_ERR_NONE;
609 }
610
611 #if (MFX_VERSION >= 2000)
612 // Write raw frame to file
WriteRawFrame_InternalMem(mfxFrameSurface1 * surface,FILE * f)613 mfxStatus WriteRawFrame_InternalMem(mfxFrameSurface1 *surface, FILE *f) {
614 mfxStatus sts = surface->FrameInterface->Map(surface, MFX_MAP_READ);
615 if (sts != MFX_ERR_NONE) {
616 printf("mfxFrameSurfaceInterface->Map failed (%d)\n", sts);
617 return sts;
618 }
619
620 sts = WriteRawFrame(surface, f);
621 if (sts != MFX_ERR_NONE) {
622 printf("Error in WriteRawFrame\n");
623 return sts;
624 }
625
626 sts = surface->FrameInterface->Unmap(surface);
627 if (sts != MFX_ERR_NONE) {
628 printf("mfxFrameSurfaceInterface->Unmap failed (%d)\n", sts);
629 return sts;
630 }
631
632 sts = surface->FrameInterface->Release(surface);
633 if (sts != MFX_ERR_NONE) {
634 printf("mfxFrameSurfaceInterface->Release failed (%d)\n", sts);
635 return sts;
636 }
637
638 return sts;
639 }
640 #endif
641
642 #endif //EXAMPLES_UTIL_H_
643