FFmpeg
qsv.c
Go to the documentation of this file.
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 #include <mfx/mfxjpeg.h>
24 
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include "libavutil/avstring.h"
29 #include "libavutil/common.h"
30 #include "libavutil/error.h"
31 #include "libavutil/hwcontext.h"
33 #include "libavutil/imgutils.h"
34 #include "libavutil/avassert.h"
35 
36 #include "avcodec.h"
37 #include "qsv_internal.h"
38 
39 #if QSV_VERSION_ATLEAST(1, 12)
40 #include "mfx/mfxvp8.h"
41 #endif
42 
44 {
45  switch (codec_id) {
46  case AV_CODEC_ID_H264:
47  return MFX_CODEC_AVC;
48 #if QSV_VERSION_ATLEAST(1, 8)
49  case AV_CODEC_ID_HEVC:
50  return MFX_CODEC_HEVC;
51 #endif
54  return MFX_CODEC_MPEG2;
55  case AV_CODEC_ID_VC1:
56  return MFX_CODEC_VC1;
57 #if QSV_VERSION_ATLEAST(1, 12)
58  case AV_CODEC_ID_VP8:
59  return MFX_CODEC_VP8;
60 #endif
61  case AV_CODEC_ID_MJPEG:
62  return MFX_CODEC_JPEG;
63 #if QSV_VERSION_ATLEAST(1, 19)
64  case AV_CODEC_ID_VP9:
65  return MFX_CODEC_VP9;
66 #endif
67 #if QSV_VERSION_ATLEAST(1, 34)
68  case AV_CODEC_ID_AV1:
69  return MFX_CODEC_AV1;
70 #endif
71 
72  default:
73  break;
74  }
75 
76  return AVERROR(ENOSYS);
77 }
78 
80 {
81  if (level == FF_LEVEL_UNKNOWN)
82  return MFX_LEVEL_UNKNOWN;
83 
84  switch (codec_id) {
85  case AV_CODEC_ID_HEVC:
86  return level / 3;
87  default:
88  return level;
89  }
90 }
91 
92 static const struct {
94  const char *desc;
95 } qsv_iopatterns[] = {
96  {MFX_IOPATTERN_IN_VIDEO_MEMORY, "input is video memory surface" },
97  {MFX_IOPATTERN_IN_SYSTEM_MEMORY, "input is system memory surface" },
98  {MFX_IOPATTERN_IN_OPAQUE_MEMORY, "input is opaque memory surface" },
99  {MFX_IOPATTERN_OUT_VIDEO_MEMORY, "output is video memory surface" },
100  {MFX_IOPATTERN_OUT_SYSTEM_MEMORY, "output is system memory surface" },
101  {MFX_IOPATTERN_OUT_OPAQUE_MEMORY, "output is opaque memory surface" },
102 };
103 
104 int ff_qsv_print_iopattern(void *log_ctx, int mfx_iopattern,
105  const char *extra_string)
106 {
107  const char *desc = NULL;
108 
109  for (int i = 0; i < FF_ARRAY_ELEMS(qsv_iopatterns); i++) {
110  if (qsv_iopatterns[i].mfx_iopattern == mfx_iopattern) {
111  desc = qsv_iopatterns[i].desc;
112  }
113  }
114  if (!desc)
115  desc = "unknown iopattern";
116 
117  av_log(log_ctx, AV_LOG_VERBOSE, "%s: %s\n", extra_string, desc);
118  return 0;
119 }
120 
121 static const struct {
122  mfxStatus mfxerr;
123  int averr;
124  const char *desc;
125 } qsv_errors[] = {
126  { MFX_ERR_NONE, 0, "success" },
127  { MFX_ERR_UNKNOWN, AVERROR_UNKNOWN, "unknown error" },
128  { MFX_ERR_NULL_PTR, AVERROR(EINVAL), "NULL pointer" },
129  { MFX_ERR_UNSUPPORTED, AVERROR(ENOSYS), "unsupported" },
130  { MFX_ERR_MEMORY_ALLOC, AVERROR(ENOMEM), "failed to allocate memory" },
131  { MFX_ERR_NOT_ENOUGH_BUFFER, AVERROR(ENOMEM), "insufficient input/output buffer" },
132  { MFX_ERR_INVALID_HANDLE, AVERROR(EINVAL), "invalid handle" },
133  { MFX_ERR_LOCK_MEMORY, AVERROR(EIO), "failed to lock the memory block" },
134  { MFX_ERR_NOT_INITIALIZED, AVERROR_BUG, "not initialized" },
135  { MFX_ERR_NOT_FOUND, AVERROR(ENOSYS), "specified object was not found" },
136  /* the following 3 errors should always be handled explicitly, so those "mappings"
137  * are for completeness only */
138  { MFX_ERR_MORE_DATA, AVERROR_UNKNOWN, "expect more data at input" },
139  { MFX_ERR_MORE_SURFACE, AVERROR_UNKNOWN, "expect more surface at output" },
140  { MFX_ERR_MORE_BITSTREAM, AVERROR_UNKNOWN, "expect more bitstream at output" },
141  { MFX_ERR_ABORTED, AVERROR_UNKNOWN, "operation aborted" },
142  { MFX_ERR_DEVICE_LOST, AVERROR(EIO), "device lost" },
143  { MFX_ERR_INCOMPATIBLE_VIDEO_PARAM, AVERROR(EINVAL), "incompatible video parameters" },
144  { MFX_ERR_INVALID_VIDEO_PARAM, AVERROR(EINVAL), "invalid video parameters" },
145  { MFX_ERR_UNDEFINED_BEHAVIOR, AVERROR_BUG, "undefined behavior" },
146  { MFX_ERR_DEVICE_FAILED, AVERROR(EIO), "device failed" },
147  { MFX_ERR_INCOMPATIBLE_AUDIO_PARAM, AVERROR(EINVAL), "incompatible audio parameters" },
148  { MFX_ERR_INVALID_AUDIO_PARAM, AVERROR(EINVAL), "invalid audio parameters" },
149 
150  { MFX_WRN_IN_EXECUTION, 0, "operation in execution" },
151  { MFX_WRN_DEVICE_BUSY, 0, "device busy" },
152  { MFX_WRN_VIDEO_PARAM_CHANGED, 0, "video parameters changed" },
153  { MFX_WRN_PARTIAL_ACCELERATION, 0, "partial acceleration" },
154  { MFX_WRN_INCOMPATIBLE_VIDEO_PARAM, 0, "incompatible video parameters" },
155  { MFX_WRN_VALUE_NOT_CHANGED, 0, "value is saturated" },
156  { MFX_WRN_OUT_OF_RANGE, 0, "value out of range" },
157  { MFX_WRN_FILTER_SKIPPED, 0, "filter skipped" },
158  { MFX_WRN_INCOMPATIBLE_AUDIO_PARAM, 0, "incompatible audio parameters" },
159 };
160 
161 int ff_qsv_map_error(mfxStatus mfx_err, const char **desc)
162 {
163  int i;
164  for (i = 0; i < FF_ARRAY_ELEMS(qsv_errors); i++) {
165  if (qsv_errors[i].mfxerr == mfx_err) {
166  if (desc)
167  *desc = qsv_errors[i].desc;
168  return qsv_errors[i].averr;
169  }
170  }
171  if (desc)
172  *desc = "unknown error";
173  return AVERROR_UNKNOWN;
174 }
175 
176 int ff_qsv_print_error(void *log_ctx, mfxStatus err,
177  const char *error_string)
178 {
179  const char *desc;
180  int ret;
181  ret = ff_qsv_map_error(err, &desc);
182  av_log(log_ctx, AV_LOG_ERROR, "%s: %s (%d)\n", error_string, desc, err);
183  return ret;
184 }
185 
186 int ff_qsv_print_warning(void *log_ctx, mfxStatus err,
187  const char *warning_string)
188 {
189  const char *desc;
190  int ret;
191  ret = ff_qsv_map_error(err, &desc);
192  av_log(log_ctx, AV_LOG_WARNING, "%s: %s (%d)\n", warning_string, desc, err);
193  return ret;
194 }
195 
197 {
198  switch (fourcc) {
199  case MFX_FOURCC_NV12: return AV_PIX_FMT_NV12;
200  case MFX_FOURCC_P010: return AV_PIX_FMT_P010;
201  case MFX_FOURCC_P8: return AV_PIX_FMT_PAL8;
202 #if CONFIG_VAAPI
203  case MFX_FOURCC_YUY2: return AV_PIX_FMT_YUYV422;
204 #if QSV_VERSION_ATLEAST(1, 27)
205  case MFX_FOURCC_Y210: return AV_PIX_FMT_Y210;
206 #endif
207 #endif
208  }
209  return AV_PIX_FMT_NONE;
210 }
211 
213 {
214  switch (format) {
215  case AV_PIX_FMT_YUV420P:
216  case AV_PIX_FMT_YUVJ420P:
217  case AV_PIX_FMT_NV12:
218  *fourcc = MFX_FOURCC_NV12;
219  return AV_PIX_FMT_NV12;
221  case AV_PIX_FMT_P010:
222  *fourcc = MFX_FOURCC_P010;
223  return AV_PIX_FMT_P010;
224 #if CONFIG_VAAPI
225  case AV_PIX_FMT_YUV422P:
226  case AV_PIX_FMT_YUYV422:
227  *fourcc = MFX_FOURCC_YUY2;
228  return AV_PIX_FMT_YUYV422;
229 #if QSV_VERSION_ATLEAST(1, 27)
231  case AV_PIX_FMT_Y210:
232  *fourcc = MFX_FOURCC_Y210;
233  return AV_PIX_FMT_Y210;
234 #endif
235 #endif
236  default:
237  return AVERROR(ENOSYS);
238  }
239 }
240 
242 {
243  int i;
244  for (i = 0; i < ctx->nb_mids; i++) {
245  QSVMid *mid = &ctx->mids[i];
246  if (mid->handle == frame->surface.Data.MemId)
247  return i;
248  }
249  return AVERROR_BUG;
250 }
251 
252 enum AVFieldOrder ff_qsv_map_picstruct(int mfx_pic_struct)
253 {
255  switch (mfx_pic_struct & 0xF) {
256  case MFX_PICSTRUCT_PROGRESSIVE:
257  field = AV_FIELD_PROGRESSIVE;
258  break;
259  case MFX_PICSTRUCT_FIELD_TFF:
260  field = AV_FIELD_TT;
261  break;
262  case MFX_PICSTRUCT_FIELD_BFF:
263  field = AV_FIELD_BB;
264  break;
265  }
266 
267  return field;
268 }
269 
270 enum AVPictureType ff_qsv_map_pictype(int mfx_pic_type)
271 {
272  enum AVPictureType type;
273  switch (mfx_pic_type & 0x7) {
274  case MFX_FRAMETYPE_I:
275  if (mfx_pic_type & MFX_FRAMETYPE_S)
276  type = AV_PICTURE_TYPE_SI;
277  else
278  type = AV_PICTURE_TYPE_I;
279  break;
280  case MFX_FRAMETYPE_B:
281  type = AV_PICTURE_TYPE_B;
282  break;
283  case MFX_FRAMETYPE_P:
284  if (mfx_pic_type & MFX_FRAMETYPE_S)
285  type = AV_PICTURE_TYPE_SP;
286  else
287  type = AV_PICTURE_TYPE_P;
288  break;
289  case MFX_FRAMETYPE_UNKNOWN:
290  type = AV_PICTURE_TYPE_NONE;
291  break;
292  default:
293  av_assert0(0);
294  }
295 
296  return type;
297 }
298 
299 static int qsv_load_plugins(mfxSession session, const char *load_plugins,
300  void *logctx)
301 {
302  if (!load_plugins || !*load_plugins)
303  return 0;
304 
305  while (*load_plugins) {
306  mfxPluginUID uid;
307  mfxStatus ret;
308  int i, err = 0;
309 
310  char *plugin = av_get_token(&load_plugins, ":");
311  if (!plugin)
312  return AVERROR(ENOMEM);
313  if (strlen(plugin) != 2 * sizeof(uid.Data)) {
314  av_log(logctx, AV_LOG_ERROR, "Invalid plugin UID length\n");
315  err = AVERROR(EINVAL);
316  goto load_plugin_fail;
317  }
318 
319  for (i = 0; i < sizeof(uid.Data); i++) {
320  err = sscanf(plugin + 2 * i, "%2hhx", uid.Data + i);
321  if (err != 1) {
322  av_log(logctx, AV_LOG_ERROR, "Invalid plugin UID\n");
323  err = AVERROR(EINVAL);
324  goto load_plugin_fail;
325  }
326 
327  }
328 
329  ret = MFXVideoUSER_Load(session, &uid, 1);
330  if (ret < 0) {
331  char errorbuf[128];
332  snprintf(errorbuf, sizeof(errorbuf),
333  "Could not load the requested plugin '%s'", plugin);
334  err = ff_qsv_print_error(logctx, ret, errorbuf);
335  goto load_plugin_fail;
336  }
337 
338  if (*load_plugins)
339  load_plugins++;
340 load_plugin_fail:
341  av_freep(&plugin);
342  if (err < 0)
343  return err;
344  }
345 
346  return 0;
347 
348 }
349 
350 //This code is only required for Linux since a display handle is required.
351 //For Windows the session is complete and ready to use.
352 
353 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
354 static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)
355 {
356  AVDictionary *child_device_opts = NULL;
357  AVVAAPIDeviceContext *hwctx;
358  int ret;
359 
360  av_dict_set(&child_device_opts, "kernel_driver", "i915", 0);
361  av_dict_set(&child_device_opts, "driver", "iHD", 0);
362 
363  ret = av_hwdevice_ctx_create(&qs->va_device_ref, AV_HWDEVICE_TYPE_VAAPI, NULL, child_device_opts, 0);
364  av_dict_free(&child_device_opts);
365  if (ret < 0) {
366  av_log(avctx, AV_LOG_ERROR, "Failed to create a VAAPI device.\n");
367  return ret;
368  } else {
369  qs->va_device_ctx = (AVHWDeviceContext*)qs->va_device_ref->data;
370  hwctx = qs->va_device_ctx->hwctx;
371 
372  ret = MFXVideoCORE_SetHandle(qs->session,
373  (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)hwctx->display);
374  if (ret < 0) {
375  return ff_qsv_print_error(avctx, ret, "Error during set display handle\n");
376  }
377  }
378 
379  return 0;
380 }
381 #endif //AVCODEC_QSV_LINUX_SESSION_HANDLE
382 
384  const char *load_plugins, int gpu_copy)
385 {
386  mfxIMPL impl = MFX_IMPL_AUTO_ANY;
387  mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
388  mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
389 
390  const char *desc;
391  int ret;
392 
393 #if QSV_VERSION_ATLEAST(1, 16)
394  init_par.GPUCopy = gpu_copy;
395 #endif
396  init_par.Implementation = impl;
397  init_par.Version = ver;
398  ret = MFXInitEx(init_par, &qs->session);
399  if (ret < 0)
400  return ff_qsv_print_error(avctx, ret,
401  "Error initializing an internal MFX session");
402 
403 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
404  ret = ff_qsv_set_display_handle(avctx, qs);
405  if (ret < 0)
406  return ret;
407 #endif
408 
409  ret = qsv_load_plugins(qs->session, load_plugins, avctx);
410  if (ret < 0) {
411  av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
412  return ret;
413  }
414 
415  MFXQueryIMPL(qs->session, &impl);
416 
417  switch (MFX_IMPL_BASETYPE(impl)) {
418  case MFX_IMPL_SOFTWARE:
419  desc = "software";
420  break;
421  case MFX_IMPL_HARDWARE:
422  case MFX_IMPL_HARDWARE2:
423  case MFX_IMPL_HARDWARE3:
424  case MFX_IMPL_HARDWARE4:
425  desc = "hardware accelerated";
426  break;
427  default:
428  desc = "unknown";
429  }
430 
431  av_log(avctx, AV_LOG_VERBOSE,
432  "Initialized an internal MFX session using %s implementation\n",
433  desc);
434 
435  return 0;
436 }
437 
438 static void mids_buf_free(void *opaque, uint8_t *data)
439 {
440  AVBufferRef *hw_frames_ref = opaque;
441  av_buffer_unref(&hw_frames_ref);
442  av_freep(&data);
443 }
444 
445 static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref)
446 {
447  AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data;
448  AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
449  int nb_surfaces = frames_hwctx->nb_surfaces;
450 
451  AVBufferRef *mids_buf, *hw_frames_ref1;
452  QSVMid *mids;
453  int i;
454 
455  hw_frames_ref1 = av_buffer_ref(hw_frames_ref);
456  if (!hw_frames_ref1)
457  return NULL;
458 
459  mids = av_mallocz_array(nb_surfaces, sizeof(*mids));
460  if (!mids) {
461  av_buffer_unref(&hw_frames_ref1);
462  return NULL;
463  }
464 
465  mids_buf = av_buffer_create((uint8_t*)mids, nb_surfaces * sizeof(*mids),
466  mids_buf_free, hw_frames_ref1, 0);
467  if (!mids_buf) {
468  av_buffer_unref(&hw_frames_ref1);
469  av_freep(&mids);
470  return NULL;
471  }
472 
473  for (i = 0; i < nb_surfaces; i++) {
474  QSVMid *mid = &mids[i];
475  mid->handle = frames_hwctx->surfaces[i].Data.MemId;
476  mid->hw_frames_ref = hw_frames_ref1;
477  }
478 
479  return mids_buf;
480 }
481 
482 static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_ref,
483  AVBufferRef *mids_buf)
484 {
485  AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data;
486  AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
487  QSVMid *mids = (QSVMid*)mids_buf->data;
488  int nb_surfaces = frames_hwctx->nb_surfaces;
489  int i;
490 
491  // the allocated size of the array is two larger than the number of
492  // surfaces, we store the references to the frames context and the
493  // QSVMid array there
494  resp->mids = av_mallocz_array(nb_surfaces + 2, sizeof(*resp->mids));
495  if (!resp->mids)
496  return AVERROR(ENOMEM);
497 
498  for (i = 0; i < nb_surfaces; i++)
499  resp->mids[i] = &mids[i];
500  resp->NumFrameActual = nb_surfaces;
501 
502  resp->mids[resp->NumFrameActual] = (mfxMemId)av_buffer_ref(hw_frames_ref);
503  if (!resp->mids[resp->NumFrameActual]) {
504  av_freep(&resp->mids);
505  return AVERROR(ENOMEM);
506  }
507 
508  resp->mids[resp->NumFrameActual + 1] = av_buffer_ref(mids_buf);
509  if (!resp->mids[resp->NumFrameActual + 1]) {
510  av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]);
511  av_freep(&resp->mids);
512  return AVERROR(ENOMEM);
513  }
514 
515  return 0;
516 }
517 
518 static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
519  mfxFrameAllocResponse *resp)
520 {
521  QSVFramesContext *ctx = pthis;
522  int ret;
523 
524  /* this should only be called from an encoder or decoder and
525  * only allocates video memory frames */
526  if (!(req->Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET |
527  MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)) ||
528  !(req->Type & (MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_ENCODE)))
529  return MFX_ERR_UNSUPPORTED;
530 
531  if (req->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
532  /* external frames -- fill from the caller-supplied frames context */
534  AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
535  mfxFrameInfo *i = &req->Info;
536  mfxFrameInfo *i1 = &frames_hwctx->surfaces[0].Info;
537 
538  if (i->Width > i1->Width || i->Height > i1->Height ||
539  i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) {
540  av_log(ctx->logctx, AV_LOG_ERROR, "Mismatching surface properties in an "
541  "allocation request: %dx%d %d %d vs %dx%d %d %d\n",
542  i->Width, i->Height, i->FourCC, i->ChromaFormat,
543  i1->Width, i1->Height, i1->FourCC, i1->ChromaFormat);
544  return MFX_ERR_UNSUPPORTED;
545  }
546 
547  ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids_buf);
548  if (ret < 0) {
549  av_log(ctx->logctx, AV_LOG_ERROR,
550  "Error filling an external frame allocation request\n");
551  return MFX_ERR_MEMORY_ALLOC;
552  }
553  } else if (req->Type & MFX_MEMTYPE_INTERNAL_FRAME) {
554  /* internal frames -- allocate a new hw frames context */
555  AVHWFramesContext *ext_frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data;
556  mfxFrameInfo *i = &req->Info;
557 
558  AVBufferRef *frames_ref, *mids_buf;
559  AVHWFramesContext *frames_ctx;
560  AVQSVFramesContext *frames_hwctx;
561 
562  frames_ref = av_hwframe_ctx_alloc(ext_frames_ctx->device_ref);
563  if (!frames_ref)
564  return MFX_ERR_MEMORY_ALLOC;
565 
566  frames_ctx = (AVHWFramesContext*)frames_ref->data;
567  frames_hwctx = frames_ctx->hwctx;
568 
569  frames_ctx->format = AV_PIX_FMT_QSV;
570  frames_ctx->sw_format = ff_qsv_map_fourcc(i->FourCC);
571  frames_ctx->width = i->Width;
572  frames_ctx->height = i->Height;
573  frames_ctx->initial_pool_size = req->NumFrameSuggested;
574 
575  frames_hwctx->frame_type = req->Type;
576 
577  ret = av_hwframe_ctx_init(frames_ref);
578  if (ret < 0) {
579  av_log(ctx->logctx, AV_LOG_ERROR,
580  "Error initializing a frames context for an internal frame "
581  "allocation request\n");
582  av_buffer_unref(&frames_ref);
583  return MFX_ERR_MEMORY_ALLOC;
584  }
585 
586  mids_buf = qsv_create_mids(frames_ref);
587  if (!mids_buf) {
588  av_buffer_unref(&frames_ref);
589  return MFX_ERR_MEMORY_ALLOC;
590  }
591 
592  ret = qsv_setup_mids(resp, frames_ref, mids_buf);
593  av_buffer_unref(&mids_buf);
594  av_buffer_unref(&frames_ref);
595  if (ret < 0) {
596  av_log(ctx->logctx, AV_LOG_ERROR,
597  "Error filling an internal frame allocation request\n");
598  return MFX_ERR_MEMORY_ALLOC;
599  }
600  } else {
601  return MFX_ERR_UNSUPPORTED;
602  }
603 
604  return MFX_ERR_NONE;
605 }
606 
607 static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp)
608 {
609  av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]);
610  av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual + 1]);
611  av_freep(&resp->mids);
612  return MFX_ERR_NONE;
613 }
614 
615 static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
616 {
617  QSVMid *qsv_mid = mid;
618  AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)qsv_mid->hw_frames_ref->data;
619  AVQSVFramesContext *hw_frames_hwctx = hw_frames_ctx->hwctx;
620  int ret;
621 
622  if (qsv_mid->locked_frame)
623  return MFX_ERR_UNDEFINED_BEHAVIOR;
624 
625  /* Allocate a system memory frame that will hold the mapped data. */
626  qsv_mid->locked_frame = av_frame_alloc();
627  if (!qsv_mid->locked_frame)
628  return MFX_ERR_MEMORY_ALLOC;
629  qsv_mid->locked_frame->format = hw_frames_ctx->sw_format;
630 
631  /* wrap the provided handle in a hwaccel AVFrame */
632  qsv_mid->hw_frame = av_frame_alloc();
633  if (!qsv_mid->hw_frame)
634  goto fail;
635 
636  qsv_mid->hw_frame->data[3] = (uint8_t*)&qsv_mid->surf;
637  qsv_mid->hw_frame->format = AV_PIX_FMT_QSV;
638 
639  // doesn't really matter what buffer is used here
640  qsv_mid->hw_frame->buf[0] = av_buffer_alloc(1);
641  if (!qsv_mid->hw_frame->buf[0])
642  goto fail;
643 
644  qsv_mid->hw_frame->width = hw_frames_ctx->width;
645  qsv_mid->hw_frame->height = hw_frames_ctx->height;
646 
647  qsv_mid->hw_frame->hw_frames_ctx = av_buffer_ref(qsv_mid->hw_frames_ref);
648  if (!qsv_mid->hw_frame->hw_frames_ctx)
649  goto fail;
650 
651  qsv_mid->surf.Info = hw_frames_hwctx->surfaces[0].Info;
652  qsv_mid->surf.Data.MemId = qsv_mid->handle;
653 
654  /* map the data to the system memory */
655  ret = av_hwframe_map(qsv_mid->locked_frame, qsv_mid->hw_frame,
657  if (ret < 0)
658  goto fail;
659 
660  ptr->Pitch = qsv_mid->locked_frame->linesize[0];
661  ptr->Y = qsv_mid->locked_frame->data[0];
662  ptr->U = qsv_mid->locked_frame->data[1];
663  ptr->V = qsv_mid->locked_frame->data[1] + 1;
664 
665  return MFX_ERR_NONE;
666 fail:
667  av_frame_free(&qsv_mid->hw_frame);
668  av_frame_free(&qsv_mid->locked_frame);
669  return MFX_ERR_MEMORY_ALLOC;
670 }
671 
672 static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
673 {
674  QSVMid *qsv_mid = mid;
675 
676  av_frame_free(&qsv_mid->locked_frame);
677  av_frame_free(&qsv_mid->hw_frame);
678 
679  return MFX_ERR_NONE;
680 }
681 
682 static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
683 {
684  QSVMid *qsv_mid = (QSVMid*)mid;
685  *hdl = qsv_mid->handle;
686  return MFX_ERR_NONE;
687 }
688 
689 int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
690  AVBufferRef *device_ref, const char *load_plugins,
691  int gpu_copy)
692 {
693  static const mfxHandleType handle_types[] = {
694  MFX_HANDLE_VA_DISPLAY,
695  MFX_HANDLE_D3D9_DEVICE_MANAGER,
696  MFX_HANDLE_D3D11_DEVICE,
697  };
698  AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref->data;
699  AVQSVDeviceContext *device_hwctx = device_ctx->hwctx;
700  mfxSession parent_session = device_hwctx->session;
701  mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
702  mfxHDL handle = NULL;
703 
704  mfxSession session;
705  mfxVersion ver;
706  mfxIMPL impl;
707  mfxHandleType handle_type;
708  mfxStatus err;
709 
710  int i, ret;
711 
712  err = MFXQueryIMPL(parent_session, &impl);
713  if (err == MFX_ERR_NONE)
714  err = MFXQueryVersion(parent_session, &ver);
715  if (err != MFX_ERR_NONE)
716  return ff_qsv_print_error(avctx, err,
717  "Error querying the session attributes");
718 
719  for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) {
720  err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &handle);
721  if (err == MFX_ERR_NONE) {
723  break;
724  }
725  handle = NULL;
726  }
727  if (!handle) {
728  av_log(avctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved "
729  "from the session\n");
730  }
731 
732 #if QSV_VERSION_ATLEAST(1, 16)
733  init_par.GPUCopy = gpu_copy;
734 #endif
735  init_par.Implementation = impl;
736  init_par.Version = ver;
737  err = MFXInitEx(init_par, &session);
738  if (err != MFX_ERR_NONE)
739  return ff_qsv_print_error(avctx, err,
740  "Error initializing a child MFX session");
741 
742  if (handle) {
743  err = MFXVideoCORE_SetHandle(session, handle_type, handle);
744  if (err != MFX_ERR_NONE)
745  return ff_qsv_print_error(avctx, err,
746  "Error setting a HW handle");
747  }
748 
749  if (QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) {
750  err = MFXJoinSession(parent_session, session);
751  if (err != MFX_ERR_NONE)
752  return ff_qsv_print_error(avctx, err,
753  "Error joining session");
754  }
755 
756  ret = qsv_load_plugins(session, load_plugins, avctx);
757  if (ret < 0) {
758  av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
759  return ret;
760  }
761 
762  *psession = session;
763  return 0;
764 }
765 
766 int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession,
767  QSVFramesContext *qsv_frames_ctx,
768  const char *load_plugins, int opaque, int gpu_copy)
769 {
770  mfxFrameAllocator frame_allocator = {
771  .pthis = qsv_frames_ctx,
772  .Alloc = qsv_frame_alloc,
773  .Lock = qsv_frame_lock,
774  .Unlock = qsv_frame_unlock,
775  .GetHDL = qsv_frame_get_hdl,
776  .Free = qsv_frame_free,
777  };
778 
779  AVHWFramesContext *frames_ctx = (AVHWFramesContext*)qsv_frames_ctx->hw_frames_ctx->data;
780  AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
781 
782  mfxSession session;
783  mfxStatus err;
784 
785  int ret;
786 
787  ret = ff_qsv_init_session_device(avctx, &session,
788  frames_ctx->device_ref, load_plugins, gpu_copy);
789  if (ret < 0)
790  return ret;
791 
792  if (!opaque) {
793  qsv_frames_ctx->logctx = avctx;
794 
795  /* allocate the memory ids for the external frames */
796  av_buffer_unref(&qsv_frames_ctx->mids_buf);
797  qsv_frames_ctx->mids_buf = qsv_create_mids(qsv_frames_ctx->hw_frames_ctx);
798  if (!qsv_frames_ctx->mids_buf)
799  return AVERROR(ENOMEM);
800  qsv_frames_ctx->mids = (QSVMid*)qsv_frames_ctx->mids_buf->data;
801  qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces;
802 
803  err = MFXVideoCORE_SetFrameAllocator(session, &frame_allocator);
804  if (err != MFX_ERR_NONE)
805  return ff_qsv_print_error(avctx, err,
806  "Error setting a frame allocator");
807  }
808 
809  *psession = session;
810  return 0;
811 }
812 
814 {
815  if (qs->session) {
816  MFXClose(qs->session);
817  qs->session = NULL;
818  }
819 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
820  av_buffer_unref(&qs->va_device_ref);
821 #endif
822  return 0;
823 }
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
#define NULL
Definition: coverity.c:32
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:125
static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, mfxFrameAllocResponse *resp)
Definition: qsv.c:518
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
static const mfxHandleType handle_types[]
Definition: qsvvpp.c:71
static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
Definition: qsv.c:672
misc image utilities
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
mfxHandleType handle_type
Definition: hwcontext_qsv.c:89
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:499
This struct is allocated as AVHWFramesContext.hwctx.
Definition: hwcontext_qsv.h:42
uint32_t fourcc
Definition: vaapi_decode.c:239
static int qsv_load_plugins(mfxSession session, const char *load_plugins, void *logctx)
Definition: qsv.c:299
int ff_qsv_level_to_mfx(enum AVCodecID codec_id, int level)
Definition: qsv.c:79
int averr
Definition: qsv.c:123
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
#define QSV_RUNTIME_VERSION_ATLEAST(MFX_VERSION, MAJOR, MINOR)
Definition: qsv_internal.h:59
GLint GLenum type
Definition: opengl_enc.c:104
int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession, AVBufferRef *device_ref, const char *load_plugins, int gpu_copy)
Definition: qsv.c:689
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate.The lists are not just lists
AVFrame * locked_frame
Definition: qsv_internal.h:67
AVBufferRef * hw_frames_ctx
Definition: qsv_internal.h:94
int ff_qsv_print_error(void *log_ctx, mfxStatus err, const char *error_string)
Definition: qsv.c:176
Undefined.
Definition: avutil.h:273
Switching Intra.
Definition: avutil.h:278
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame...
Definition: frame.h:647
UID uid
Definition: mxfenc.c:2165
#define FF_LEVEL_UNKNOWN
Definition: avcodec.h:1983
#define AV_PIX_FMT_P010
Definition: pixfmt.h:448
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
uint8_t
AVFrame * hw_frame
Definition: qsv_internal.h:68
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
AVBufferRef * mids_buf
Definition: qsv_internal.h:101
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
static void mids_buf_free(void *opaque, uint8_t *data)
Definition: qsv.c:438
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:92
int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, const char *device, AVDictionary *opts, int flags)
Open a device of the specified type and create an AVHWDeviceContext for it.
Definition: hwcontext.c:610
int mfx_iopattern
Definition: qsv.c:93
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:210
int ff_qsv_map_error(mfxStatus mfx_err, const char **desc)
Convert a libmfx error code into an ffmpeg error code.
Definition: qsv.c:161
#define av_log(a,...)
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_qsv.h:35
int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession, QSVFramesContext *qsv_frames_ctx, const char *load_plugins, int opaque, int gpu_copy)
Definition: qsv.c:766
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:46
int width
Definition: frame.h:366
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
int ff_qsv_find_surface_idx(QSVFramesContext *ctx, QSVFrame *frame)
Definition: qsv.c:241
error code definitions
The mapping must be direct.
Definition: hwcontext.h:540
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this field
static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp)
Definition: qsv.c:607
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:203
mfxHDL handle
Definition: qsv_internal.h:65
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:89
int ff_qsv_print_iopattern(void *log_ctx, int mfx_iopattern, const char *extra_string)
Definition: qsv.c:104
simple assert() macros that are a bit more flexible than ISO C assert().
AVBufferRef * av_buffer_create(uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:333
int ff_qsv_close_internal_session(QSVSession *qs)
Definition: qsv.c:813
enum AVPictureType ff_qsv_map_pictype(int mfx_pic_type)
Definition: qsv.c:270
#define fail()
Definition: checkasm.h:123
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition: avstring.c:151
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
int ff_qsv_print_warning(void *log_ctx, mfxStatus err, const char *warning_string)
Definition: qsv.c:186
int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc)
Definition: qsv.c:212
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition: pixfmt.h:78
#define QSV_VERSION_MINOR
Definition: qsv_internal.h:49
const char * desc
Definition: qsv.c:94
int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id)
Definition: qsv.c:43
static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
Definition: qsv.c:682
AVFormatContext * ctx
Definition: movenc.c:48
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
enum AVCodecID codec_id
Definition: vaapi_decode.c:369
mfxFrameSurface1 surface
Definition: qsv_internal.h:74
preferred ID for MPEG-1/2 video decoding
Definition: codec_id.h:51
#define FF_ARRAY_ELEMS(a)
if(ret)
VADisplay display
The VADisplay handle, to be filled by the user.
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:381
Libavcodec external API header.
AVBufferRef * av_buffer_alloc(int size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:67
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:339
main external API structure.
Definition: avcodec.h:526
uint8_t * data
The data buffer.
Definition: buffer.h:89
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:162
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:67
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:70
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:399
Switching Predicted.
Definition: avutil.h:279
AVBufferRef * hw_frames_ref
Definition: qsv_internal.h:64
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
HW acceleration through QSV, data[3] contains a pointer to the mfxFrameSurface1 structure.
Definition: pixfmt.h:222
int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs, const char *load_plugins, int gpu_copy)
Definition: qsv.c:383
AVPictureType
Definition: avutil.h:272
#define snprintf
Definition: snprintf.h:34
static const struct @122 qsv_errors[]
static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_ref, AVBufferRef *mids_buf)
Definition: qsv.c:482
static AVBufferRef * qsv_create_mids(AVBufferRef *hw_frames_ref)
Definition: qsv.c:445
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:400
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:322
uint8_t level
Definition: svq3.c:205
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:141
AVFieldOrder
Definition: codec_par.h:36
mfxStatus mfxerr
Definition: qsv.c:122
A reference to a data buffer.
Definition: buffer.h:81
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
common internal and external API header
static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
Definition: qsv.c:615
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition: hwcontext.c:789
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:247
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
mfxFrameSurface1 surf
Definition: qsv_internal.h:69
Bi-dir predicted.
Definition: avutil.h:276
#define QSV_VERSION_MAJOR
Definition: qsv_internal.h:48
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
static const struct @121 qsv_iopatterns[]
VAAPI connection details.
int height
Definition: frame.h:366
enum AVFieldOrder ff_qsv_map_picstruct(int mfx_pic_struct)
Definition: qsv.c:252
#define av_freep(p)
An API-specific header for AV_HWDEVICE_TYPE_QSV.
#define AV_PIX_FMT_Y210
Definition: pixfmt.h:451
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:222
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
mfxSession session
Definition: qsv_internal.h:86
int i
Definition: input.c:407
Predicted.
Definition: avutil.h:275
enum AVPixelFormat ff_qsv_map_fourcc(uint32_t fourcc)
Definition: qsv.c:196
void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.c:190