Commit | Line | Data |
---|---|---|
d0a63d8b AK |
1 | /* |
2 | * Intel MediaSDK QSV encoder/decoder shared code | |
3 | * | |
4 | * This file is part of Libav. | |
5 | * | |
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. | |
10 | * | |
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. | |
15 | * | |
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 | |
19 | */ | |
20 | ||
21 | #include <mfx/mfxvideo.h> | |
66acb76b | 22 | #include <mfx/mfxplugin.h> |
d0a63d8b | 23 | |
66acb76b AK |
24 | #include <stdio.h> |
25 | #include <string.h> | |
26 | ||
27 | #include "libavutil/avstring.h" | |
a0524d9b | 28 | #include "libavutil/common.h" |
d0a63d8b | 29 | #include "libavutil/error.h" |
a0524d9b AK |
30 | #include "libavutil/hwcontext.h" |
31 | #include "libavutil/hwcontext_qsv.h" | |
4ab61cd9 | 32 | #include "libavutil/imgutils.h" |
d0a63d8b AK |
33 | |
34 | #include "avcodec.h" | |
35 | #include "qsv_internal.h" | |
36 | ||
e0b16457 MT |
37 | #if QSV_VERSION_ATLEAST(1, 12) |
38 | #include "mfx/mfxvp8.h" | |
39 | #endif | |
40 | ||
d0a63d8b AK |
41 | int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id) |
42 | { | |
43 | switch (codec_id) { | |
44 | case AV_CODEC_ID_H264: | |
45 | return MFX_CODEC_AVC; | |
66acb76b AK |
46 | #if QSV_VERSION_ATLEAST(1, 8) |
47 | case AV_CODEC_ID_HEVC: | |
48 | return MFX_CODEC_HEVC; | |
49 | #endif | |
d0a63d8b AK |
50 | case AV_CODEC_ID_MPEG1VIDEO: |
51 | case AV_CODEC_ID_MPEG2VIDEO: | |
52 | return MFX_CODEC_MPEG2; | |
53 | case AV_CODEC_ID_VC1: | |
54 | return MFX_CODEC_VC1; | |
e0b16457 MT |
55 | #if QSV_VERSION_ATLEAST(1, 12) |
56 | case AV_CODEC_ID_VP8: | |
57 | return MFX_CODEC_VP8; | |
58 | #endif | |
d0a63d8b AK |
59 | default: |
60 | break; | |
61 | } | |
62 | ||
63 | return AVERROR(ENOSYS); | |
64 | } | |
65 | ||
cd1047f3 MT |
66 | int ff_qsv_profile_to_mfx(enum AVCodecID codec_id, int profile) |
67 | { | |
68 | if (profile == FF_PROFILE_UNKNOWN) | |
69 | return MFX_PROFILE_UNKNOWN; | |
70 | switch (codec_id) { | |
71 | case AV_CODEC_ID_H264: | |
72 | case AV_CODEC_ID_HEVC: | |
73 | return profile; | |
74 | case AV_CODEC_ID_VC1: | |
75 | return 4 * profile + 1; | |
76 | case AV_CODEC_ID_MPEG2VIDEO: | |
77 | return 0x10 * profile; | |
78 | } | |
79 | return MFX_PROFILE_UNKNOWN; | |
80 | } | |
81 | ||
95414eb2 AK |
82 | static const struct { |
83 | mfxStatus mfxerr; | |
84 | int averr; | |
85 | const char *desc; | |
86 | } qsv_errors[] = { | |
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" }, | |
984736dd AK |
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" }, | |
95414eb2 AK |
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" }, | |
95414eb2 AK |
108 | { MFX_ERR_INCOMPATIBLE_AUDIO_PARAM, AVERROR(EINVAL), "incompatible audio parameters" }, |
109 | { MFX_ERR_INVALID_AUDIO_PARAM, AVERROR(EINVAL), "invalid audio parameters" }, | |
110 | ||
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" }, | |
120 | }; | |
121 | ||
122 | int ff_qsv_map_error(mfxStatus mfx_err, const char **desc) | |
d0a63d8b | 123 | { |
95414eb2 AK |
124 | int i; |
125 | for (i = 0; i < FF_ARRAY_ELEMS(qsv_errors); i++) { | |
126 | if (qsv_errors[i].mfxerr == mfx_err) { | |
127 | if (desc) | |
128 | *desc = qsv_errors[i].desc; | |
129 | return qsv_errors[i].averr; | |
130 | } | |
d0a63d8b | 131 | } |
95414eb2 AK |
132 | if (desc) |
133 | *desc = "unknown error"; | |
134 | return AVERROR_UNKNOWN; | |
135 | } | |
136 | ||
137 | int ff_qsv_print_error(void *log_ctx, mfxStatus err, | |
138 | const char *error_string) | |
139 | { | |
140 | const char *desc; | |
141 | int ret; | |
142 | ret = ff_qsv_map_error(err, &desc); | |
143 | av_log(log_ctx, AV_LOG_ERROR, "%s: %s (%d)\n", error_string, desc, err); | |
144 | return ret; | |
d0a63d8b AK |
145 | } |
146 | ||
8e07c22e AK |
147 | int ff_qsv_print_warning(void *log_ctx, mfxStatus err, |
148 | const char *warning_string) | |
149 | { | |
150 | const char *desc; | |
151 | int ret; | |
152 | ret = ff_qsv_map_error(err, &desc); | |
153 | av_log(log_ctx, AV_LOG_WARNING, "%s: %s (%d)\n", warning_string, desc, err); | |
154 | return ret; | |
155 | } | |
156 | ||
4ab61cd9 AK |
157 | static enum AVPixelFormat qsv_map_fourcc(uint32_t fourcc) |
158 | { | |
159 | switch (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; | |
163 | } | |
164 | return AV_PIX_FMT_NONE; | |
165 | } | |
166 | ||
536bb17e AK |
167 | int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc) |
168 | { | |
169 | switch (format) { | |
170 | case AV_PIX_FMT_YUV420P: | |
171 | case AV_PIX_FMT_YUVJ420P: | |
21962261 | 172 | case AV_PIX_FMT_NV12: |
536bb17e AK |
173 | *fourcc = MFX_FOURCC_NV12; |
174 | return AV_PIX_FMT_NV12; | |
92736c74 | 175 | case AV_PIX_FMT_YUV420P10: |
21962261 | 176 | case AV_PIX_FMT_P010: |
92736c74 AK |
177 | *fourcc = MFX_FOURCC_P010; |
178 | return AV_PIX_FMT_P010; | |
536bb17e AK |
179 | default: |
180 | return AVERROR(ENOSYS); | |
181 | } | |
182 | } | |
183 | ||
00aeedd8 AK |
184 | int ff_qsv_find_surface_idx(QSVFramesContext *ctx, QSVFrame *frame) |
185 | { | |
186 | int i; | |
187 | for (i = 0; i < ctx->nb_mids; i++) { | |
188 | QSVMid *mid = &ctx->mids[i]; | |
189 | if (mid->handle == frame->surface.Data.MemId) | |
190 | return i; | |
191 | } | |
192 | return AVERROR_BUG; | |
193 | } | |
194 | ||
a0524d9b AK |
195 | static int qsv_load_plugins(mfxSession session, const char *load_plugins, |
196 | void *logctx) | |
197 | { | |
198 | if (!load_plugins || !*load_plugins) | |
199 | return 0; | |
200 | ||
201 | while (*load_plugins) { | |
202 | mfxPluginUID uid; | |
203 | mfxStatus ret; | |
204 | int i, err = 0; | |
205 | ||
206 | char *plugin = av_get_token(&load_plugins, ":"); | |
207 | if (!plugin) | |
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; | |
213 | } | |
214 | ||
215 | for (i = 0; i < sizeof(uid.Data); i++) { | |
216 | err = sscanf(plugin + 2 * i, "%2hhx", uid.Data + i); | |
217 | if (err != 1) { | |
218 | av_log(logctx, AV_LOG_ERROR, "Invalid plugin UID\n"); | |
219 | err = AVERROR(EINVAL); | |
220 | goto load_plugin_fail; | |
221 | } | |
222 | ||
223 | } | |
224 | ||
225 | ret = MFXVideoUSER_Load(session, &uid, 1); | |
226 | if (ret < 0) { | |
95414eb2 AK |
227 | char errorbuf[128]; |
228 | snprintf(errorbuf, sizeof(errorbuf), | |
229 | "Could not load the requested plugin '%s'", plugin); | |
230 | err = ff_qsv_print_error(logctx, ret, errorbuf); | |
a0524d9b AK |
231 | goto load_plugin_fail; |
232 | } | |
233 | ||
234 | if (*load_plugins) | |
235 | load_plugins++; | |
236 | load_plugin_fail: | |
237 | av_freep(&plugin); | |
238 | if (err < 0) | |
239 | return err; | |
240 | } | |
241 | ||
242 | return 0; | |
243 | ||
244 | } | |
245 | ||
66acb76b AK |
246 | int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session, |
247 | const char *load_plugins) | |
d0a63d8b AK |
248 | { |
249 | mfxIMPL impl = MFX_IMPL_AUTO_ANY; | |
250 | mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } }; | |
251 | ||
252 | const char *desc; | |
253 | int ret; | |
254 | ||
255 | ret = MFXInit(impl, &ver, session); | |
95414eb2 AK |
256 | if (ret < 0) |
257 | return ff_qsv_print_error(avctx, ret, | |
258 | "Error initializing an internal MFX session"); | |
d0a63d8b | 259 | |
a0524d9b AK |
260 | ret = qsv_load_plugins(*session, load_plugins, avctx); |
261 | if (ret < 0) { | |
262 | av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); | |
263 | return ret; | |
66acb76b AK |
264 | } |
265 | ||
ce9d7da7 LB |
266 | MFXQueryIMPL(*session, &impl); |
267 | ||
268 | switch (MFX_IMPL_BASETYPE(impl)) { | |
269 | case MFX_IMPL_SOFTWARE: | |
270 | desc = "software"; | |
271 | break; | |
272 | case MFX_IMPL_HARDWARE: | |
273 | case MFX_IMPL_HARDWARE2: | |
274 | case MFX_IMPL_HARDWARE3: | |
275 | case MFX_IMPL_HARDWARE4: | |
276 | desc = "hardware accelerated"; | |
277 | break; | |
278 | default: | |
279 | desc = "unknown"; | |
280 | } | |
281 | ||
d0a63d8b AK |
282 | av_log(avctx, AV_LOG_VERBOSE, |
283 | "Initialized an internal MFX session using %s implementation\n", | |
284 | desc); | |
285 | ||
286 | return 0; | |
287 | } | |
a0524d9b | 288 | |
4ab61cd9 AK |
289 | static void mids_buf_free(void *opaque, uint8_t *data) |
290 | { | |
291 | AVBufferRef *hw_frames_ref = opaque; | |
292 | av_buffer_unref(&hw_frames_ref); | |
293 | av_freep(&data); | |
294 | } | |
295 | ||
296 | static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref) | |
297 | { | |
298 | AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data; | |
299 | AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; | |
300 | int nb_surfaces = frames_hwctx->nb_surfaces; | |
301 | ||
302 | AVBufferRef *mids_buf, *hw_frames_ref1; | |
303 | QSVMid *mids; | |
304 | int i; | |
305 | ||
306 | hw_frames_ref1 = av_buffer_ref(hw_frames_ref); | |
307 | if (!hw_frames_ref1) | |
308 | return NULL; | |
309 | ||
310 | mids = av_mallocz_array(nb_surfaces, sizeof(*mids)); | |
311 | if (!mids) { | |
312 | av_buffer_unref(&hw_frames_ref1); | |
313 | return NULL; | |
314 | } | |
315 | ||
316 | mids_buf = av_buffer_create((uint8_t*)mids, nb_surfaces * sizeof(*mids), | |
317 | mids_buf_free, hw_frames_ref1, 0); | |
318 | if (!mids_buf) { | |
319 | av_buffer_unref(&hw_frames_ref1); | |
320 | av_freep(&mids); | |
321 | return NULL; | |
322 | } | |
323 | ||
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; | |
328 | } | |
329 | ||
330 | return mids_buf; | |
331 | } | |
332 | ||
333 | static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_ref, | |
334 | AVBufferRef *mids_buf) | |
335 | { | |
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; | |
340 | int i; | |
341 | ||
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)); | |
346 | if (!resp->mids) | |
347 | return AVERROR(ENOMEM); | |
348 | ||
349 | for (i = 0; i < nb_surfaces; i++) | |
350 | resp->mids[i] = &mids[i]; | |
351 | resp->NumFrameActual = nb_surfaces; | |
352 | ||
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); | |
357 | } | |
358 | ||
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); | |
364 | } | |
365 | ||
366 | return 0; | |
367 | } | |
368 | ||
a0524d9b AK |
369 | static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, |
370 | mfxFrameAllocResponse *resp) | |
371 | { | |
372 | QSVFramesContext *ctx = pthis; | |
4ab61cd9 | 373 | int ret; |
a0524d9b | 374 | |
4ab61cd9 AK |
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))) | |
a0524d9b | 380 | return MFX_ERR_UNSUPPORTED; |
a0524d9b | 381 | |
4ab61cd9 AK |
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; | |
388 | ||
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; | |
396 | } | |
397 | ||
398 | ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids_buf); | |
399 | if (ret < 0) { | |
400 | av_log(ctx->logctx, AV_LOG_ERROR, | |
401 | "Error filling an external frame allocation request\n"); | |
402 | return MFX_ERR_MEMORY_ALLOC; | |
403 | } | |
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; | |
408 | ||
409 | AVBufferRef *frames_ref, *mids_buf; | |
410 | AVHWFramesContext *frames_ctx; | |
411 | AVQSVFramesContext *frames_hwctx; | |
412 | ||
413 | frames_ref = av_hwframe_ctx_alloc(ext_frames_ctx->device_ref); | |
414 | if (!frames_ref) | |
415 | return MFX_ERR_MEMORY_ALLOC; | |
416 | ||
417 | frames_ctx = (AVHWFramesContext*)frames_ref->data; | |
418 | frames_hwctx = frames_ctx->hwctx; | |
419 | ||
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; | |
425 | ||
426 | frames_hwctx->frame_type = req->Type; | |
427 | ||
428 | ret = av_hwframe_ctx_init(frames_ref); | |
429 | if (ret < 0) { | |
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; | |
435 | } | |
00aeedd8 | 436 | |
4ab61cd9 AK |
437 | mids_buf = qsv_create_mids(frames_ref); |
438 | if (!mids_buf) { | |
439 | av_buffer_unref(&frames_ref); | |
440 | return MFX_ERR_MEMORY_ALLOC; | |
441 | } | |
00aeedd8 | 442 | |
4ab61cd9 AK |
443 | ret = qsv_setup_mids(resp, frames_ref, mids_buf); |
444 | av_buffer_unref(&mids_buf); | |
445 | av_buffer_unref(&frames_ref); | |
446 | if (ret < 0) { | |
447 | av_log(ctx->logctx, AV_LOG_ERROR, | |
448 | "Error filling an internal frame allocation request\n"); | |
449 | return MFX_ERR_MEMORY_ALLOC; | |
450 | } | |
451 | } else { | |
452 | return MFX_ERR_UNSUPPORTED; | |
453 | } | |
a0524d9b AK |
454 | |
455 | return MFX_ERR_NONE; | |
456 | } | |
457 | ||
458 | static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) | |
459 | { | |
4ab61cd9 AK |
460 | av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]); |
461 | av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual + 1]); | |
00aeedd8 | 462 | av_freep(&resp->mids); |
a0524d9b AK |
463 | return MFX_ERR_NONE; |
464 | } | |
465 | ||
466 | static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) | |
467 | { | |
4ab61cd9 AK |
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; | |
4ab61cd9 | 471 | int ret; |
4ab61cd9 AK |
472 | |
473 | if (qsv_mid->locked_frame) | |
474 | return MFX_ERR_UNDEFINED_BEHAVIOR; | |
475 | ||
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; | |
481 | ||
482 | /* wrap the provided handle in a hwaccel AVFrame */ | |
483 | qsv_mid->hw_frame = av_frame_alloc(); | |
484 | if (!qsv_mid->hw_frame) | |
485 | goto fail; | |
486 | ||
487 | qsv_mid->hw_frame->data[3] = (uint8_t*)&qsv_mid->surf; | |
488 | qsv_mid->hw_frame->format = AV_PIX_FMT_QSV; | |
489 | ||
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]) | |
493 | goto fail; | |
494 | ||
495 | qsv_mid->hw_frame->width = hw_frames_ctx->width; | |
496 | qsv_mid->hw_frame->height = hw_frames_ctx->height; | |
497 | ||
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) | |
500 | goto fail; | |
501 | ||
502 | qsv_mid->surf.Info = hw_frames_hwctx->surfaces[0].Info; | |
503 | qsv_mid->surf.Data.MemId = qsv_mid->handle; | |
504 | ||
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); | |
508 | if (ret < 0) | |
509 | goto fail; | |
510 | ||
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; | |
515 | ||
516 | return MFX_ERR_NONE; | |
517 | fail: | |
518 | av_frame_free(&qsv_mid->hw_frame); | |
519 | av_frame_free(&qsv_mid->locked_frame); | |
520 | return MFX_ERR_MEMORY_ALLOC; | |
a0524d9b AK |
521 | } |
522 | ||
523 | static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) | |
524 | { | |
4ab61cd9 | 525 | QSVMid *qsv_mid = mid; |
4ab61cd9 AK |
526 | |
527 | av_frame_free(&qsv_mid->locked_frame); | |
528 | av_frame_free(&qsv_mid->hw_frame); | |
529 | ||
530 | return MFX_ERR_NONE; | |
a0524d9b AK |
531 | } |
532 | ||
533 | static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) | |
534 | { | |
00aeedd8 AK |
535 | QSVMid *qsv_mid = (QSVMid*)mid; |
536 | *hdl = qsv_mid->handle; | |
a0524d9b AK |
537 | return MFX_ERR_NONE; |
538 | } | |
539 | ||
4936a48b MT |
540 | int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession, |
541 | AVBufferRef *device_ref, const char *load_plugins) | |
a0524d9b AK |
542 | { |
543 | static const mfxHandleType handle_types[] = { | |
544 | MFX_HANDLE_VA_DISPLAY, | |
545 | MFX_HANDLE_D3D9_DEVICE_MANAGER, | |
546 | MFX_HANDLE_D3D11_DEVICE, | |
547 | }; | |
4936a48b MT |
548 | AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref->data; |
549 | AVQSVDeviceContext *device_hwctx = device_ctx->hwctx; | |
a0524d9b AK |
550 | mfxSession parent_session = device_hwctx->session; |
551 | ||
552 | mfxSession session; | |
553 | mfxVersion ver; | |
554 | mfxIMPL impl; | |
555 | mfxHDL handle = NULL; | |
556 | mfxHandleType handle_type; | |
557 | mfxStatus err; | |
558 | ||
559 | int i, ret; | |
560 | ||
561 | err = MFXQueryIMPL(parent_session, &impl); | |
562 | if (err == MFX_ERR_NONE) | |
563 | err = MFXQueryVersion(parent_session, &ver); | |
95414eb2 AK |
564 | if (err != MFX_ERR_NONE) |
565 | return ff_qsv_print_error(avctx, err, | |
566 | "Error querying the session attributes"); | |
a0524d9b AK |
567 | |
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]; | |
572 | break; | |
573 | } | |
574 | handle = NULL; | |
575 | } | |
576 | if (!handle) { | |
577 | av_log(avctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " | |
578 | "from the session\n"); | |
579 | } | |
580 | ||
581 | err = MFXInit(impl, &ver, &session); | |
95414eb2 AK |
582 | if (err != MFX_ERR_NONE) |
583 | return ff_qsv_print_error(avctx, err, | |
584 | "Error initializing a child MFX session"); | |
a0524d9b AK |
585 | |
586 | if (handle) { | |
587 | err = MFXVideoCORE_SetHandle(session, handle_type, handle); | |
95414eb2 AK |
588 | if (err != MFX_ERR_NONE) |
589 | return ff_qsv_print_error(avctx, err, | |
590 | "Error setting a HW handle"); | |
a0524d9b AK |
591 | } |
592 | ||
593 | ret = qsv_load_plugins(session, load_plugins, avctx); | |
594 | if (ret < 0) { | |
595 | av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); | |
596 | return ret; | |
597 | } | |
598 | ||
4936a48b MT |
599 | *psession = session; |
600 | return 0; | |
601 | } | |
602 | ||
603 | int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession, | |
604 | QSVFramesContext *qsv_frames_ctx, | |
605 | const char *load_plugins, int opaque) | |
606 | { | |
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, | |
614 | }; | |
615 | ||
616 | AVHWFramesContext *frames_ctx = (AVHWFramesContext*)qsv_frames_ctx->hw_frames_ctx->data; | |
617 | AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; | |
618 | ||
619 | mfxSession session; | |
620 | mfxStatus err; | |
621 | ||
622 | int ret; | |
623 | ||
624 | ret = ff_qsv_init_session_device(avctx, &session, | |
625 | frames_ctx->device_ref, load_plugins); | |
626 | if (ret < 0) | |
627 | return ret; | |
628 | ||
a0524d9b | 629 | if (!opaque) { |
4ab61cd9 | 630 | qsv_frames_ctx->logctx = avctx; |
a0524d9b | 631 | |
4ab61cd9 AK |
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; | |
a0524d9b | 638 | qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces; |
a0524d9b AK |
639 | |
640 | err = MFXVideoCORE_SetFrameAllocator(session, &frame_allocator); | |
95414eb2 AK |
641 | if (err != MFX_ERR_NONE) |
642 | return ff_qsv_print_error(avctx, err, | |
643 | "Error setting a frame allocator"); | |
a0524d9b AK |
644 | } |
645 | ||
646 | *psession = session; | |
647 | return 0; | |
648 | } |