FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "libavutil/avstring.h"
28 #include "libavutil/error.h"
29 
30 #include "avcodec.h"
31 #include "qsv_internal.h"
32 
34 {
35  switch (codec_id) {
36  case AV_CODEC_ID_H264:
37  return MFX_CODEC_AVC;
38 #if QSV_VERSION_ATLEAST(1, 8)
39  case AV_CODEC_ID_HEVC:
40  return MFX_CODEC_HEVC;
41 #endif
44  return MFX_CODEC_MPEG2;
45  case AV_CODEC_ID_VC1:
46  return MFX_CODEC_VC1;
47  default:
48  break;
49  }
50 
51  return AVERROR(ENOSYS);
52 }
53 
54 int ff_qsv_error(int mfx_err)
55 {
56  switch (mfx_err) {
57  case MFX_ERR_NONE:
58  return 0;
59  case MFX_ERR_MEMORY_ALLOC:
60  case MFX_ERR_NOT_ENOUGH_BUFFER:
61  return AVERROR(ENOMEM);
62  case MFX_ERR_INVALID_HANDLE:
63  return AVERROR(EINVAL);
64  case MFX_ERR_DEVICE_FAILED:
65  case MFX_ERR_DEVICE_LOST:
66  case MFX_ERR_LOCK_MEMORY:
67  return AVERROR(EIO);
68  case MFX_ERR_NULL_PTR:
69  case MFX_ERR_UNDEFINED_BEHAVIOR:
70  case MFX_ERR_NOT_INITIALIZED:
71  return AVERROR_BUG;
72  case MFX_ERR_UNSUPPORTED:
73  case MFX_ERR_NOT_FOUND:
74  return AVERROR(ENOSYS);
75  case MFX_ERR_MORE_DATA:
76  case MFX_ERR_MORE_SURFACE:
77  case MFX_ERR_MORE_BITSTREAM:
78  return AVERROR(EAGAIN);
79  case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
80  case MFX_ERR_INVALID_VIDEO_PARAM:
81  return AVERROR(EINVAL);
82  case MFX_ERR_ABORTED:
83  case MFX_ERR_UNKNOWN:
84  default:
85  return AVERROR_UNKNOWN;
86  }
87 }
89 {
90  // this code is only required for Linux. It searches for a valid
91  // display handle. First in /dev/dri/renderD then in /dev/dri/card
92 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
93  // VAAPI display handle
94  int ret = 0;
95  VADisplay va_dpy = NULL;
96  VAStatus va_res = VA_STATUS_SUCCESS;
97  int major_version = 0, minor_version = 0;
98  int fd = -1;
99  char adapterpath[256];
100  int adapter_num;
101 
102  qs->fd_display = -1;
103  qs->va_display = NULL;
104 
105  //search for valid graphics device
106  for (adapter_num = 0;adapter_num < 6;adapter_num++) {
107 
108  if (adapter_num<3) {
109  snprintf(adapterpath,sizeof(adapterpath),
110  "/dev/dri/renderD%d", adapter_num+128);
111  } else {
112  snprintf(adapterpath,sizeof(adapterpath),
113  "/dev/dri/card%d", adapter_num-3);
114  }
115 
116  fd = open(adapterpath, O_RDWR);
117  if (fd < 0) {
118  av_log(avctx, AV_LOG_ERROR,
119  "mfx init: %s fd open failed\n", adapterpath);
120  continue;
121  }
122 
123  va_dpy = vaGetDisplayDRM(fd);
124  if (!va_dpy) {
125  av_log(avctx, AV_LOG_ERROR,
126  "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);
127  close(fd);
128  continue;
129  }
130 
131  va_res = vaInitialize(va_dpy, &major_version, &minor_version);
132  if (VA_STATUS_SUCCESS != va_res) {
133  av_log(avctx, AV_LOG_ERROR,
134  "mfx init: %s vaInitialize failed\n", adapterpath);
135  close(fd);
136  fd = -1;
137  continue;
138  } else {
139  av_log(avctx, AV_LOG_VERBOSE,
140  "mfx initialization: %s vaInitialize successful\n",adapterpath);
141  qs->fd_display = fd;
142  qs->va_display = va_dpy;
143  ret = MFXVideoCORE_SetHandle(qs->session,
144  (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)va_dpy);
145  if (ret < 0) {
146  av_log(avctx, AV_LOG_ERROR,
147  "Error %d during set display handle\n", ret);
148  return ff_qsv_error(ret);
149  }
150  break;
151  }
152  }
153 #endif //AVCODEC_QSV_LINUX_SESSION_HANDLE
154  return 0;
155 }
156 /**
157  * @brief Initialize a MSDK session
158  *
159  * Media SDK is based on sessions, so this is the prerequisite
160  * initialization for HW acceleration. For Windows the session is
161  * complete and ready to use, for Linux a display handle is
162  * required. For releases of Media Server Studio >= 2015 R4 the
163  * render nodes interface is preferred (/dev/dri/renderD).
164  * Using Media Server Studio 2015 R4 or newer is recommended
165  * but the older /dev/dri/card interface is also searched
166  * for broader compatibility.
167  *
168  * @param avctx ffmpeg metadata for this codec context
169  * @param session the MSDK session used
170  */
172  const char *load_plugins)
173 {
174  mfxIMPL impl = MFX_IMPL_AUTO_ANY;
175  mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
176 
177  const char *desc;
178  int ret;
179 
180  ret = MFXInit(impl, &ver, &qs->session);
181  if (ret < 0) {
182  av_log(avctx, AV_LOG_ERROR, "Error initializing an internal MFX session\n");
183  return ff_qsv_error(ret);
184  }
185 
186  ret = ff_qsv_set_display_handle(avctx, qs);
187  if (ret < 0)
188  return ret;
189 
190  MFXQueryIMPL(qs->session, &impl);
191 
192  switch (MFX_IMPL_BASETYPE(impl)) {
193  case MFX_IMPL_SOFTWARE:
194  desc = "software";
195  break;
196  case MFX_IMPL_HARDWARE:
197  case MFX_IMPL_HARDWARE2:
198  case MFX_IMPL_HARDWARE3:
199  case MFX_IMPL_HARDWARE4:
200  desc = "hardware accelerated";
201  break;
202  default:
203  desc = "unknown";
204  }
205 
206  if (load_plugins && *load_plugins) {
207  while (*load_plugins) {
208  mfxPluginUID uid;
209  int i, err = 0;
210 
211  char *plugin = av_get_token(&load_plugins, ":");
212  if (!plugin)
213  return AVERROR(ENOMEM);
214  if (strlen(plugin) != 2 * sizeof(uid.Data)) {
215  av_log(avctx, AV_LOG_ERROR, "Invalid plugin UID length\n");
216  err = AVERROR(EINVAL);
217  goto load_plugin_fail;
218  }
219 
220  for (i = 0; i < sizeof(uid.Data); i++) {
221  err = sscanf(plugin + 2 * i, "%2hhx", uid.Data + i);
222  if (err != 1) {
223  av_log(avctx, AV_LOG_ERROR, "Invalid plugin UID\n");
224  err = AVERROR(EINVAL);
225  goto load_plugin_fail;
226  }
227 
228  }
229 
230  ret = MFXVideoUSER_Load(qs->session, &uid, 1);
231  if (ret < 0) {
232  av_log(avctx, AV_LOG_ERROR, "Could not load the requested plugin: %s\n",
233  plugin);
234  err = ff_qsv_error(ret);
235  goto load_plugin_fail;
236  }
237 
238 load_plugin_fail:
239  av_freep(&plugin);
240  if (err < 0)
241  return err;
242  }
243  }
244 
245  av_log(avctx, AV_LOG_VERBOSE,
246  "Initialized an internal MFX session using %s implementation\n",
247  desc);
248 
249  return 0;
250 }
251 
253 {
254  if (qs->session) {
255  MFXClose(qs->session);
256  qs->session = NULL;
257  }
258 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
259  if (qs->va_display) {
260  vaTerminate(qs->va_display);
261  qs->va_display = NULL;
262  }
263  if (qs->fd_display > 0) {
264  close(qs->fd_display);
265  qs->fd_display = -1;
266  }
267 #endif
268  return 0;
269 }
#define NULL
Definition: coverity.c:32
UID uid
Definition: mxfenc.c:1820
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
#define av_log(a,...)
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:101
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
error code definitions
#define AVERROR(e)
Definition: error.h:43
enum AVCodecID codec_id
Definition: mov_chan.c:433
int ff_qsv_close_internal_session(QSVSession *qs)
Definition: qsv.c:252
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:149
#define QSV_VERSION_MINOR
Definition: qsv_internal.h:44
int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id)
Definition: qsv.c:33
preferred ID for MPEG-1/2 video decoding
Definition: avcodec.h:106
int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs, const char *load_plugins)
Initialize a MSDK session.
Definition: qsv.c:171
Libavcodec external API header.
main external API structure.
Definition: avcodec.h:1532
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
#define snprintf
Definition: snprintf.h:34
int ff_qsv_error(int mfx_err)
Convert a libmfx error code into a ffmpeg error code.
Definition: qsv.c:54
#define QSV_VERSION_MAJOR
Definition: qsv_internal.h:43
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)
Definition: qsv.c:88
#define av_freep(p)
mfxSession session
Definition: qsv_internal.h:67