2 * Intel MediaSDK QSV encoder/decoder shared code
4 * This file is part of Libav.
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * Libav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <mfx/mfxvideo.h>
22 #include <mfx/mfxplugin.h>
27 #include "libavutil/avstring.h"
28 #include "libavutil/common.h"
29 #include "libavutil/error.h"
30 #include "libavutil/hwcontext.h"
31 #include "libavutil/hwcontext_qsv.h"
32 #include "libavutil/imgutils.h"
35 #include "qsv_internal.h"
37 #if QSV_VERSION_ATLEAST(1, 12)
38 #include "mfx/mfxvp8.h"
41 int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id
)
44 case AV_CODEC_ID_H264
:
46 #if QSV_VERSION_ATLEAST(1, 8)
47 case AV_CODEC_ID_HEVC
:
48 return MFX_CODEC_HEVC
;
50 case AV_CODEC_ID_MPEG1VIDEO
:
51 case AV_CODEC_ID_MPEG2VIDEO
:
52 return MFX_CODEC_MPEG2
;
55 #if QSV_VERSION_ATLEAST(1, 12)
63 return AVERROR(ENOSYS
);
66 int ff_qsv_profile_to_mfx(enum AVCodecID codec_id
, int profile
)
68 if (profile
== FF_PROFILE_UNKNOWN
)
69 return MFX_PROFILE_UNKNOWN
;
71 case AV_CODEC_ID_H264
:
72 case AV_CODEC_ID_HEVC
:
75 return 4 * profile
+ 1;
76 case AV_CODEC_ID_MPEG2VIDEO
:
77 return 0x10 * profile
;
79 return MFX_PROFILE_UNKNOWN
;
87 { MFX_ERR_NONE
, 0, "success" },
88 { MFX_ERR_UNKNOWN
, AVERROR_UNKNOWN
, "unknown error" },
89 { MFX_ERR_NULL_PTR
, AVERROR(EINVAL
), "NULL pointer" },
90 { MFX_ERR_UNSUPPORTED
, AVERROR(ENOSYS
), "unsupported" },
91 { MFX_ERR_MEMORY_ALLOC
, AVERROR(ENOMEM
), "failed to allocate memory" },
92 { MFX_ERR_NOT_ENOUGH_BUFFER
, AVERROR(ENOMEM
), "insufficient input/output buffer" },
93 { MFX_ERR_INVALID_HANDLE
, AVERROR(EINVAL
), "invalid handle" },
94 { MFX_ERR_LOCK_MEMORY
, AVERROR(EIO
), "failed to lock the memory block" },
95 { MFX_ERR_NOT_INITIALIZED
, AVERROR_BUG
, "not initialized" },
96 { MFX_ERR_NOT_FOUND
, AVERROR(ENOSYS
), "specified object was not found" },
97 { MFX_ERR_MORE_DATA
, AVERROR(EAGAIN
), "expect more data at input" },
98 { MFX_ERR_MORE_SURFACE
, AVERROR(EAGAIN
), "expect more surface at output" },
99 { MFX_ERR_ABORTED
, AVERROR_UNKNOWN
, "operation aborted" },
100 { MFX_ERR_DEVICE_LOST
, AVERROR(EIO
), "device lost" },
101 { MFX_ERR_INCOMPATIBLE_VIDEO_PARAM
, AVERROR(EINVAL
), "incompatible video parameters" },
102 { MFX_ERR_INVALID_VIDEO_PARAM
, AVERROR(EINVAL
), "invalid video parameters" },
103 { MFX_ERR_UNDEFINED_BEHAVIOR
, AVERROR_BUG
, "undefined behavior" },
104 { MFX_ERR_DEVICE_FAILED
, AVERROR(EIO
), "device failed" },
105 { MFX_ERR_MORE_BITSTREAM
, AVERROR(EAGAIN
), "expect more bitstream at output" },
106 { MFX_ERR_INCOMPATIBLE_AUDIO_PARAM
, AVERROR(EINVAL
), "incompatible audio parameters" },
107 { MFX_ERR_INVALID_AUDIO_PARAM
, AVERROR(EINVAL
), "invalid audio parameters" },
109 { MFX_WRN_IN_EXECUTION
, 0, "operation in execution" },
110 { MFX_WRN_DEVICE_BUSY
, 0, "device busy" },
111 { MFX_WRN_VIDEO_PARAM_CHANGED
, 0, "video parameters changed" },
112 { MFX_WRN_PARTIAL_ACCELERATION
, 0, "partial acceleration" },
113 { MFX_WRN_INCOMPATIBLE_VIDEO_PARAM
, 0, "incompatible video parameters" },
114 { MFX_WRN_VALUE_NOT_CHANGED
, 0, "value is saturated" },
115 { MFX_WRN_OUT_OF_RANGE
, 0, "value out of range" },
116 { MFX_WRN_FILTER_SKIPPED
, 0, "filter skipped" },
117 { MFX_WRN_INCOMPATIBLE_AUDIO_PARAM
, 0, "incompatible audio parameters" },
120 int ff_qsv_map_error(mfxStatus mfx_err
, const char **desc
)
123 for (i
= 0; i
< FF_ARRAY_ELEMS(qsv_errors
); i
++) {
124 if (qsv_errors
[i
].mfxerr
== mfx_err
) {
126 *desc
= qsv_errors
[i
].desc
;
127 return qsv_errors
[i
].averr
;
131 *desc
= "unknown error";
132 return AVERROR_UNKNOWN
;
135 int ff_qsv_print_error(void *log_ctx
, mfxStatus err
,
136 const char *error_string
)
140 ret
= ff_qsv_map_error(err
, &desc
);
141 av_log(log_ctx
, AV_LOG_ERROR
, "%s: %s (%d)\n", error_string
, desc
, err
);
145 int ff_qsv_print_warning(void *log_ctx
, mfxStatus err
,
146 const char *warning_string
)
150 ret
= ff_qsv_map_error(err
, &desc
);
151 av_log(log_ctx
, AV_LOG_WARNING
, "%s: %s (%d)\n", warning_string
, desc
, err
);
155 static enum AVPixelFormat
qsv_map_fourcc(uint32_t fourcc
)
158 case MFX_FOURCC_NV12
: return AV_PIX_FMT_NV12
;
159 case MFX_FOURCC_P010
: return AV_PIX_FMT_P010
;
160 case MFX_FOURCC_P8
: return AV_PIX_FMT_PAL8
;
162 return AV_PIX_FMT_NONE
;
165 int ff_qsv_map_pixfmt(enum AVPixelFormat format
, uint32_t *fourcc
)
168 case AV_PIX_FMT_YUV420P
:
169 case AV_PIX_FMT_YUVJ420P
:
170 case AV_PIX_FMT_NV12
:
171 *fourcc
= MFX_FOURCC_NV12
;
172 return AV_PIX_FMT_NV12
;
173 case AV_PIX_FMT_YUV420P10
:
174 case AV_PIX_FMT_P010
:
175 *fourcc
= MFX_FOURCC_P010
;
176 return AV_PIX_FMT_P010
;
178 return AVERROR(ENOSYS
);
182 int ff_qsv_find_surface_idx(QSVFramesContext
*ctx
, QSVFrame
*frame
)
185 for (i
= 0; i
< ctx
->nb_mids
; i
++) {
186 QSVMid
*mid
= &ctx
->mids
[i
];
187 if (mid
->handle
== frame
->surface
.Data
.MemId
)
193 static int qsv_load_plugins(mfxSession session
, const char *load_plugins
,
196 if (!load_plugins
|| !*load_plugins
)
199 while (*load_plugins
) {
204 char *plugin
= av_get_token(&load_plugins
, ":");
206 return AVERROR(ENOMEM
);
207 if (strlen(plugin
) != 2 * sizeof(uid
.Data
)) {
208 av_log(logctx
, AV_LOG_ERROR
, "Invalid plugin UID length\n");
209 err
= AVERROR(EINVAL
);
210 goto load_plugin_fail
;
213 for (i
= 0; i
< sizeof(uid
.Data
); i
++) {
214 err
= sscanf(plugin
+ 2 * i
, "%2hhx", uid
.Data
+ i
);
216 av_log(logctx
, AV_LOG_ERROR
, "Invalid plugin UID\n");
217 err
= AVERROR(EINVAL
);
218 goto load_plugin_fail
;
223 ret
= MFXVideoUSER_Load(session
, &uid
, 1);
226 snprintf(errorbuf
, sizeof(errorbuf
),
227 "Could not load the requested plugin '%s'", plugin
);
228 err
= ff_qsv_print_error(logctx
, ret
, errorbuf
);
229 goto load_plugin_fail
;
244 int ff_qsv_init_internal_session(AVCodecContext
*avctx
, mfxSession
*session
,
245 const char *load_plugins
)
247 mfxIMPL impl
= MFX_IMPL_AUTO_ANY
;
248 mfxVersion ver
= { { QSV_VERSION_MINOR
, QSV_VERSION_MAJOR
} };
253 ret
= MFXInit(impl
, &ver
, session
);
255 return ff_qsv_print_error(avctx
, ret
,
256 "Error initializing an internal MFX session");
258 ret
= qsv_load_plugins(*session
, load_plugins
, avctx
);
260 av_log(avctx
, AV_LOG_ERROR
, "Error loading plugins\n");
264 MFXQueryIMPL(*session
, &impl
);
266 switch (MFX_IMPL_BASETYPE(impl
)) {
267 case MFX_IMPL_SOFTWARE
:
270 case MFX_IMPL_HARDWARE
:
271 case MFX_IMPL_HARDWARE2
:
272 case MFX_IMPL_HARDWARE3
:
273 case MFX_IMPL_HARDWARE4
:
274 desc
= "hardware accelerated";
280 av_log(avctx
, AV_LOG_VERBOSE
,
281 "Initialized an internal MFX session using %s implementation\n",
287 static void mids_buf_free(void *opaque
, uint8_t *data
)
289 AVBufferRef
*hw_frames_ref
= opaque
;
290 av_buffer_unref(&hw_frames_ref
);
294 static AVBufferRef
*qsv_create_mids(AVBufferRef
*hw_frames_ref
)
296 AVHWFramesContext
*frames_ctx
= (AVHWFramesContext
*)hw_frames_ref
->data
;
297 AVQSVFramesContext
*frames_hwctx
= frames_ctx
->hwctx
;
298 int nb_surfaces
= frames_hwctx
->nb_surfaces
;
300 AVBufferRef
*mids_buf
, *hw_frames_ref1
;
304 hw_frames_ref1
= av_buffer_ref(hw_frames_ref
);
308 mids
= av_mallocz_array(nb_surfaces
, sizeof(*mids
));
310 av_buffer_unref(&hw_frames_ref1
);
314 mids_buf
= av_buffer_create((uint8_t*)mids
, nb_surfaces
* sizeof(*mids
),
315 mids_buf_free
, hw_frames_ref1
, 0);
317 av_buffer_unref(&hw_frames_ref1
);
322 for (i
= 0; i
< nb_surfaces
; i
++) {
323 QSVMid
*mid
= &mids
[i
];
324 mid
->handle
= frames_hwctx
->surfaces
[i
].Data
.MemId
;
325 mid
->hw_frames_ref
= hw_frames_ref1
;
331 static int qsv_setup_mids(mfxFrameAllocResponse
*resp
, AVBufferRef
*hw_frames_ref
,
332 AVBufferRef
*mids_buf
)
334 AVHWFramesContext
*frames_ctx
= (AVHWFramesContext
*)hw_frames_ref
->data
;
335 AVQSVFramesContext
*frames_hwctx
= frames_ctx
->hwctx
;
336 QSVMid
*mids
= (QSVMid
*)mids_buf
->data
;
337 int nb_surfaces
= frames_hwctx
->nb_surfaces
;
340 // the allocated size of the array is two larger than the number of
341 // surfaces, we store the references to the frames context and the
342 // QSVMid array there
343 resp
->mids
= av_mallocz_array(nb_surfaces
+ 2, sizeof(*resp
->mids
));
345 return AVERROR(ENOMEM
);
347 for (i
= 0; i
< nb_surfaces
; i
++)
348 resp
->mids
[i
] = &mids
[i
];
349 resp
->NumFrameActual
= nb_surfaces
;
351 resp
->mids
[resp
->NumFrameActual
] = (mfxMemId
)av_buffer_ref(hw_frames_ref
);
352 if (!resp
->mids
[resp
->NumFrameActual
]) {
353 av_freep(&resp
->mids
);
354 return AVERROR(ENOMEM
);
357 resp
->mids
[resp
->NumFrameActual
+ 1] = av_buffer_ref(mids_buf
);
358 if (!resp
->mids
[resp
->NumFrameActual
+ 1]) {
359 av_buffer_unref((AVBufferRef
**)&resp
->mids
[resp
->NumFrameActual
]);
360 av_freep(&resp
->mids
);
361 return AVERROR(ENOMEM
);
367 static mfxStatus
qsv_frame_alloc(mfxHDL pthis
, mfxFrameAllocRequest
*req
,
368 mfxFrameAllocResponse
*resp
)
370 QSVFramesContext
*ctx
= pthis
;
373 /* this should only be called from an encoder or decoder and
374 * only allocates video memory frames */
375 if (!(req
->Type
& (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET
|
376 MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET
)) ||
377 !(req
->Type
& (MFX_MEMTYPE_FROM_DECODE
| MFX_MEMTYPE_FROM_ENCODE
)))
378 return MFX_ERR_UNSUPPORTED
;
380 if (req
->Type
& MFX_MEMTYPE_EXTERNAL_FRAME
) {
381 /* external frames -- fill from the caller-supplied frames context */
382 AVHWFramesContext
*frames_ctx
= (AVHWFramesContext
*)ctx
->hw_frames_ctx
->data
;
383 AVQSVFramesContext
*frames_hwctx
= frames_ctx
->hwctx
;
384 mfxFrameInfo
*i
= &req
->Info
;
385 mfxFrameInfo
*i1
= &frames_hwctx
->surfaces
[0].Info
;
387 if (i
->Width
!= i1
->Width
|| i
->Height
!= i1
->Height
||
388 i
->FourCC
!= i1
->FourCC
|| i
->ChromaFormat
!= i1
->ChromaFormat
) {
389 av_log(ctx
->logctx
, AV_LOG_ERROR
, "Mismatching surface properties in an "
390 "allocation request: %dx%d %d %d vs %dx%d %d %d\n",
391 i
->Width
, i
->Height
, i
->FourCC
, i
->ChromaFormat
,
392 i1
->Width
, i1
->Height
, i1
->FourCC
, i1
->ChromaFormat
);
393 return MFX_ERR_UNSUPPORTED
;
396 ret
= qsv_setup_mids(resp
, ctx
->hw_frames_ctx
, ctx
->mids_buf
);
398 av_log(ctx
->logctx
, AV_LOG_ERROR
,
399 "Error filling an external frame allocation request\n");
400 return MFX_ERR_MEMORY_ALLOC
;
402 } else if (req
->Type
& MFX_MEMTYPE_INTERNAL_FRAME
) {
403 /* internal frames -- allocate a new hw frames context */
404 AVHWFramesContext
*ext_frames_ctx
= (AVHWFramesContext
*)ctx
->hw_frames_ctx
->data
;
405 mfxFrameInfo
*i
= &req
->Info
;
407 AVBufferRef
*frames_ref
, *mids_buf
;
408 AVHWFramesContext
*frames_ctx
;
409 AVQSVFramesContext
*frames_hwctx
;
411 frames_ref
= av_hwframe_ctx_alloc(ext_frames_ctx
->device_ref
);
413 return MFX_ERR_MEMORY_ALLOC
;
415 frames_ctx
= (AVHWFramesContext
*)frames_ref
->data
;
416 frames_hwctx
= frames_ctx
->hwctx
;
418 frames_ctx
->format
= AV_PIX_FMT_QSV
;
419 frames_ctx
->sw_format
= qsv_map_fourcc(i
->FourCC
);
420 frames_ctx
->width
= i
->Width
;
421 frames_ctx
->height
= i
->Height
;
422 frames_ctx
->initial_pool_size
= req
->NumFrameSuggested
;
424 frames_hwctx
->frame_type
= req
->Type
;
426 ret
= av_hwframe_ctx_init(frames_ref
);
428 av_log(ctx
->logctx
, AV_LOG_ERROR
,
429 "Error initializing a frames context for an internal frame "
430 "allocation request\n");
431 av_buffer_unref(&frames_ref
);
432 return MFX_ERR_MEMORY_ALLOC
;
435 mids_buf
= qsv_create_mids(frames_ref
);
437 av_buffer_unref(&frames_ref
);
438 return MFX_ERR_MEMORY_ALLOC
;
441 ret
= qsv_setup_mids(resp
, frames_ref
, mids_buf
);
442 av_buffer_unref(&mids_buf
);
443 av_buffer_unref(&frames_ref
);
445 av_log(ctx
->logctx
, AV_LOG_ERROR
,
446 "Error filling an internal frame allocation request\n");
447 return MFX_ERR_MEMORY_ALLOC
;
450 return MFX_ERR_UNSUPPORTED
;
456 static mfxStatus
qsv_frame_free(mfxHDL pthis
, mfxFrameAllocResponse
*resp
)
458 av_buffer_unref((AVBufferRef
**)&resp
->mids
[resp
->NumFrameActual
]);
459 av_buffer_unref((AVBufferRef
**)&resp
->mids
[resp
->NumFrameActual
+ 1]);
460 av_freep(&resp
->mids
);
464 static mfxStatus
qsv_frame_lock(mfxHDL pthis
, mfxMemId mid
, mfxFrameData
*ptr
)
466 QSVMid
*qsv_mid
= mid
;
467 AVHWFramesContext
*hw_frames_ctx
= (AVHWFramesContext
*)qsv_mid
->hw_frames_ref
->data
;
468 AVQSVFramesContext
*hw_frames_hwctx
= hw_frames_ctx
->hwctx
;
473 if (qsv_mid
->locked_frame
)
474 return MFX_ERR_UNDEFINED_BEHAVIOR
;
476 /* Allocate a system memory frame that will hold the mapped data. */
477 qsv_mid
->locked_frame
= av_frame_alloc();
478 if (!qsv_mid
->locked_frame
)
479 return MFX_ERR_MEMORY_ALLOC
;
480 qsv_mid
->locked_frame
->format
= hw_frames_ctx
->sw_format
;
482 /* wrap the provided handle in a hwaccel AVFrame */
483 qsv_mid
->hw_frame
= av_frame_alloc();
484 if (!qsv_mid
->hw_frame
)
487 qsv_mid
->hw_frame
->data
[3] = (uint8_t*)&qsv_mid
->surf
;
488 qsv_mid
->hw_frame
->format
= AV_PIX_FMT_QSV
;
490 // doesn't really matter what buffer is used here
491 qsv_mid
->hw_frame
->buf
[0] = av_buffer_alloc(1);
492 if (!qsv_mid
->hw_frame
->buf
[0])
495 qsv_mid
->hw_frame
->width
= hw_frames_ctx
->width
;
496 qsv_mid
->hw_frame
->height
= hw_frames_ctx
->height
;
498 qsv_mid
->hw_frame
->hw_frames_ctx
= av_buffer_ref(qsv_mid
->hw_frames_ref
);
499 if (!qsv_mid
->hw_frame
->hw_frames_ctx
)
502 qsv_mid
->surf
.Info
= hw_frames_hwctx
->surfaces
[0].Info
;
503 qsv_mid
->surf
.Data
.MemId
= qsv_mid
->handle
;
505 /* map the data to the system memory */
506 ret
= av_hwframe_map(qsv_mid
->locked_frame
, qsv_mid
->hw_frame
,
507 AV_HWFRAME_MAP_DIRECT
);
511 ptr
->Pitch
= qsv_mid
->locked_frame
->linesize
[0];
512 ptr
->Y
= qsv_mid
->locked_frame
->data
[0];
513 ptr
->U
= qsv_mid
->locked_frame
->data
[1];
514 ptr
->V
= qsv_mid
->locked_frame
->data
[1] + 1;
518 av_frame_free(&qsv_mid
->hw_frame
);
519 av_frame_free(&qsv_mid
->locked_frame
);
520 return MFX_ERR_MEMORY_ALLOC
;
523 static mfxStatus
qsv_frame_unlock(mfxHDL pthis
, mfxMemId mid
, mfxFrameData
*ptr
)
525 QSVMid
*qsv_mid
= mid
;
528 av_frame_free(&qsv_mid
->locked_frame
);
529 av_frame_free(&qsv_mid
->hw_frame
);
534 static mfxStatus
qsv_frame_get_hdl(mfxHDL pthis
, mfxMemId mid
, mfxHDL
*hdl
)
536 QSVMid
*qsv_mid
= (QSVMid
*)mid
;
537 *hdl
= qsv_mid
->handle
;
541 int ff_qsv_init_session_hwcontext(AVCodecContext
*avctx
, mfxSession
*psession
,
542 QSVFramesContext
*qsv_frames_ctx
,
543 const char *load_plugins
, int opaque
)
545 static const mfxHandleType handle_types
[] = {
546 MFX_HANDLE_VA_DISPLAY
,
547 MFX_HANDLE_D3D9_DEVICE_MANAGER
,
548 MFX_HANDLE_D3D11_DEVICE
,
550 mfxFrameAllocator frame_allocator
= {
551 .pthis
= qsv_frames_ctx
,
552 .Alloc
= qsv_frame_alloc
,
553 .Lock
= qsv_frame_lock
,
554 .Unlock
= qsv_frame_unlock
,
555 .GetHDL
= qsv_frame_get_hdl
,
556 .Free
= qsv_frame_free
,
559 AVHWFramesContext
*frames_ctx
= (AVHWFramesContext
*)qsv_frames_ctx
->hw_frames_ctx
->data
;
560 AVQSVFramesContext
*frames_hwctx
= frames_ctx
->hwctx
;
561 AVQSVDeviceContext
*device_hwctx
= frames_ctx
->device_ctx
->hwctx
;
562 mfxSession parent_session
= device_hwctx
->session
;
567 mfxHDL handle
= NULL
;
568 mfxHandleType handle_type
;
573 err
= MFXQueryIMPL(parent_session
, &impl
);
574 if (err
== MFX_ERR_NONE
)
575 err
= MFXQueryVersion(parent_session
, &ver
);
576 if (err
!= MFX_ERR_NONE
)
577 return ff_qsv_print_error(avctx
, err
,
578 "Error querying the session attributes");
580 for (i
= 0; i
< FF_ARRAY_ELEMS(handle_types
); i
++) {
581 err
= MFXVideoCORE_GetHandle(parent_session
, handle_types
[i
], &handle
);
582 if (err
== MFX_ERR_NONE
) {
583 handle_type
= handle_types
[i
];
589 av_log(avctx
, AV_LOG_VERBOSE
, "No supported hw handle could be retrieved "
590 "from the session\n");
593 err
= MFXInit(impl
, &ver
, &session
);
594 if (err
!= MFX_ERR_NONE
)
595 return ff_qsv_print_error(avctx
, err
,
596 "Error initializing a child MFX session");
599 err
= MFXVideoCORE_SetHandle(session
, handle_type
, handle
);
600 if (err
!= MFX_ERR_NONE
)
601 return ff_qsv_print_error(avctx
, err
,
602 "Error setting a HW handle");
605 ret
= qsv_load_plugins(session
, load_plugins
, avctx
);
607 av_log(avctx
, AV_LOG_ERROR
, "Error loading plugins\n");
612 qsv_frames_ctx
->logctx
= avctx
;
614 /* allocate the memory ids for the external frames */
615 av_buffer_unref(&qsv_frames_ctx
->mids_buf
);
616 qsv_frames_ctx
->mids_buf
= qsv_create_mids(qsv_frames_ctx
->hw_frames_ctx
);
617 if (!qsv_frames_ctx
->mids_buf
)
618 return AVERROR(ENOMEM
);
619 qsv_frames_ctx
->mids
= (QSVMid
*)qsv_frames_ctx
->mids_buf
->data
;
620 qsv_frames_ctx
->nb_mids
= frames_hwctx
->nb_surfaces
;
622 err
= MFXVideoCORE_SetFrameAllocator(session
, &frame_allocator
);
623 if (err
!= MFX_ERR_NONE
)
624 return ff_qsv_print_error(avctx
, err
,
625 "Error setting a frame allocator");