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 /* the following 3 errors should always be handled explicitly, so those "mappings"
98 * are for completeness only */
99 { MFX_ERR_MORE_DATA
, AVERROR_UNKNOWN
, "expect more data at input" },
100 { MFX_ERR_MORE_SURFACE
, AVERROR_UNKNOWN
, "expect more surface at output" },
101 { MFX_ERR_MORE_BITSTREAM
, AVERROR_UNKNOWN
, "expect more bitstream at output" },
102 { MFX_ERR_ABORTED
, AVERROR_UNKNOWN
, "operation aborted" },
103 { MFX_ERR_DEVICE_LOST
, AVERROR(EIO
), "device lost" },
104 { MFX_ERR_INCOMPATIBLE_VIDEO_PARAM
, AVERROR(EINVAL
), "incompatible video parameters" },
105 { MFX_ERR_INVALID_VIDEO_PARAM
, AVERROR(EINVAL
), "invalid video parameters" },
106 { MFX_ERR_UNDEFINED_BEHAVIOR
, AVERROR_BUG
, "undefined behavior" },
107 { MFX_ERR_DEVICE_FAILED
, AVERROR(EIO
), "device failed" },
108 { MFX_ERR_INCOMPATIBLE_AUDIO_PARAM
, AVERROR(EINVAL
), "incompatible audio parameters" },
109 { MFX_ERR_INVALID_AUDIO_PARAM
, AVERROR(EINVAL
), "invalid audio parameters" },
111 { MFX_WRN_IN_EXECUTION
, 0, "operation in execution" },
112 { MFX_WRN_DEVICE_BUSY
, 0, "device busy" },
113 { MFX_WRN_VIDEO_PARAM_CHANGED
, 0, "video parameters changed" },
114 { MFX_WRN_PARTIAL_ACCELERATION
, 0, "partial acceleration" },
115 { MFX_WRN_INCOMPATIBLE_VIDEO_PARAM
, 0, "incompatible video parameters" },
116 { MFX_WRN_VALUE_NOT_CHANGED
, 0, "value is saturated" },
117 { MFX_WRN_OUT_OF_RANGE
, 0, "value out of range" },
118 { MFX_WRN_FILTER_SKIPPED
, 0, "filter skipped" },
119 { MFX_WRN_INCOMPATIBLE_AUDIO_PARAM
, 0, "incompatible audio parameters" },
122 int ff_qsv_map_error(mfxStatus mfx_err
, const char **desc
)
125 for (i
= 0; i
< FF_ARRAY_ELEMS(qsv_errors
); i
++) {
126 if (qsv_errors
[i
].mfxerr
== mfx_err
) {
128 *desc
= qsv_errors
[i
].desc
;
129 return qsv_errors
[i
].averr
;
133 *desc
= "unknown error";
134 return AVERROR_UNKNOWN
;
137 int ff_qsv_print_error(void *log_ctx
, mfxStatus err
,
138 const char *error_string
)
142 ret
= ff_qsv_map_error(err
, &desc
);
143 av_log(log_ctx
, AV_LOG_ERROR
, "%s: %s (%d)\n", error_string
, desc
, err
);
147 int ff_qsv_print_warning(void *log_ctx
, mfxStatus err
,
148 const char *warning_string
)
152 ret
= ff_qsv_map_error(err
, &desc
);
153 av_log(log_ctx
, AV_LOG_WARNING
, "%s: %s (%d)\n", warning_string
, desc
, err
);
157 static enum AVPixelFormat
qsv_map_fourcc(uint32_t fourcc
)
160 case MFX_FOURCC_NV12
: return AV_PIX_FMT_NV12
;
161 case MFX_FOURCC_P010
: return AV_PIX_FMT_P010
;
162 case MFX_FOURCC_P8
: return AV_PIX_FMT_PAL8
;
164 return AV_PIX_FMT_NONE
;
167 int ff_qsv_map_pixfmt(enum AVPixelFormat format
, uint32_t *fourcc
)
170 case AV_PIX_FMT_YUV420P
:
171 case AV_PIX_FMT_YUVJ420P
:
172 case AV_PIX_FMT_NV12
:
173 *fourcc
= MFX_FOURCC_NV12
;
174 return AV_PIX_FMT_NV12
;
175 case AV_PIX_FMT_YUV420P10
:
176 case AV_PIX_FMT_P010
:
177 *fourcc
= MFX_FOURCC_P010
;
178 return AV_PIX_FMT_P010
;
180 return AVERROR(ENOSYS
);
184 int ff_qsv_find_surface_idx(QSVFramesContext
*ctx
, QSVFrame
*frame
)
187 for (i
= 0; i
< ctx
->nb_mids
; i
++) {
188 QSVMid
*mid
= &ctx
->mids
[i
];
189 if (mid
->handle
== frame
->surface
.Data
.MemId
)
195 static int qsv_load_plugins(mfxSession session
, const char *load_plugins
,
198 if (!load_plugins
|| !*load_plugins
)
201 while (*load_plugins
) {
206 char *plugin
= av_get_token(&load_plugins
, ":");
208 return AVERROR(ENOMEM
);
209 if (strlen(plugin
) != 2 * sizeof(uid
.Data
)) {
210 av_log(logctx
, AV_LOG_ERROR
, "Invalid plugin UID length\n");
211 err
= AVERROR(EINVAL
);
212 goto load_plugin_fail
;
215 for (i
= 0; i
< sizeof(uid
.Data
); i
++) {
216 err
= sscanf(plugin
+ 2 * i
, "%2hhx", uid
.Data
+ i
);
218 av_log(logctx
, AV_LOG_ERROR
, "Invalid plugin UID\n");
219 err
= AVERROR(EINVAL
);
220 goto load_plugin_fail
;
225 ret
= MFXVideoUSER_Load(session
, &uid
, 1);
228 snprintf(errorbuf
, sizeof(errorbuf
),
229 "Could not load the requested plugin '%s'", plugin
);
230 err
= ff_qsv_print_error(logctx
, ret
, errorbuf
);
231 goto load_plugin_fail
;
246 int ff_qsv_init_internal_session(AVCodecContext
*avctx
, mfxSession
*session
,
247 const char *load_plugins
)
249 mfxIMPL impl
= MFX_IMPL_AUTO_ANY
;
250 mfxVersion ver
= { { QSV_VERSION_MINOR
, QSV_VERSION_MAJOR
} };
255 ret
= MFXInit(impl
, &ver
, session
);
257 return ff_qsv_print_error(avctx
, ret
,
258 "Error initializing an internal MFX session");
260 ret
= qsv_load_plugins(*session
, load_plugins
, avctx
);
262 av_log(avctx
, AV_LOG_ERROR
, "Error loading plugins\n");
266 MFXQueryIMPL(*session
, &impl
);
268 switch (MFX_IMPL_BASETYPE(impl
)) {
269 case MFX_IMPL_SOFTWARE
:
272 case MFX_IMPL_HARDWARE
:
273 case MFX_IMPL_HARDWARE2
:
274 case MFX_IMPL_HARDWARE3
:
275 case MFX_IMPL_HARDWARE4
:
276 desc
= "hardware accelerated";
282 av_log(avctx
, AV_LOG_VERBOSE
,
283 "Initialized an internal MFX session using %s implementation\n",
289 static void mids_buf_free(void *opaque
, uint8_t *data
)
291 AVBufferRef
*hw_frames_ref
= opaque
;
292 av_buffer_unref(&hw_frames_ref
);
296 static AVBufferRef
*qsv_create_mids(AVBufferRef
*hw_frames_ref
)
298 AVHWFramesContext
*frames_ctx
= (AVHWFramesContext
*)hw_frames_ref
->data
;
299 AVQSVFramesContext
*frames_hwctx
= frames_ctx
->hwctx
;
300 int nb_surfaces
= frames_hwctx
->nb_surfaces
;
302 AVBufferRef
*mids_buf
, *hw_frames_ref1
;
306 hw_frames_ref1
= av_buffer_ref(hw_frames_ref
);
310 mids
= av_mallocz_array(nb_surfaces
, sizeof(*mids
));
312 av_buffer_unref(&hw_frames_ref1
);
316 mids_buf
= av_buffer_create((uint8_t*)mids
, nb_surfaces
* sizeof(*mids
),
317 mids_buf_free
, hw_frames_ref1
, 0);
319 av_buffer_unref(&hw_frames_ref1
);
324 for (i
= 0; i
< nb_surfaces
; i
++) {
325 QSVMid
*mid
= &mids
[i
];
326 mid
->handle
= frames_hwctx
->surfaces
[i
].Data
.MemId
;
327 mid
->hw_frames_ref
= hw_frames_ref1
;
333 static int qsv_setup_mids(mfxFrameAllocResponse
*resp
, AVBufferRef
*hw_frames_ref
,
334 AVBufferRef
*mids_buf
)
336 AVHWFramesContext
*frames_ctx
= (AVHWFramesContext
*)hw_frames_ref
->data
;
337 AVQSVFramesContext
*frames_hwctx
= frames_ctx
->hwctx
;
338 QSVMid
*mids
= (QSVMid
*)mids_buf
->data
;
339 int nb_surfaces
= frames_hwctx
->nb_surfaces
;
342 // the allocated size of the array is two larger than the number of
343 // surfaces, we store the references to the frames context and the
344 // QSVMid array there
345 resp
->mids
= av_mallocz_array(nb_surfaces
+ 2, sizeof(*resp
->mids
));
347 return AVERROR(ENOMEM
);
349 for (i
= 0; i
< nb_surfaces
; i
++)
350 resp
->mids
[i
] = &mids
[i
];
351 resp
->NumFrameActual
= nb_surfaces
;
353 resp
->mids
[resp
->NumFrameActual
] = (mfxMemId
)av_buffer_ref(hw_frames_ref
);
354 if (!resp
->mids
[resp
->NumFrameActual
]) {
355 av_freep(&resp
->mids
);
356 return AVERROR(ENOMEM
);
359 resp
->mids
[resp
->NumFrameActual
+ 1] = av_buffer_ref(mids_buf
);
360 if (!resp
->mids
[resp
->NumFrameActual
+ 1]) {
361 av_buffer_unref((AVBufferRef
**)&resp
->mids
[resp
->NumFrameActual
]);
362 av_freep(&resp
->mids
);
363 return AVERROR(ENOMEM
);
369 static mfxStatus
qsv_frame_alloc(mfxHDL pthis
, mfxFrameAllocRequest
*req
,
370 mfxFrameAllocResponse
*resp
)
372 QSVFramesContext
*ctx
= pthis
;
375 /* this should only be called from an encoder or decoder and
376 * only allocates video memory frames */
377 if (!(req
->Type
& (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET
|
378 MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET
)) ||
379 !(req
->Type
& (MFX_MEMTYPE_FROM_DECODE
| MFX_MEMTYPE_FROM_ENCODE
)))
380 return MFX_ERR_UNSUPPORTED
;
382 if (req
->Type
& MFX_MEMTYPE_EXTERNAL_FRAME
) {
383 /* external frames -- fill from the caller-supplied frames context */
384 AVHWFramesContext
*frames_ctx
= (AVHWFramesContext
*)ctx
->hw_frames_ctx
->data
;
385 AVQSVFramesContext
*frames_hwctx
= frames_ctx
->hwctx
;
386 mfxFrameInfo
*i
= &req
->Info
;
387 mfxFrameInfo
*i1
= &frames_hwctx
->surfaces
[0].Info
;
389 if (i
->Width
!= i1
->Width
|| i
->Height
!= i1
->Height
||
390 i
->FourCC
!= i1
->FourCC
|| i
->ChromaFormat
!= i1
->ChromaFormat
) {
391 av_log(ctx
->logctx
, AV_LOG_ERROR
, "Mismatching surface properties in an "
392 "allocation request: %dx%d %d %d vs %dx%d %d %d\n",
393 i
->Width
, i
->Height
, i
->FourCC
, i
->ChromaFormat
,
394 i1
->Width
, i1
->Height
, i1
->FourCC
, i1
->ChromaFormat
);
395 return MFX_ERR_UNSUPPORTED
;
398 ret
= qsv_setup_mids(resp
, ctx
->hw_frames_ctx
, ctx
->mids_buf
);
400 av_log(ctx
->logctx
, AV_LOG_ERROR
,
401 "Error filling an external frame allocation request\n");
402 return MFX_ERR_MEMORY_ALLOC
;
404 } else if (req
->Type
& MFX_MEMTYPE_INTERNAL_FRAME
) {
405 /* internal frames -- allocate a new hw frames context */
406 AVHWFramesContext
*ext_frames_ctx
= (AVHWFramesContext
*)ctx
->hw_frames_ctx
->data
;
407 mfxFrameInfo
*i
= &req
->Info
;
409 AVBufferRef
*frames_ref
, *mids_buf
;
410 AVHWFramesContext
*frames_ctx
;
411 AVQSVFramesContext
*frames_hwctx
;
413 frames_ref
= av_hwframe_ctx_alloc(ext_frames_ctx
->device_ref
);
415 return MFX_ERR_MEMORY_ALLOC
;
417 frames_ctx
= (AVHWFramesContext
*)frames_ref
->data
;
418 frames_hwctx
= frames_ctx
->hwctx
;
420 frames_ctx
->format
= AV_PIX_FMT_QSV
;
421 frames_ctx
->sw_format
= qsv_map_fourcc(i
->FourCC
);
422 frames_ctx
->width
= i
->Width
;
423 frames_ctx
->height
= i
->Height
;
424 frames_ctx
->initial_pool_size
= req
->NumFrameSuggested
;
426 frames_hwctx
->frame_type
= req
->Type
;
428 ret
= av_hwframe_ctx_init(frames_ref
);
430 av_log(ctx
->logctx
, AV_LOG_ERROR
,
431 "Error initializing a frames context for an internal frame "
432 "allocation request\n");
433 av_buffer_unref(&frames_ref
);
434 return MFX_ERR_MEMORY_ALLOC
;
437 mids_buf
= qsv_create_mids(frames_ref
);
439 av_buffer_unref(&frames_ref
);
440 return MFX_ERR_MEMORY_ALLOC
;
443 ret
= qsv_setup_mids(resp
, frames_ref
, mids_buf
);
444 av_buffer_unref(&mids_buf
);
445 av_buffer_unref(&frames_ref
);
447 av_log(ctx
->logctx
, AV_LOG_ERROR
,
448 "Error filling an internal frame allocation request\n");
449 return MFX_ERR_MEMORY_ALLOC
;
452 return MFX_ERR_UNSUPPORTED
;
458 static mfxStatus
qsv_frame_free(mfxHDL pthis
, mfxFrameAllocResponse
*resp
)
460 av_buffer_unref((AVBufferRef
**)&resp
->mids
[resp
->NumFrameActual
]);
461 av_buffer_unref((AVBufferRef
**)&resp
->mids
[resp
->NumFrameActual
+ 1]);
462 av_freep(&resp
->mids
);
466 static mfxStatus
qsv_frame_lock(mfxHDL pthis
, mfxMemId mid
, mfxFrameData
*ptr
)
468 QSVMid
*qsv_mid
= mid
;
469 AVHWFramesContext
*hw_frames_ctx
= (AVHWFramesContext
*)qsv_mid
->hw_frames_ref
->data
;
470 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
;
527 av_frame_free(&qsv_mid
->locked_frame
);
528 av_frame_free(&qsv_mid
->hw_frame
);
533 static mfxStatus
qsv_frame_get_hdl(mfxHDL pthis
, mfxMemId mid
, mfxHDL
*hdl
)
535 QSVMid
*qsv_mid
= (QSVMid
*)mid
;
536 *hdl
= qsv_mid
->handle
;
540 int ff_qsv_init_session_device(AVCodecContext
*avctx
, mfxSession
*psession
,
541 AVBufferRef
*device_ref
, const char *load_plugins
)
543 static const mfxHandleType handle_types
[] = {
544 MFX_HANDLE_VA_DISPLAY
,
545 MFX_HANDLE_D3D9_DEVICE_MANAGER
,
546 MFX_HANDLE_D3D11_DEVICE
,
548 AVHWDeviceContext
*device_ctx
= (AVHWDeviceContext
*)device_ref
->data
;
549 AVQSVDeviceContext
*device_hwctx
= device_ctx
->hwctx
;
550 mfxSession parent_session
= device_hwctx
->session
;
555 mfxHDL handle
= NULL
;
556 mfxHandleType handle_type
;
561 err
= MFXQueryIMPL(parent_session
, &impl
);
562 if (err
== MFX_ERR_NONE
)
563 err
= MFXQueryVersion(parent_session
, &ver
);
564 if (err
!= MFX_ERR_NONE
)
565 return ff_qsv_print_error(avctx
, err
,
566 "Error querying the session attributes");
568 for (i
= 0; i
< FF_ARRAY_ELEMS(handle_types
); i
++) {
569 err
= MFXVideoCORE_GetHandle(parent_session
, handle_types
[i
], &handle
);
570 if (err
== MFX_ERR_NONE
) {
571 handle_type
= handle_types
[i
];
577 av_log(avctx
, AV_LOG_VERBOSE
, "No supported hw handle could be retrieved "
578 "from the session\n");
581 err
= MFXInit(impl
, &ver
, &session
);
582 if (err
!= MFX_ERR_NONE
)
583 return ff_qsv_print_error(avctx
, err
,
584 "Error initializing a child MFX session");
587 err
= MFXVideoCORE_SetHandle(session
, handle_type
, handle
);
588 if (err
!= MFX_ERR_NONE
)
589 return ff_qsv_print_error(avctx
, err
,
590 "Error setting a HW handle");
593 ret
= qsv_load_plugins(session
, load_plugins
, avctx
);
595 av_log(avctx
, AV_LOG_ERROR
, "Error loading plugins\n");
603 int ff_qsv_init_session_frames(AVCodecContext
*avctx
, mfxSession
*psession
,
604 QSVFramesContext
*qsv_frames_ctx
,
605 const char *load_plugins
, int opaque
)
607 mfxFrameAllocator frame_allocator
= {
608 .pthis
= qsv_frames_ctx
,
609 .Alloc
= qsv_frame_alloc
,
610 .Lock
= qsv_frame_lock
,
611 .Unlock
= qsv_frame_unlock
,
612 .GetHDL
= qsv_frame_get_hdl
,
613 .Free
= qsv_frame_free
,
616 AVHWFramesContext
*frames_ctx
= (AVHWFramesContext
*)qsv_frames_ctx
->hw_frames_ctx
->data
;
617 AVQSVFramesContext
*frames_hwctx
= frames_ctx
->hwctx
;
624 ret
= ff_qsv_init_session_device(avctx
, &session
,
625 frames_ctx
->device_ref
, load_plugins
);
630 qsv_frames_ctx
->logctx
= avctx
;
632 /* allocate the memory ids for the external frames */
633 av_buffer_unref(&qsv_frames_ctx
->mids_buf
);
634 qsv_frames_ctx
->mids_buf
= qsv_create_mids(qsv_frames_ctx
->hw_frames_ctx
);
635 if (!qsv_frames_ctx
->mids_buf
)
636 return AVERROR(ENOMEM
);
637 qsv_frames_ctx
->mids
= (QSVMid
*)qsv_frames_ctx
->mids_buf
->data
;
638 qsv_frames_ctx
->nb_mids
= frames_hwctx
->nb_surfaces
;
640 err
= MFXVideoCORE_SetFrameAllocator(session
, &frame_allocator
);
641 if (err
!= MFX_ERR_NONE
)
642 return ff_qsv_print_error(avctx
, err
,
643 "Error setting a frame allocator");