You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
9.6KB

  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. #include <mfx/mfxvideo.h>
  21. #include <mfx/mfxplugin.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include "libavutil/avstring.h"
  25. #include "libavutil/common.h"
  26. #include "libavutil/error.h"
  27. #include "libavutil/hwcontext.h"
  28. #include "libavutil/hwcontext_qsv.h"
  29. #include "avcodec.h"
  30. #include "qsv_internal.h"
  31. int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id)
  32. {
  33. switch (codec_id) {
  34. case AV_CODEC_ID_H264:
  35. return MFX_CODEC_AVC;
  36. #if QSV_VERSION_ATLEAST(1, 8)
  37. case AV_CODEC_ID_HEVC:
  38. return MFX_CODEC_HEVC;
  39. #endif
  40. case AV_CODEC_ID_MPEG1VIDEO:
  41. case AV_CODEC_ID_MPEG2VIDEO:
  42. return MFX_CODEC_MPEG2;
  43. case AV_CODEC_ID_VC1:
  44. return MFX_CODEC_VC1;
  45. default:
  46. break;
  47. }
  48. return AVERROR(ENOSYS);
  49. }
  50. int ff_qsv_error(int mfx_err)
  51. {
  52. switch (mfx_err) {
  53. case MFX_ERR_NONE:
  54. return 0;
  55. case MFX_ERR_MEMORY_ALLOC:
  56. case MFX_ERR_NOT_ENOUGH_BUFFER:
  57. return AVERROR(ENOMEM);
  58. case MFX_ERR_INVALID_HANDLE:
  59. return AVERROR(EINVAL);
  60. case MFX_ERR_DEVICE_FAILED:
  61. case MFX_ERR_DEVICE_LOST:
  62. case MFX_ERR_LOCK_MEMORY:
  63. return AVERROR(EIO);
  64. case MFX_ERR_NULL_PTR:
  65. case MFX_ERR_UNDEFINED_BEHAVIOR:
  66. case MFX_ERR_NOT_INITIALIZED:
  67. return AVERROR_BUG;
  68. case MFX_ERR_UNSUPPORTED:
  69. case MFX_ERR_NOT_FOUND:
  70. return AVERROR(ENOSYS);
  71. case MFX_ERR_MORE_DATA:
  72. case MFX_ERR_MORE_SURFACE:
  73. case MFX_ERR_MORE_BITSTREAM:
  74. return AVERROR(EAGAIN);
  75. case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
  76. case MFX_ERR_INVALID_VIDEO_PARAM:
  77. return AVERROR(EINVAL);
  78. case MFX_ERR_ABORTED:
  79. case MFX_ERR_UNKNOWN:
  80. default:
  81. return AVERROR_UNKNOWN;
  82. }
  83. }
  84. static int qsv_load_plugins(mfxSession session, const char *load_plugins,
  85. void *logctx)
  86. {
  87. if (!load_plugins || !*load_plugins)
  88. return 0;
  89. while (*load_plugins) {
  90. mfxPluginUID uid;
  91. mfxStatus ret;
  92. int i, err = 0;
  93. char *plugin = av_get_token(&load_plugins, ":");
  94. if (!plugin)
  95. return AVERROR(ENOMEM);
  96. if (strlen(plugin) != 2 * sizeof(uid.Data)) {
  97. av_log(logctx, AV_LOG_ERROR, "Invalid plugin UID length\n");
  98. err = AVERROR(EINVAL);
  99. goto load_plugin_fail;
  100. }
  101. for (i = 0; i < sizeof(uid.Data); i++) {
  102. err = sscanf(plugin + 2 * i, "%2hhx", uid.Data + i);
  103. if (err != 1) {
  104. av_log(logctx, AV_LOG_ERROR, "Invalid plugin UID\n");
  105. err = AVERROR(EINVAL);
  106. goto load_plugin_fail;
  107. }
  108. }
  109. ret = MFXVideoUSER_Load(session, &uid, 1);
  110. if (ret < 0) {
  111. av_log(logctx, AV_LOG_ERROR, "Could not load the requested plugin: %s\n",
  112. plugin);
  113. err = ff_qsv_error(ret);
  114. goto load_plugin_fail;
  115. }
  116. if (*load_plugins)
  117. load_plugins++;
  118. load_plugin_fail:
  119. av_freep(&plugin);
  120. if (err < 0)
  121. return err;
  122. }
  123. return 0;
  124. }
  125. int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
  126. const char *load_plugins)
  127. {
  128. mfxIMPL impl = MFX_IMPL_AUTO_ANY;
  129. mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
  130. const char *desc;
  131. int ret;
  132. ret = MFXInit(impl, &ver, session);
  133. if (ret < 0) {
  134. av_log(avctx, AV_LOG_ERROR, "Error initializing an internal MFX session\n");
  135. return ff_qsv_error(ret);
  136. }
  137. ret = qsv_load_plugins(*session, load_plugins, avctx);
  138. if (ret < 0) {
  139. av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
  140. return ret;
  141. }
  142. MFXQueryIMPL(*session, &impl);
  143. switch (MFX_IMPL_BASETYPE(impl)) {
  144. case MFX_IMPL_SOFTWARE:
  145. desc = "software";
  146. break;
  147. case MFX_IMPL_HARDWARE:
  148. case MFX_IMPL_HARDWARE2:
  149. case MFX_IMPL_HARDWARE3:
  150. case MFX_IMPL_HARDWARE4:
  151. desc = "hardware accelerated";
  152. break;
  153. default:
  154. desc = "unknown";
  155. }
  156. av_log(avctx, AV_LOG_VERBOSE,
  157. "Initialized an internal MFX session using %s implementation\n",
  158. desc);
  159. return 0;
  160. }
  161. static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
  162. mfxFrameAllocResponse *resp)
  163. {
  164. QSVFramesContext *ctx = pthis;
  165. mfxFrameInfo *i = &req->Info;
  166. mfxFrameInfo *i1 = &ctx->info;
  167. if (!(req->Type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) ||
  168. !(req->Type & (MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_ENCODE)) ||
  169. !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME))
  170. return MFX_ERR_UNSUPPORTED;
  171. if (i->Width != i1->Width || i->Height != i1->Height ||
  172. i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) {
  173. av_log(ctx, AV_LOG_ERROR, "Mismatching surface properties in an "
  174. "allocation request: %dx%d %d %d vs %dx%d %d %d\n",
  175. i->Width, i->Height, i->FourCC, i->ChromaFormat,
  176. i1->Width, i1->Height, i1->FourCC, i1->ChromaFormat);
  177. return MFX_ERR_UNSUPPORTED;
  178. }
  179. resp->mids = ctx->mids;
  180. resp->NumFrameActual = ctx->nb_mids;
  181. return MFX_ERR_NONE;
  182. }
  183. static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp)
  184. {
  185. return MFX_ERR_NONE;
  186. }
  187. static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
  188. {
  189. return MFX_ERR_UNSUPPORTED;
  190. }
  191. static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
  192. {
  193. return MFX_ERR_UNSUPPORTED;
  194. }
  195. static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
  196. {
  197. *hdl = mid;
  198. return MFX_ERR_NONE;
  199. }
  200. int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *psession,
  201. QSVFramesContext *qsv_frames_ctx,
  202. const char *load_plugins, int opaque)
  203. {
  204. static const mfxHandleType handle_types[] = {
  205. MFX_HANDLE_VA_DISPLAY,
  206. MFX_HANDLE_D3D9_DEVICE_MANAGER,
  207. MFX_HANDLE_D3D11_DEVICE,
  208. };
  209. mfxFrameAllocator frame_allocator = {
  210. .pthis = qsv_frames_ctx,
  211. .Alloc = qsv_frame_alloc,
  212. .Lock = qsv_frame_lock,
  213. .Unlock = qsv_frame_unlock,
  214. .GetHDL = qsv_frame_get_hdl,
  215. .Free = qsv_frame_free,
  216. };
  217. AVHWFramesContext *frames_ctx = (AVHWFramesContext*)qsv_frames_ctx->hw_frames_ctx->data;
  218. AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
  219. AVQSVDeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
  220. mfxSession parent_session = device_hwctx->session;
  221. mfxSession session;
  222. mfxVersion ver;
  223. mfxIMPL impl;
  224. mfxHDL handle = NULL;
  225. mfxHandleType handle_type;
  226. mfxStatus err;
  227. int i, ret;
  228. err = MFXQueryIMPL(parent_session, &impl);
  229. if (err == MFX_ERR_NONE)
  230. err = MFXQueryVersion(parent_session, &ver);
  231. if (err != MFX_ERR_NONE) {
  232. av_log(avctx, AV_LOG_ERROR, "Error querying the session attributes\n");
  233. return ff_qsv_error(err);
  234. }
  235. for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) {
  236. err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &handle);
  237. if (err == MFX_ERR_NONE) {
  238. handle_type = handle_types[i];
  239. break;
  240. }
  241. handle = NULL;
  242. }
  243. if (!handle) {
  244. av_log(avctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved "
  245. "from the session\n");
  246. }
  247. err = MFXInit(impl, &ver, &session);
  248. if (err != MFX_ERR_NONE) {
  249. av_log(avctx, AV_LOG_ERROR,
  250. "Error initializing a child MFX session: %d\n", err);
  251. return ff_qsv_error(err);
  252. }
  253. if (handle) {
  254. err = MFXVideoCORE_SetHandle(session, handle_type, handle);
  255. if (err != MFX_ERR_NONE) {
  256. av_log(avctx, AV_LOG_ERROR, "Error setting a HW handle: %d\n", err);
  257. return ff_qsv_error(err);
  258. }
  259. }
  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;
  264. }
  265. if (!opaque) {
  266. av_freep(&qsv_frames_ctx->mids);
  267. qsv_frames_ctx->mids = av_mallocz_array(frames_hwctx->nb_surfaces,
  268. sizeof(*qsv_frames_ctx->mids));
  269. if (!qsv_frames_ctx->mids)
  270. return AVERROR(ENOMEM);
  271. qsv_frames_ctx->info = frames_hwctx->surfaces[0].Info;
  272. qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces;
  273. for (i = 0; i < frames_hwctx->nb_surfaces; i++)
  274. qsv_frames_ctx->mids[i] = frames_hwctx->surfaces[i].Data.MemId;
  275. err = MFXVideoCORE_SetFrameAllocator(session, &frame_allocator);
  276. if (err != MFX_ERR_NONE) {
  277. av_log(avctx, AV_LOG_ERROR, "Error setting a frame allocator: %d\n", err);
  278. return ff_qsv_error(err);
  279. }
  280. }
  281. *psession = session;
  282. return 0;
  283. }