blob: 12844197419a8874fb74ee0bd930ab322a72b91d
1 | /* |
2 | * Intel MediaSDK QSV encoder/decoder shared code |
3 | * |
4 | * This file is part of FFmpeg. |
5 | * |
6 | * FFmpeg 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 | * FFmpeg 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 FFmpeg; 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> |
22 | #include <mfx/mfxplugin.h> |
23 | |
24 | #include <stdio.h> |
25 | #include <string.h> |
26 | |
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" |
33 | |
34 | #include "avcodec.h" |
35 | #include "qsv_internal.h" |
36 | |
37 | #if QSV_VERSION_ATLEAST(1, 12) |
38 | #include "mfx/mfxvp8.h" |
39 | #endif |
40 | |
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; |
46 | #if QSV_VERSION_ATLEAST(1, 8) |
47 | case AV_CODEC_ID_HEVC: |
48 | return MFX_CODEC_HEVC; |
49 | #endif |
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; |
55 | #if QSV_VERSION_ATLEAST(1, 12) |
56 | case AV_CODEC_ID_VP8: |
57 | return MFX_CODEC_VP8; |
58 | #endif |
59 | default: |
60 | break; |
61 | } |
62 | |
63 | return AVERROR(ENOSYS); |
64 | } |
65 | |
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 | |
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" }, |
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" }, |
108 | |
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" }, |
118 | }; |
119 | |
120 | int ff_qsv_map_error(mfxStatus mfx_err, const char **desc) |
121 | { |
122 | int i; |
123 | for (i = 0; i < FF_ARRAY_ELEMS(qsv_errors); i++) { |
124 | if (qsv_errors[i].mfxerr == mfx_err) { |
125 | if (desc) |
126 | *desc = qsv_errors[i].desc; |
127 | return qsv_errors[i].averr; |
128 | } |
129 | } |
130 | if (desc) |
131 | *desc = "unknown error"; |
132 | return AVERROR_UNKNOWN; |
133 | } |
134 | |
135 | int ff_qsv_print_error(void *log_ctx, mfxStatus err, |
136 | const char *error_string) |
137 | { |
138 | const char *desc; |
139 | int ret; |
140 | ret = ff_qsv_map_error(err, &desc); |
141 | av_log(log_ctx, AV_LOG_ERROR, "%s: %s (%d)\n", error_string, desc, err); |
142 | return ret; |
143 | } |
144 | |
145 | int ff_qsv_print_warning(void *log_ctx, mfxStatus err, |
146 | const char *warning_string) |
147 | { |
148 | const char *desc; |
149 | int ret; |
150 | ret = ff_qsv_map_error(err, &desc); |
151 | av_log(log_ctx, AV_LOG_WARNING, "%s: %s (%d)\n", warning_string, desc, err); |
152 | return ret; |
153 | } |
154 | |
155 | static enum AVPixelFormat qsv_map_fourcc(uint32_t fourcc) |
156 | { |
157 | switch (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; |
161 | } |
162 | return AV_PIX_FMT_NONE; |
163 | } |
164 | |
165 | int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc) |
166 | { |
167 | switch (format) { |
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; |
177 | default: |
178 | return AVERROR(ENOSYS); |
179 | } |
180 | } |
181 | |
182 | int ff_qsv_find_surface_idx(QSVFramesContext *ctx, QSVFrame *frame) |
183 | { |
184 | int i; |
185 | for (i = 0; i < ctx->nb_mids; i++) { |
186 | QSVMid *mid = &ctx->mids[i]; |
187 | if (mid->handle == frame->surface.Data.MemId) |
188 | return i; |
189 | } |
190 | return AVERROR_BUG; |
191 | } |
192 | |
193 | static int qsv_load_plugins(mfxSession session, const char *load_plugins, |
194 | void *logctx) |
195 | { |
196 | if (!load_plugins || !*load_plugins) |
197 | return 0; |
198 | |
199 | while (*load_plugins) { |
200 | mfxPluginUID uid; |
201 | mfxStatus ret; |
202 | int i, err = 0; |
203 | |
204 | char *plugin = av_get_token(&load_plugins, ":"); |
205 | if (!plugin) |
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; |
211 | } |
212 | |
213 | for (i = 0; i < sizeof(uid.Data); i++) { |
214 | err = sscanf(plugin + 2 * i, "%2hhx", uid.Data + i); |
215 | if (err != 1) { |
216 | av_log(logctx, AV_LOG_ERROR, "Invalid plugin UID\n"); |
217 | err = AVERROR(EINVAL); |
218 | goto load_plugin_fail; |
219 | } |
220 | |
221 | } |
222 | |
223 | ret = MFXVideoUSER_Load(session, &uid, 1); |
224 | if (ret < 0) { |
225 | char errorbuf[128]; |
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; |
230 | } |
231 | |
232 | if (*load_plugins) |
233 | load_plugins++; |
234 | load_plugin_fail: |
235 | av_freep(&plugin); |
236 | if (err < 0) |
237 | return err; |
238 | } |
239 | |
240 | return 0; |
241 | |
242 | } |
243 | |
244 | int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session, |
245 | const char *load_plugins) |
246 | { |
247 | mfxIMPL impl = MFX_IMPL_AUTO_ANY; |
248 | mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } }; |
249 | |
250 | const char *desc; |
251 | int ret; |
252 | |
253 | ret = MFXInit(impl, &ver, session); |
254 | if (ret < 0) |
255 | return ff_qsv_print_error(avctx, ret, |
256 | "Error initializing an internal MFX session"); |
257 | |
258 | ret = qsv_load_plugins(*session, load_plugins, avctx); |
259 | if (ret < 0) { |
260 | av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); |
261 | return ret; |
262 | } |
263 | |
264 | MFXQueryIMPL(*session, &impl); |
265 | |
266 | switch (MFX_IMPL_BASETYPE(impl)) { |
267 | case MFX_IMPL_SOFTWARE: |
268 | desc = "software"; |
269 | break; |
270 | case MFX_IMPL_HARDWARE: |
271 | case MFX_IMPL_HARDWARE2: |
272 | case MFX_IMPL_HARDWARE3: |
273 | case MFX_IMPL_HARDWARE4: |
274 | desc = "hardware accelerated"; |
275 | break; |
276 | default: |
277 | desc = "unknown"; |
278 | } |
279 | |
280 | av_log(avctx, AV_LOG_VERBOSE, |
281 | "Initialized an internal MFX session using %s implementation\n", |
282 | desc); |
283 | |
284 | return 0; |
285 | } |
286 | |
287 | static void mids_buf_free(void *opaque, uint8_t *data) |
288 | { |
289 | AVBufferRef *hw_frames_ref = opaque; |
290 | av_buffer_unref(&hw_frames_ref); |
291 | av_freep(&data); |
292 | } |
293 | |
294 | static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref) |
295 | { |
296 | AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data; |
297 | AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; |
298 | int nb_surfaces = frames_hwctx->nb_surfaces; |
299 | |
300 | AVBufferRef *mids_buf, *hw_frames_ref1; |
301 | QSVMid *mids; |
302 | int i; |
303 | |
304 | hw_frames_ref1 = av_buffer_ref(hw_frames_ref); |
305 | if (!hw_frames_ref1) |
306 | return NULL; |
307 | |
308 | mids = av_mallocz_array(nb_surfaces, sizeof(*mids)); |
309 | if (!mids) { |
310 | av_buffer_unref(&hw_frames_ref1); |
311 | return NULL; |
312 | } |
313 | |
314 | mids_buf = av_buffer_create((uint8_t*)mids, nb_surfaces * sizeof(*mids), |
315 | mids_buf_free, hw_frames_ref1, 0); |
316 | if (!mids_buf) { |
317 | av_buffer_unref(&hw_frames_ref1); |
318 | av_freep(&mids); |
319 | return NULL; |
320 | } |
321 | |
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; |
326 | } |
327 | |
328 | return mids_buf; |
329 | } |
330 | |
331 | static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_ref, |
332 | AVBufferRef *mids_buf) |
333 | { |
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; |
338 | int i; |
339 | |
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)); |
344 | if (!resp->mids) |
345 | return AVERROR(ENOMEM); |
346 | |
347 | for (i = 0; i < nb_surfaces; i++) |
348 | resp->mids[i] = &mids[i]; |
349 | resp->NumFrameActual = nb_surfaces; |
350 | |
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); |
355 | } |
356 | |
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); |
362 | } |
363 | |
364 | return 0; |
365 | } |
366 | |
367 | static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, |
368 | mfxFrameAllocResponse *resp) |
369 | { |
370 | QSVFramesContext *ctx = pthis; |
371 | int ret; |
372 | |
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; |
379 | |
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; |
386 | |
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; |
394 | } |
395 | |
396 | ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids_buf); |
397 | if (ret < 0) { |
398 | av_log(ctx->logctx, AV_LOG_ERROR, |
399 | "Error filling an external frame allocation request\n"); |
400 | return MFX_ERR_MEMORY_ALLOC; |
401 | } |
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; |
406 | |
407 | AVBufferRef *frames_ref, *mids_buf; |
408 | AVHWFramesContext *frames_ctx; |
409 | AVQSVFramesContext *frames_hwctx; |
410 | |
411 | frames_ref = av_hwframe_ctx_alloc(ext_frames_ctx->device_ref); |
412 | if (!frames_ref) |
413 | return MFX_ERR_MEMORY_ALLOC; |
414 | |
415 | frames_ctx = (AVHWFramesContext*)frames_ref->data; |
416 | frames_hwctx = frames_ctx->hwctx; |
417 | |
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; |
423 | |
424 | frames_hwctx->frame_type = req->Type; |
425 | |
426 | ret = av_hwframe_ctx_init(frames_ref); |
427 | if (ret < 0) { |
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; |
433 | } |
434 | |
435 | mids_buf = qsv_create_mids(frames_ref); |
436 | if (!mids_buf) { |
437 | av_buffer_unref(&frames_ref); |
438 | return MFX_ERR_MEMORY_ALLOC; |
439 | } |
440 | |
441 | ret = qsv_setup_mids(resp, frames_ref, mids_buf); |
442 | av_buffer_unref(&mids_buf); |
443 | av_buffer_unref(&frames_ref); |
444 | if (ret < 0) { |
445 | av_log(ctx->logctx, AV_LOG_ERROR, |
446 | "Error filling an internal frame allocation request\n"); |
447 | return MFX_ERR_MEMORY_ALLOC; |
448 | } |
449 | } else { |
450 | return MFX_ERR_UNSUPPORTED; |
451 | } |
452 | |
453 | return MFX_ERR_NONE; |
454 | } |
455 | |
456 | static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) |
457 | { |
458 | av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]); |
459 | av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual + 1]); |
460 | av_freep(&resp->mids); |
461 | return MFX_ERR_NONE; |
462 | } |
463 | |
464 | static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) |
465 | { |
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; |
469 | int ret; |
470 | |
471 | if (qsv_mid->locked_frame) |
472 | return MFX_ERR_UNDEFINED_BEHAVIOR; |
473 | |
474 | /* Allocate a system memory frame that will hold the mapped data. */ |
475 | qsv_mid->locked_frame = av_frame_alloc(); |
476 | if (!qsv_mid->locked_frame) |
477 | return MFX_ERR_MEMORY_ALLOC; |
478 | qsv_mid->locked_frame->format = hw_frames_ctx->sw_format; |
479 | |
480 | /* wrap the provided handle in a hwaccel AVFrame */ |
481 | qsv_mid->hw_frame = av_frame_alloc(); |
482 | if (!qsv_mid->hw_frame) |
483 | goto fail; |
484 | |
485 | qsv_mid->hw_frame->data[3] = (uint8_t*)&qsv_mid->surf; |
486 | qsv_mid->hw_frame->format = AV_PIX_FMT_QSV; |
487 | |
488 | // doesn't really matter what buffer is used here |
489 | qsv_mid->hw_frame->buf[0] = av_buffer_alloc(1); |
490 | if (!qsv_mid->hw_frame->buf[0]) |
491 | goto fail; |
492 | |
493 | qsv_mid->hw_frame->width = hw_frames_ctx->width; |
494 | qsv_mid->hw_frame->height = hw_frames_ctx->height; |
495 | |
496 | qsv_mid->hw_frame->hw_frames_ctx = av_buffer_ref(qsv_mid->hw_frames_ref); |
497 | if (!qsv_mid->hw_frame->hw_frames_ctx) |
498 | goto fail; |
499 | |
500 | qsv_mid->surf.Info = hw_frames_hwctx->surfaces[0].Info; |
501 | qsv_mid->surf.Data.MemId = qsv_mid->handle; |
502 | |
503 | /* map the data to the system memory */ |
504 | ret = av_hwframe_map(qsv_mid->locked_frame, qsv_mid->hw_frame, |
505 | AV_HWFRAME_MAP_DIRECT); |
506 | if (ret < 0) |
507 | goto fail; |
508 | |
509 | ptr->Pitch = qsv_mid->locked_frame->linesize[0]; |
510 | ptr->Y = qsv_mid->locked_frame->data[0]; |
511 | ptr->U = qsv_mid->locked_frame->data[1]; |
512 | ptr->V = qsv_mid->locked_frame->data[1] + 1; |
513 | |
514 | return MFX_ERR_NONE; |
515 | fail: |
516 | av_frame_free(&qsv_mid->hw_frame); |
517 | av_frame_free(&qsv_mid->locked_frame); |
518 | return MFX_ERR_MEMORY_ALLOC; |
519 | } |
520 | |
521 | static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) |
522 | { |
523 | QSVMid *qsv_mid = mid; |
524 | |
525 | av_frame_free(&qsv_mid->locked_frame); |
526 | av_frame_free(&qsv_mid->hw_frame); |
527 | |
528 | return MFX_ERR_NONE; |
529 | } |
530 | |
531 | static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) |
532 | { |
533 | QSVMid *qsv_mid = (QSVMid*)mid; |
534 | *hdl = qsv_mid->handle; |
535 | return MFX_ERR_NONE; |
536 | } |
537 | |
538 | int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *psession, |
539 | QSVFramesContext *qsv_frames_ctx, |
540 | const char *load_plugins, int opaque) |
541 | { |
542 | static const mfxHandleType handle_types[] = { |
543 | MFX_HANDLE_VA_DISPLAY, |
544 | MFX_HANDLE_D3D9_DEVICE_MANAGER, |
545 | MFX_HANDLE_D3D11_DEVICE, |
546 | }; |
547 | mfxFrameAllocator frame_allocator = { |
548 | .pthis = qsv_frames_ctx, |
549 | .Alloc = qsv_frame_alloc, |
550 | .Lock = qsv_frame_lock, |
551 | .Unlock = qsv_frame_unlock, |
552 | .GetHDL = qsv_frame_get_hdl, |
553 | .Free = qsv_frame_free, |
554 | }; |
555 | |
556 | AVHWFramesContext *frames_ctx = (AVHWFramesContext*)qsv_frames_ctx->hw_frames_ctx->data; |
557 | AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; |
558 | AVQSVDeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; |
559 | mfxSession parent_session = device_hwctx->session; |
560 | |
561 | mfxSession session; |
562 | mfxVersion ver; |
563 | mfxIMPL impl; |
564 | mfxHDL handle = NULL; |
565 | mfxHandleType handle_type; |
566 | mfxStatus err; |
567 | |
568 | int i, ret; |
569 | |
570 | err = MFXQueryIMPL(parent_session, &impl); |
571 | if (err == MFX_ERR_NONE) |
572 | err = MFXQueryVersion(parent_session, &ver); |
573 | if (err != MFX_ERR_NONE) |
574 | return ff_qsv_print_error(avctx, err, |
575 | "Error querying the session attributes"); |
576 | |
577 | for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { |
578 | err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &handle); |
579 | if (err == MFX_ERR_NONE) { |
580 | handle_type = handle_types[i]; |
581 | break; |
582 | } |
583 | handle = NULL; |
584 | } |
585 | if (!handle) { |
586 | av_log(avctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " |
587 | "from the session\n"); |
588 | } |
589 | |
590 | err = MFXInit(impl, &ver, &session); |
591 | if (err != MFX_ERR_NONE) |
592 | return ff_qsv_print_error(avctx, err, |
593 | "Error initializing a child MFX session"); |
594 | |
595 | if (handle) { |
596 | err = MFXVideoCORE_SetHandle(session, handle_type, handle); |
597 | if (err != MFX_ERR_NONE) |
598 | return ff_qsv_print_error(avctx, err, |
599 | "Error setting a HW handle"); |
600 | } |
601 | |
602 | ret = qsv_load_plugins(session, load_plugins, avctx); |
603 | if (ret < 0) { |
604 | av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); |
605 | return ret; |
606 | } |
607 | |
608 | if (!opaque) { |
609 | qsv_frames_ctx->logctx = avctx; |
610 | |
611 | /* allocate the memory ids for the external frames */ |
612 | av_buffer_unref(&qsv_frames_ctx->mids_buf); |
613 | qsv_frames_ctx->mids_buf = qsv_create_mids(qsv_frames_ctx->hw_frames_ctx); |
614 | if (!qsv_frames_ctx->mids_buf) |
615 | return AVERROR(ENOMEM); |
616 | qsv_frames_ctx->mids = (QSVMid*)qsv_frames_ctx->mids_buf->data; |
617 | qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces; |
618 | |
619 | err = MFXVideoCORE_SetFrameAllocator(session, &frame_allocator); |
620 | if (err != MFX_ERR_NONE) |
621 | return ff_qsv_print_error(avctx, err, |
622 | "Error setting a frame allocator"); |
623 | } |
624 | |
625 | *psession = session; |
626 | return 0; |
627 | } |
628 |